source: finroc_plugins_data_ports/tests/test_collection.cpp @ 139:b80094f9fac6

Last change on this file since 139:b80094f9fac6 was 139:b80094f9fac6, checked in by Max Reichardt <mreichardt@…>, 10 months ago

Merge with 17.03

File size: 18.9 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#include "plugins/structure/tModule.h"
49
50//----------------------------------------------------------------------
51// Debugging
52//----------------------------------------------------------------------
53#include <cassert>
54
55//----------------------------------------------------------------------
56// Namespace usage
57//----------------------------------------------------------------------
58
59//----------------------------------------------------------------------
60// Namespace declaration
61//----------------------------------------------------------------------
62namespace finroc
63{
64namespace data_ports
65{
66
67//----------------------------------------------------------------------
68// Forward declarations / typedefs / enums
69//----------------------------------------------------------------------
70
71//----------------------------------------------------------------------
72// Const values
73//----------------------------------------------------------------------
74
75//----------------------------------------------------------------------
76// Implementation
77//----------------------------------------------------------------------
78
79void TestPortChains()
80{
81  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "\nTesting forwarding data among port chains");
82  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortChains");
83
84  // Create ports
85  tOutputPort<std::string> output_port1("Output Port 1", parent);
86  tOutputPort<std::string> output_port2("Output Port 2", parent);
87  tOutputPort<std::string> output_port3("Output Port 3", parent);
88  tProxyPort<std::string, true> proxy_port1("Proxy Port 1", parent);
89  tProxyPort<std::string, true> proxy_port2("Proxy Port 2", parent);
90  tProxyPort<std::string, true> proxy_port3("Proxy Port 3", parent);
91  tInputPort<std::string> input_port1("Input Port 1", parent);
92  tInputPort<std::string> input_port2("Input Port 2", parent);
93  tInputPort<std::string> input_port3("Input Port 3", parent);
94
95  // Connect ports
96  output_port1.ConnectTo(proxy_port1);
97  output_port2.ConnectTo(proxy_port2);
98  output_port3.ConnectTo(proxy_port3);
99  proxy_port1.ConnectTo(input_port1);
100  proxy_port2.ConnectTo(input_port2);
101  proxy_port3.ConnectTo(input_port3);
102  parent->Init();
103
104  std::string test_string = "12345";
105  for (int i = 0; i < 20; i++)
106  {
107    // Publish data
108    tPortDataPointer<std::string> unused_buffer = output_port1.GetUnusedBuffer();
109    std::string test_string2 = "Test" + std::to_string(i);
110    *unused_buffer = test_string2;
111    output_port1.Publish(unused_buffer);
112
113    // Forward data to second and third chain
114    output_port2.Publish(input_port1.GetPointer());
115    output_port3.Publish(input_port2.GetPointer());
116    RRLIB_UNIT_TESTS_ASSERT(test_string2 == *input_port3.GetPointer());
117
118    if (i > 10)
119    {
120      output_port2.Publish(test_string);
121      output_port3.Publish(input_port2.GetPointer());
122      RRLIB_UNIT_TESTS_ASSERT(test_string == *input_port3.GetPointer());
123      RRLIB_UNIT_TESTS_ASSERT(test_string == *input_port2.GetPointer());
124      RRLIB_UNIT_TESTS_ASSERT(test_string2 == *input_port1.GetPointer());
125    }
126  }
127
128  parent->ManagedDelete();
129}
130
131template <typename T>
132void TestPortQueues(const T& value1, const T& value2, const T& value3)
133{
134  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "\nTesting port queue basic operation for type ", (rrlib::rtti::tDataType<T>()).GetName());
135  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortQueue");
136
137  tOutputPort<T> output_port("Output Port", parent);
138  tInputPort<T> input_port_fifo("Input Port FIFO", parent, tQueueSettings(false));
139  tInputPort<T> input_port_all("Input Port ALL", parent, tQueueSettings(true));
140  output_port.ConnectTo(input_port_fifo);
141  output_port.ConnectTo(input_port_all);
142  parent->Init();
143
144  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, " Enqueueing three values");
145  output_port.Publish(value1);
146  output_port.Publish(value2);
147  output_port.Publish(value3);
148
149  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, " Dequeueing five values FIFO");
150  for (size_t i = 0; i < 5; ++i)
151  {
152    tPortDataPointer<const T> result = input_port_fifo.Dequeue();
153    if (result)
154    {
155      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Dequeued ", *result);
156    }
157    else
158    {
159      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Dequeued nothing");
160    }
161    RRLIB_UNIT_TESTS_ASSERT((i == 0 && value1 == *result) || (i == 1 && value2 == *result) || (i == 2 && value3 == *result) || (i > 2 && (!result)));
162  }
163
164  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, " Dequeueing all values at once");
165  tPortBuffers<tPortDataPointer<const T>> dequeued = input_port_all.DequeueAllBuffers();
166  size_t i = 0;
167  while (!dequeued.Empty())
168  {
169    T result = *dequeued.PopFront();
170    FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Dequeued ", result);
171    RRLIB_UNIT_TESTS_ASSERT((i == 0 && value1 == result) || (i == 1 && value2 == result) || (i == 2 && value3 == result));
172    i++;
173  }
174
175  parent->ManagedDelete();
176};
177
178
179
180template <typename T>
181void TestPortListeners(const T& publish_value)
182{
183  class tListener
184  {
185  public:
186    void OnPortChange(const T& value, tChangeContext& change_context)
187    {
188      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed: ", value);
189      this->value1 = value;
190      this->calls++;
191    }
192    void OnPortChange(tPortDataPointer<const T>& value, tChangeContext& change_context)
193    {
194      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed (tPortDataPointer): ", *value);
195      this->value2 = *value;
196      this->calls++;
197    }
198    void OnPortChange(const rrlib::rtti::tGenericObject& value, tChangeContext& change_context)
199    {
200      rrlib::serialization::tStringOutputStream stream;
201      value.Serialize(stream);
202      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic: ", stream.ToString());
203      this->calls++;
204    }
205    void OnPortChange(tPortDataPointer<const rrlib::rtti::tGenericObject>& value, tChangeContext& change_context)
206    {
207      rrlib::serialization::tStringOutputStream stream;
208      value->Serialize(stream);
209      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Generic (tPortDataPointer): ", stream.ToString());
210      this->calls++;
211    }
212    void OnPortChange(tChangeContext& change_context)
213    {
214      FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "  Port Changed Simple");
215      this->calls++;
216    }
217
218    T value1, value2;
219    size_t calls;
220
221    tListener() : value1(), value2(), calls(0) {}
222  };
223
224  FINROC_LOG_PRINT(DEBUG_VERBOSE_1, "\nTesting port listeners for type ", (rrlib::rtti::tDataType<T>()).GetName());
225  tListener listener;
226  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestPortListeners");
227
228  tOutputPort<T> output_port("Output Port", parent);
229  tInputPort<T> input_port("Input Port", parent);
230  output_port.ConnectTo(input_port);
231  input_port.AddPortListener(listener);
232  input_port.AddPortListenerForPointer(listener);
233  input_port.AddPortListenerSimple(listener);
234  tGenericPort generic_input_port = tGenericPort::Wrap(*input_port.GetWrapped());
235  generic_input_port.AddPortListener(listener);
236  generic_input_port.AddPortListenerForPointer(listener);
237  generic_input_port.AddPortListenerSimple(listener);
238  parent->Init();
239
240  output_port.Publish(publish_value);
241
242  RRLIB_UNIT_TESTS_ASSERT(listener.value1 == publish_value && listener.value2 == publish_value && listener.calls == 6);
243
244  parent->ManagedDelete();
245}
246
247template <typename T>
248void TestNetworkConnectionLoss(const T& default_value, const T& publish_value)
249{
250  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestNetworkConnectionLoss");
251
252  tOutputPort<T> output_port("Output Port", parent);
253  tInputPort<T> input_port_no_explicit_default("Input Port No Explicit Default", parent, core::tFrameworkElement::tFlag::DEFAULT_ON_DISCONNECT);
254  tInputPort<T> input_port_explicit_default("Input Port Explicit Default", parent, core::tFrameworkElement::tFlag::DEFAULT_ON_DISCONNECT, default_value);
255  tInputPort<T> input_port_deferred_default("Input Port Deferred Default", parent, core::tFrameworkElement::tFlag::DEFAULT_ON_DISCONNECT);
256  input_port_deferred_default.SetDefault(default_value);
257  output_port.ConnectTo(input_port_no_explicit_default);
258  output_port.ConnectTo(input_port_explicit_default);
259  output_port.ConnectTo(input_port_deferred_default);
260  parent->Init();
261
262  output_port.Publish(publish_value);
263  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_no_explicit_default.GetPointer());
264  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_explicit_default.GetPointer());
265  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_deferred_default.GetPointer());
266  input_port_no_explicit_default.GetWrapped()->NotifyOfNetworkConnectionLoss();
267  input_port_explicit_default.GetWrapped()->NotifyOfNetworkConnectionLoss();
268  input_port_deferred_default.GetWrapped()->NotifyOfNetworkConnectionLoss();
269  RRLIB_UNIT_TESTS_EQUALITY(T(), *input_port_no_explicit_default.GetPointer());
270  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_explicit_default.GetPointer());
271  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_deferred_default.GetPointer());
272  output_port.Publish(publish_value);
273  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_no_explicit_default.GetPointer());
274  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_explicit_default.GetPointer());
275  RRLIB_UNIT_TESTS_EQUALITY(publish_value, *input_port_deferred_default.GetPointer());
276  output_port.DisconnectAll();
277  RRLIB_UNIT_TESTS_EQUALITY(T(), *input_port_no_explicit_default.GetPointer());
278  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_explicit_default.GetPointer());
279  RRLIB_UNIT_TESTS_EQUALITY(default_value, *input_port_deferred_default.GetPointer());
280
281  parent->ManagedDelete();
282}
283
284void TestOutOfBoundsPublish()
285{
286  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestOutOfBoundsPublish");
287
288  tOutputPort<int> output_port("Output Port", parent, tBounds<int>(0, 2, tOutOfBoundsAction::DISCARD));
289  tInputPort<int> input_port("Input Port", parent, tBounds<int>(0, 1));
290  output_port.ConnectTo(input_port);
291  parent->Init();
292
293  output_port.Publish(3);
294  RRLIB_UNIT_TESTS_EQUALITY(0, input_port.Get());
295  output_port.Publish(2);
296  RRLIB_UNIT_TESTS_EQUALITY(1, input_port.Get());
297
298  parent->ManagedDelete();
299}
300
301template <typename T>
302void TestHijackedPublishing(const T& value_to_publish)
303{
304  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestHijackedPublishing");
305  T default_value = T();
306
307  tOutputPort<T> output_port("Output Port", parent);
308  tProxyPort<T, true> proxy_port("Proxy Port", parent, core::tFrameworkElementFlag::PUSH_STRATEGY);
309  tInputPort<T> input_port("Input Port", parent);
310  output_port.ConnectTo(proxy_port);
311  proxy_port.ConnectTo(input_port);
312  parent->Init();
313
314  output_port.Publish(value_to_publish);
315  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *proxy_port.GetPointer());
316  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
317  input_port.GetWrapped()->SetHijacked(true);
318  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *proxy_port.GetPointer());
319  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
320  output_port.Publish(default_value);
321  RRLIB_UNIT_TESTS_EQUALITY(default_value, *proxy_port.GetPointer());
322  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
323  proxy_port.GetWrapped()->SetHijacked(true);
324  input_port.GetWrapped()->SetHijacked(false);
325  output_port.Publish(value_to_publish);
326  RRLIB_UNIT_TESTS_EQUALITY(default_value, *proxy_port.GetPointer());
327  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, *input_port.GetPointer());
328  output_port.GetWrapped()->SetHijacked(true);
329  output_port.Publish(value_to_publish);
330
331  parent->ManagedDelete();
332}
333
334template <typename T>
335void TestGenericPorts(T value_to_publish, T another_value)
336{
337  core::tFrameworkElement* parent = new core::tFrameworkElement(&core::tRuntimeEnvironment::GetInstance(), "TestGenericPorts");
338  T default_value = T();
339  rrlib::rtti::tGenericObjectWrapper<T> default_buffer(default_value);
340  rrlib::rtti::tGenericObjectWrapper<T> value_buffer(value_to_publish);
341  rrlib::rtti::tGenericObjectWrapper<T> another_value_buffer(another_value);
342
343  tGenericPort output_port("Output Port", rrlib::rtti::tDataType<T>(), parent, core::tFrameworkElement::tFlag::EMITS_DATA | core::tFrameworkElement::tFlag::OUTPUT_PORT);
344  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);
345  tGenericPort input_port("Input Port", rrlib::rtti::tDataType<T>(), parent, core::tFrameworkElement::tFlag::ACCEPTS_DATA | core::tFrameworkElement::tFlag::PUSH_STRATEGY);
346  output_port.ConnectTo(proxy_port);
347  proxy_port.ConnectTo(input_port);
348  parent->Init();
349
350  // Publish by value
351  T get_value = T();
352  rrlib::rtti::tGenericObjectWrapper<T> get_buffer(get_value);
353  input_port.Get(get_buffer);
354  RRLIB_UNIT_TESTS_EQUALITY(default_value, get_value);
355  output_port.Publish(value_buffer);
356  proxy_port.Get(get_buffer);
357  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, get_value);
358  input_port.Get(get_buffer);
359  RRLIB_UNIT_TESTS_EQUALITY(value_to_publish, get_value);
360
361  // Publish via buffer
362  auto unused_buffer = output_port.GetUnusedBuffer();
363  unused_buffer->GetData<T>() = another_value;
364  output_port.Publish(unused_buffer);
365  proxy_port.Get(get_buffer);
366  RRLIB_UNIT_TESTS_EQUALITY(another_value, get_value);
367  input_port.Get(get_buffer);
368  RRLIB_UNIT_TESTS_EQUALITY(another_value, get_value);
369
370  parent->ManagedDelete();
371}
372
373struct mTestModule : structure::tModule
374{
375  using tModule::tModule;
376  void Update() override {}
377};
378
379template <typename ... T, typename NAMES>
380void PortPackTestHelper(core::tFrameworkElement *parent, const std::initializer_list<NAMES> &names_initializer)
381{
382  data_ports::tPortPack<mTestModule::tInput, T...> ports(parent, "X");
383
384  RRLIB_UNIT_TESTS_EQUALITY(sizeof...(T), ports.NumberOfPorts());
385  for (size_t i = 0; i < sizeof...(T); ++i)
386  {
387    RRLIB_UNIT_TESTS_EQUALITY("X" + std::to_string(i), ports.GetPort(i).GetName());
388  }
389
390  std::array<NAMES, sizeof...(T)> names;
391  assert(names_initializer.size() == names.size());
392  std::copy(names_initializer.begin(), names_initializer.end(), names.begin());
393  data_ports::tPortPack<tInputPort, T...> named_ports(parent, names.begin(), names.end());
394
395  RRLIB_UNIT_TESTS_EQUALITY(sizeof...(T), named_ports.NumberOfPorts());
396  for (size_t i = 0; i < sizeof...(T); ++i)
397  {
398    RRLIB_UNIT_TESTS_EQUALITY(std::string(names[i]), named_ports.GetPort(i).GetName());
399  }
400}
401
402class DataPortsTestCollection : public rrlib::util::tUnitTestSuite
403{
404  RRLIB_UNIT_TESTS_BEGIN_SUITE(DataPortsTestCollection);
405  RRLIB_UNIT_TESTS_ADD_TEST(Test);
406  RRLIB_UNIT_TESTS_ADD_TEST(PortPack);
407  RRLIB_UNIT_TESTS_ADD_TEST(PortPackLegacy);
408  RRLIB_UNIT_TESTS_END_SUITE;
409
410  void Test()
411  {
412    TestPortChains();
413    TestPortQueues<int>(1, 2, 3);
414    TestPortQueues<std::string>("1", "2", "3");
415    TestPortListeners<int>(1);
416    TestPortListeners<std::string>("test");
417    TestNetworkConnectionLoss<int>(4, 7);
418    TestNetworkConnectionLoss<std::string>("default_value", "published_value");
419    TestOutOfBoundsPublish();
420    TestHijackedPublishing<int>(42);
421    TestHijackedPublishing<std::string>("test");
422    TestGenericPorts<bool>(true, false);
423    TestGenericPorts<std::string>("123", "45");
424
425    tThreadLocalBufferManagement local_buffers;
426    TestPortChains();
427    TestPortQueues<int>(1, 2, 3);
428    TestPortListeners<int>(1);
429    TestNetworkConnectionLoss<int>(4, 7);
430    TestOutOfBoundsPublish();
431    TestHijackedPublishing<int>(42);
432    TestGenericPorts<bool>(true, false);
433  }
434
435  void PortPack()
436  {
437    auto parent = new mTestModule(&core::tRuntimeEnvironment::GetInstance(), "TestModule");
438
439    PortPackTestHelper<int, double, std::string, bool>(parent, {"foo", "bar", "baz", "fnord"});
440
441    std::array<std::string, 0> empty_names;
442    RRLIB_UNIT_TESTS_EQUALITY(size_t(0), data_ports::tPortPack<mTestModule::tInput>(parent, "X").NumberOfPorts());
443    RRLIB_UNIT_TESTS_EQUALITY(size_t(0), data_ports::tPortPack<mTestModule::tInput>(parent, empty_names.begin(), empty_names.end()).NumberOfPorts());
444  }
445
446  void PortPackLegacy()
447  {
448    auto parent = new mTestModule(&core::tRuntimeEnvironment::GetInstance(), "TestModule");
449
450    using tTypeList = rrlib::util::tTypeList<int, double, std::string, bool>;
451    data_ports::tPortPack<mTestModule::tInput, tTypeList> ports(parent, "X");
452
453    RRLIB_UNIT_TESTS_EQUALITY(tTypeList::cSIZE, ports.NumberOfPorts());
454
455    for (size_t i = 0; i < tTypeList::cSIZE; ++i)
456    {
457      RRLIB_UNIT_TESTS_EQUALITY("X" + std::to_string(i + 1), ports.GetPort(i).GetName());
458    }
459
460    std::array<std::string, tTypeList::cSIZE> names {"foo", "bar", "baz", "fnord"};
461    data_ports::tPortPack<mTestModule::tInput, tTypeList> named_ports(parent, names.begin(), names.end());
462
463    for (size_t i = 0; i < tTypeList::cSIZE; ++i)
464    {
465      RRLIB_UNIT_TESTS_EQUALITY(names[i], named_ports.GetPort(i).GetName());
466    }
467  }
468};
469
470RRLIB_UNIT_TESTS_REGISTER_SUITE(DataPortsTestCollection);
471
472//----------------------------------------------------------------------
473// End of namespace declaration
474//----------------------------------------------------------------------
475}
476}
Note: See TracBrowser for help on using the repository browser.