source: finroc_plugins_data_ports/tests/test_collection.cpp @ 117:5783af72224e

17.03
Last change on this file since 117:5783af72224e was 117:5783af72224e, checked in by Tobias Föhst <foehst@…>, 3 years ago

Adds test for port packs

File size: 17.3 KB
Line 
1//
2// You received this file as part of Finroc
3// A framework for intelligent robot control
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/data_ports/tests/test_collection.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2013-01-03
27 *
28 * Collections of tests.
29 * This is the place to add simple tests for data_ports.
30 */
31//----------------------------------------------------------------------
32
33//----------------------------------------------------------------------
34// External includes (system with <>, local with "")
35//----------------------------------------------------------------------
36#include "core/tRuntimeEnvironment.h"
37#include "rrlib/util/tUnitTestSuite.h"
38
39//----------------------------------------------------------------------
40// Internal includes with ""
41//----------------------------------------------------------------------
42#include "plugins/data_ports/tInputPort.h"
43#include "plugins/data_ports/tOutputPort.h"
44#include "plugins/data_ports/tProxyPort.h"
45#include "plugins/data_ports/tThreadLocalBufferManagement.h"
46#include "plugins/data_ports/tPortPack.h"
47
48//----------------------------------------------------------------------
49// Debugging
50//----------------------------------------------------------------------
51#include <cassert>
52
53//----------------------------------------------------------------------
54// Namespace usage
55//----------------------------------------------------------------------
56
57//----------------------------------------------------------------------
58// Namespace declaration
59//----------------------------------------------------------------------
60namespace finroc
61{
62namespace data_ports
63{
64
65//----------------------------------------------------------------------
66// Forward declarations / typedefs / enums
67//----------------------------------------------------------------------
68
69//----------------------------------------------------------------------
70// Const values
71//----------------------------------------------------------------------
72
73//----------------------------------------------------------------------
74// Implementation
75//----------------------------------------------------------------------
76
77void TestPortChains()
78{
79  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "\nTesting forwarding data among port chains");
80  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortChains");
81
82  // Create ports
83  tOutputPort<std::string> output_port1("Output Port 1", parent);
84  tOutputPort<std::string> output_port2("Output Port 2", parent);
85  tOutputPort<std::string> output_port3("Output Port 3", parent);
86  tProxyPort<std::string, true> proxy_port1("Proxy Port 1", parent);
87  tProxyPort<std::string, true> proxy_port2("Proxy Port 2", parent);
88  tProxyPort<std::string, true> proxy_port3("Proxy Port 3", parent);
89  tInputPort<std::string> input_port1("Input Port 1", parent);
90  tInputPort<std::string> input_port2("Input Port 2", parent);
91  tInputPort<std::string> input_port3("Input Port 3", parent);
92
93  // Connect ports
94  output_port1.ConnectTo(proxy_port1);
95  output_port2.ConnectTo(proxy_port2);
96  output_port3.ConnectTo(proxy_port3);
97  proxy_port1.ConnectTo(input_port1);
98  proxy_port2.ConnectTo(input_port2);
99  proxy_port3.ConnectTo(input_port3);
100  parent->Init();
101
102  std::string test_string = "12345";
103  for (int i = 0; i < 20; i++)
104  {
105    // Publish data
106    tPortDataPointer<std::string> unused_buffer = output_port1.GetUnusedBuffer();
107    std::string test_string2 = "Test" + std::to_string(i);
108    *unused_buffer = test_string2;
109    output_port1.Publish(unused_buffer);
110
111    // Forward data to second and third chain
112    output_port2.Publish(input_port1.GetPointer());
113    output_port3.Publish(input_port2.GetPointer());
114    RRLIB_UNIT_TESTS_ASSERT(test_string2 == *input_port3.GetPointer());
115
116    if (i > 10)
117    {
118      output_port2.Publish(test_string);
119      output_port3.Publish(input_port2.GetPointer());
120      RRLIB_UNIT_TESTS_ASSERT(test_string == *input_port3.GetPointer());
121      RRLIB_UNIT_TESTS_ASSERT(test_string == *input_port2.GetPointer());
122      RRLIB_UNIT_TESTS_ASSERT(test_string2 == *input_port1.GetPointer());
123    }
124  }
125
126  parent->ManagedDelete();
127}
128
129template <typename T>
130void TestPortQueues(const T& value1, const T& value2, const T& value3)
131{
132  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "\nTesting port queue basic operation for type ", (rrlib::rtti::tDataType<T>()).GetName());
133  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortQueue");
134
135  tOutputPort<T> output_port("Output Port", parent);
136  tInputPort<T> input_port_fifo("Input Port FIFO", parent, tQueueSettings(false));
137  tInputPort<T> input_port_all("Input Port ALL", parent, tQueueSettings(true));
138  output_port.ConnectTo(input_port_fifo);
139  output_port.ConnectTo(input_port_all);
140  parent->Init();
141
142  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, " Enqueueing three values");
143  output_port.Publish(value1);
144  output_port.Publish(value2);
145  output_port.Publish(value3);
146
147  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, " Dequeueing five values FIFO");
148  for (size_t i = 0; i < 5; ++i)
149  {
150    tPortDataPointer<const T> result = input_port_fifo.Dequeue();
151    if (result)
152    {
153      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Dequeued ", *result);
154    }
155    else
156    {
157      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Dequeued nothing");
158    }
159    RRLIB_UNIT_TESTS_ASSERT((i == 0 && value1 == *result) || (i == 1 && value2 == *result) || (i == 2 && value3 == *result) || (i > 2 && (!result)));
160  }
161
162  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, " Dequeueing all values at once");
163  tPortBuffers<tPortDataPointer<const T>> dequeued = input_port_all.DequeueAllBuffers();
164  size_t i = 0;
165  while (!dequeued.Empty())
166  {
167    T result = *dequeued.PopFront();
168    FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Dequeued ", result);
169    RRLIB_UNIT_TESTS_ASSERT((i == 0 && value1 == result) || (i == 1 && value2 == result) || (i == 2 && value3 == result));
170    i++;
171  }
172
173  parent->ManagedDelete();
174};
175
176
177
178template <typename T>
179void TestPortListeners(const T& publish_value)
180{
181  class tListener
182  {
183  public:
184    void OnPortChange(const T& value, tChangeContext& change_context)
185    {
186      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed: ", value);
187      this->value1 = value;
188      this->calls++;
189    }
190    void OnPortChange(tPortDataPointer<const T>& value, tChangeContext& change_context)
191    {
192      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed (tPortDataPointer): ", *value);
193      this->value2 = *value;
194      this->calls++;
195    }
196    void OnPortChange(const rrlib::rtti::tGenericObject& value, tChangeContext& change_context)
197    {
198      rrlib::serialization::tStringOutputStream stream;
199      value.Serialize(stream);
200      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic: ", stream.ToString());
201      this->calls++;
202    }
203    void OnPortChange(tPortDataPointer<const rrlib::rtti::tGenericObject>& value, tChangeContext& change_context)
204    {
205      rrlib::serialization::tStringOutputStream stream;
206      value->Serialize(stream);
207      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic (tPortDataPointer): ", stream.ToString());
208      this->calls++;
209    }
210    void OnPortChange(tChangeContext& change_context)
211    {
212      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Simple");
213      this->calls++;
214    }
215
216    T value1, value2;
217    size_t calls;
218
219    tListener() : value1(), value2(), calls(0) {}
220  };
221
222  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "\nTesting port listeners for type ", (rrlib::rtti::tDataType<T>()).GetName());
223  tListener listener;
224  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortListeners");
225
226  tOutputPort<T> output_port("Output Port", parent);
227  tInputPort<T> input_port("Input Port", parent);
228  output_port.ConnectTo(input_port);
229  input_port.AddPortListener(listener);
230  input_port.AddPortListenerForPointer(listener);
231  input_port.AddPortListenerSimple(listener);
232  tGenericPort generic_input_port = tGenericPort::Wrap(*input_port.GetWrapped());
233  generic_input_port.AddPortListener(listener);
234  generic_input_port.AddPortListenerForPointer(listener);
235  generic_input_port.AddPortListenerSimple(listener);
236  parent->Init();
237
238  output_port.Publish(publish_value);
239
240  RRLIB_UNIT_TESTS_ASSERT(listener.value1 == publish_value && listener.value2 == publish_value && listener.calls == 6);
241
242  parent->ManagedDelete();
243}
244
245template <typename T>
246void TestNetworkConnectionLoss(const T& default_value, const T& publish_value)
247{
248  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestNetworkConnectionLoss");
249
250  tOutputPort<T> output_port("Output Port", parent);
251  tInputPort<T> input_port_no_explicit_default("Input Port No Explicit Default", parent, core::tFrameworkElement::tFlag::DEFAULT_ON_DISCONNECT);
252  tInputPort<T> input_port_explicit_default("Input Port Explicit Default", parent, core::tFrameworkElement::tFlag::DEFAULT_ON_DISCONNECT, default_value);
253  tInputPort<T> input_port_deferred_default("Input Port Deferred Default", parent, core::tFrameworkElement::tFlag::DEFAULT_ON_DISCONNECT);
254  input_port_deferred_default.SetDefault(default_value);
255  output_port.ConnectTo(input_port_no_explicit_default);
256  output_port.ConnectTo(input_port_explicit_default);
257  output_port.ConnectTo(input_port_deferred_default);
258  parent->Init();
259
260  output_port.Publish(publish_value);
261  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_no_explicit_default.GetPointer());
262  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_explicit_default.GetPointer());
263  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_deferred_default.GetPointer());
264  input_port_no_explicit_default.GetWrapped()->NotifyOfNetworkConnectionLoss();
265  input_port_explicit_default.GetWrapped()->NotifyOfNetworkConnectionLoss();
266  input_port_deferred_default.GetWrapped()->NotifyOfNetworkConnectionLoss();
267  RRLIB_UNIT_TESTS_EQUALITY(T(), *input_port_no_explicit_default.GetPointer());
268  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_explicit_default.GetPointer());
269  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_deferred_default.GetPointer());
270  output_port.Publish(publish_value);
271  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_no_explicit_default.GetPointer());
272  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_explicit_default.GetPointer());
273  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_deferred_default.GetPointer());
274  output_port.DisconnectAll();
275  RRLIB_UNIT_TESTS_EQUALITY(T(), *input_port_no_explicit_default.GetPointer());
276  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_explicit_default.GetPointer());
277  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_deferred_default.GetPointer());
278
279  parent->ManagedDelete();
280}
281
282void TestOutOfBoundsPublish()
283{
284  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestOutOfBoundsPublish");
285
286  tOutputPort<int> output_port("Output Port", parent, tBounds<int>(0, 2, tOutOfBoundsAction::DISCARD));
287  tInputPort<int> input_port("Input Port", parent, tBounds<int>(0, 1));
288  output_port.ConnectTo(input_port);
289  parent->Init();
290
291  output_port.Publish(3);
292  RRLIB_UNIT_TESTS_EQUALITY(0, input_port.Get());
293  output_port.Publish(2);
294  RRLIB_UNIT_TESTS_EQUALITY(1, input_port.Get());
295
296  parent->ManagedDelete();
297}
298
299template <typename T>
300void TestHijackedPublishing(const T& value_to_publish)
301{
302  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestHijackedPublishing");
303  T default_value = T();
304
305  tOutputPort<T> output_port("Output Port", parent);
306  tProxyPort<T, true> proxy_port("Proxy Port", parent, core::tFrameworkElementFlag::PUSH_STRATEGY);
307  tInputPort<T> input_port("Input Port", parent);
308  output_port.ConnectTo(proxy_port);
309  proxy_port.ConnectTo(input_port);
310  parent->Init();
311
312  output_port.Publish(value_to_publish);
313  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *proxy_port.GetPointer());
314  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
315  input_port.GetWrapped()->SetHijacked(true);
316  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *proxy_port.GetPointer());
317  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
318  output_port.Publish(default_value);
319  RRLIB_UNIT_TESTS_EQUALITY(default_value, *proxy_port.GetPointer());
320  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
321  proxy_port.GetWrapped()->SetHijacked(true);
322  input_port.GetWrapped()->SetHijacked(false);
323  output_port.Publish(value_to_publish);
324  RRLIB_UNIT_TESTS_EQUALITY(default_value, *proxy_port.GetPointer());
325  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
326  output_port.GetWrapped()->SetHijacked(true);
327  output_port.Publish(value_to_publish);
328
329  parent->ManagedDelete();
330}
331
332template <typename T>
333void TestGenericPorts(T value_to_publish, T another_value)
334{
335  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestGenericPorts");
336  T default_value = T();
337  rrlib::rtti::tGenericObjectWrapper<T> default_buffer(default_value);
338  rrlib::rtti::tGenericObjectWrapper<T> value_buffer(value_to_publish);
339  rrlib::rtti::tGenericObjectWrapper<T> another_value_buffer(another_value);
340
341  tGenericPort output_port("Output Port", rrlib::rtti::tDataType<T>(), parent, core::tFrameworkElement::tFlag::EMITS_DATA | core::tFrameworkElement::tFlag::OUTPUT_PORT);
342  tGenericPort proxy_port("Proxy Port", rrlib::rtti::tDataType<T>(), parent, core::tFrameworkElement::tFlag::ACCEPTS_DATA | core::tFrameworkElement::tFlag::PUSH_STRATEGY | core::tFrameworkElement::tFlag::EMITS_DATA);
343  tGenericPort input_port("Input Port", rrlib::rtti::tDataType<T>(), parent, core::tFrameworkElement::tFlag::ACCEPTS_DATA | core::tFrameworkElement::tFlag::PUSH_STRATEGY);
344  output_port.ConnectTo(proxy_port);
345  proxy_port.ConnectTo(input_port);
346  parent->Init();
347
348  // Publish by value
349  T get_value = T();
350  rrlib::rtti::tGenericObjectWrapper<T> get_buffer(get_value);
351  input_port.Get(get_buffer);
352  RRLIB_UNIT_TESTS_EQUALITY(default_value, get_value);
353  output_port.Publish(value_buffer);
354  proxy_port.Get(get_buffer);
355  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, get_value);
356  input_port.Get(get_buffer);
357  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, get_value);
358
359  // Publish via buffer
360  auto unused_buffer = output_port.GetUnusedBuffer();
361  unused_buffer->GetData<T>() = another_value;
362  output_port.Publish(unused_buffer);
363  proxy_port.Get(get_buffer);
364  RRLIB_UNIT_TESTS_EQUALITY(another_value, get_value);
365  input_port.Get(get_buffer);
366  RRLIB_UNIT_TESTS_EQUALITY(another_value, get_value);
367
368  parent->ManagedDelete();
369}
370
371class DataPortsTestCollection : public rrlib::util::tUnitTestSuite
372{
373  RRLIB_UNIT_TESTS_BEGIN_SUITE(DataPortsTestCollection);
374  RRLIB_UNIT_TESTS_ADD_TEST(Test);
375  RRLIB_UNIT_TESTS_ADD_TEST(PortPack);
376  RRLIB_UNIT_TESTS_END_SUITE;
377
378  void Test()
379  {
380    TestPortChains();
381    TestPortQueues<int>(1, 2, 3);
382    TestPortQueues<std::string>("1", "2", "3");
383    TestPortListeners<int>(1);
384    TestPortListeners<std::string>("test");
385    TestNetworkConnectionLoss<int>(4, 7);
386    TestNetworkConnectionLoss<std::string>("default_value", "published_value");
387    TestOutOfBoundsPublish();
388    TestHijackedPublishing<int>(42);
389    TestHijackedPublishing<std::string>("test");
390    TestGenericPorts<bool>(true, false);
391    TestGenericPorts<std::string>("123", "45");
392
393    tThreadLocalBufferManagement local_buffers;
394    TestPortChains();
395    TestPortQueues<int>(1, 2, 3);
396    TestPortListeners<int>(1);
397    TestNetworkConnectionLoss<int>(4, 7);
398    TestOutOfBoundsPublish();
399    TestHijackedPublishing<int>(42);
400    TestGenericPorts<bool>(true, false);
401  }
402
403  void PortPack()
404  {
405    auto parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortPack");
406
407    using tTypeList = rrlib::util::tTypeList<int, double, std::string, bool>;
408    data_ports::tPortPack<tInputPort, tTypeList> ports(parent, "X");
409
410    RRLIB_UNIT_TESTS_EQUALITY(tTypeList::cSIZE, ports.NumberOfPorts());
411
412    for (size_t i = 0; i < tTypeList::cSIZE; ++i)
413    {
414      RRLIB_UNIT_TESTS_EQUALITY("X" + std::to_string(i + 1), ports.GetPort(i).GetName());
415    }
416
417    std::array<std::string, tTypeList::cSIZE> names {"foo", "bar", "baz", "fnord"};
418    data_ports::tPortPack<tInputPort, tTypeList> named_ports(parent, names.begin(), names.end());
419
420    for (size_t i = 0; i < tTypeList::cSIZE; ++i)
421    {
422      RRLIB_UNIT_TESTS_EQUALITY(names[i], named_ports.GetPort(i).GetName());
423    }
424  }
425};
426
427RRLIB_UNIT_TESTS_REGISTER_SUITE(DataPortsTestCollection);
428
429//----------------------------------------------------------------------
430// End of namespace declaration
431//----------------------------------------------------------------------
432}
433}
Note: See TracBrowser for help on using the repository browser.