source: finroc_plugins_data_ports/tests/test_collection.cpp @ 106:5096776a7d9c

17.03
Last change on this file since 106:5096776a7d9c was 106:5096776a7d9c, checked in by Max Reichardt <mreichardt@…>, 7 years ago

Adapts to changes in rrlib_rtti and finroc_core

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