1 /*
2 Copyright (c) 2005-2021 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #if __INTEL_COMPILER && _MSC_VER
18 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19 #endif
20
21 #include "common/config.h"
22
23 #include "tbb/flow_graph.h"
24
25 #include "common/test.h"
26 #include "common/utils.h"
27 #include "common/graph_utils.h"
28
29 #include <tuple>
30 #include <cmath>
31 #include <vector>
32
33
34 //! \file test_composite_node.cpp
35 //! \brief Test for [flow_graph.composite_node] specification
36
37
38 struct passthru_body {
operator ()passthru_body39 int operator()( int i ) {
40 return i;
41 }
42 };
43
44 class my_input_body{
45 int start;
46 int finish;
47 int step;
48 public:
my_input_body(int f,int s)49 my_input_body(int f, int s) : start(1), finish(f), step(s) {}
operator ()(tbb::flow_control & fc)50 int operator()(tbb::flow_control& fc) {
51 int a = start;
52 if (start <= finish) {
53 a = start;
54 start+=step;
55 return a;
56 }
57 else {
58 fc.stop();
59 return int();
60 };
61 }
62 };
63
64 struct m_fxn_body{
operator ()m_fxn_body65 void operator()(int, tbb::flow::multifunction_node<int, std::tuple<int,int> >::output_ports_type ) {}
66 };
67
68 struct ct_body {
ct_bodyct_body69 ct_body(){}
operator ()ct_body70 void operator()(tbb::flow::continue_msg){}
71 };
72
73 struct seq_body {
operator ()seq_body74 std::size_t operator()(int i) { return i; }
75 };
76
77 template<int N, typename T1, typename T2>
78 struct compare {
compare_refscompare79 static void compare_refs(T1 tuple1, T2 tuple2) {
80 CHECK_MESSAGE( ( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly");
81 compare<N-1, T1, T2>::compare_refs(tuple1, tuple2);
82 }
83 };
84
85 template<typename T1, typename T2>
86 struct compare<1, T1, T2> {
compare_refscompare87 static void compare_refs(T1 tuple1, T2 tuple2) {
88 CHECK_MESSAGE( (&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set");
89 }
90 };
91
92 struct tiny_node : public tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > {
93 tbb::flow::function_node< int, int > f1;
94 tbb::flow::function_node< int, int > f2;
95 typedef tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > base_type;
96
97 public:
tiny_nodetiny_node98 tiny_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), f1(g, tbb::flow::unlimited, passthru_body() ), f2(g, tbb::flow::unlimited, passthru_body() ) {
99 tbb::flow::make_edge(f1, f2);
100
101 std::tuple<tbb::flow::function_node< int, int >& > input_tuple(f1);
102 std::tuple<tbb::flow::function_node< int, int >& > output_tuple(f2);
103 base_type::set_external_ports(input_tuple, output_tuple);
104
105 if(hidden)
106 base_type::add_nodes(f1, f2);
107 else
108 base_type::add_visible_nodes(f1, f2);
109
110 }
111 };
112
test_tiny(bool hidden=false)113 int test_tiny(bool hidden = false) {
114 tbb::flow::graph g;
115 tbb::flow::function_node< int, int > f0( g, tbb::flow::unlimited, passthru_body() );
116 tiny_node t(g, hidden);
117 CHECK_MESSAGE( (&tbb::flow::input_port<0>(t) == &t.f1), "f1 not bound to input port 0 in composite_node t");
118 CHECK_MESSAGE( (&tbb::flow::output_port<0>(t) == &t.f2), "f2 not bound to output port 0 in composite_node t");
119
120 tiny_node t1(g, hidden);
121 CHECK_MESSAGE( (&std::get<0>(t1.input_ports()) == &t1.f1), "f1 not bound to input port 0 in composite_node t1");
122 CHECK_MESSAGE( (&std::get<0>(t1.output_ports()) == &t1.f2), "f2 not bound to output port 0 in composite_node t1");
123
124 test_input_ports_return_ref(t1);
125 test_output_ports_return_ref(t1);
126
127 tiny_node t2(g, hidden);
128 CHECK_MESSAGE( (&tbb::flow::input_port<0>(t2) == &t2.f1), "f1 not bound to input port 0 in composite_node t2");
129 CHECK_MESSAGE( (&tbb::flow::output_port<0>(t2) == &t2.f2), "f2 not bound to output port 0 in composite_node t2");
130
131 tbb::flow::function_node< int, int > f3( g, tbb::flow::unlimited, passthru_body() );
132 tbb::flow::make_edge( f0, t );
133 tbb::flow::make_edge( t, t1 );
134 tbb::flow::make_edge( t1, t2 );
135 tbb::flow::make_edge( t2 , f3 );
136 tbb::flow::queue_node<int> q(g);
137 tbb::flow::make_edge(f3, q);
138 f0.try_put(1);
139 g.wait_for_all();
140
141 int i, j =0;
142 q.try_get(i);
143 CHECK_MESSAGE( ( i == 1), "item did not go through graph");
144 q.try_get(j);
145 CHECK_MESSAGE( ( !j), "unexpected item in graph");
146 g.wait_for_all();
147
148 tbb::flow::remove_edge(f3, q);
149 tbb::flow::remove_edge(t2, f3);
150 tbb::flow::remove_edge(t1, t2);
151
152 tbb::flow::make_edge( t1 , f3 );
153 tbb::flow::make_edge(f3, q);
154
155 f0.try_put(2);
156 g.wait_for_all();
157
158 q.try_get(i);
159 CHECK_MESSAGE( ( i == 2), "item did not go through graph after removal of edge");
160 q.try_get(j);
161 CHECK_MESSAGE( ( !j), "unexpected item in graph after removal of edge");
162
163 return 0;
164 }
165
166 class adder_node : public tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > {
167 public:
168 tbb::flow::join_node< std::tuple< int, int >, tbb::flow::queueing > j;
169 tbb::flow::function_node< std::tuple< int, int >, int > f;
170 private:
171 typedef tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > base_type;
172
173 struct f_body {
operator ()adder_node::f_body174 int operator()( const std::tuple< int, int > &t ) {
175 return std::get<0>(t) + std::get<1>(t);
176 }
177 };
178
179 public:
adder_node(tbb::flow::graph & g,bool hidden=false)180 adder_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), j(g), f(g, tbb::flow::unlimited, f_body() ) {
181 tbb::flow::make_edge( j, f );
182
183 base_type::set_external_ports(base_type::input_ports_type(tbb::flow::input_port<0>(j), tbb::flow::input_port<1>(j)), base_type::output_ports_type(f));
184
185 if (hidden)
186 base_type::add_nodes(j, f);
187 else
188 base_type::add_visible_nodes(j, f);
189
190 }
191 };
192
operator ()square_body193 struct square_body { int operator()(int v) { return v*v; } };
operator ()cube_body194 struct cube_body { int operator()(int v) { return v*v*v; } };
adder_sum(int i)195 int adder_sum(int i) {
196 return (int)(pow(3*pow(i,3) + pow(i, 2),2));
197 }
test_adder(bool hidden=false)198 int test_adder(bool hidden = false) {
199 tbb::flow::graph g;
200 tbb::flow::function_node<int,int> s(g, tbb::flow::unlimited, square_body());
201 tbb::flow::function_node<int,int> c(g, tbb::flow::unlimited, cube_body());
202 tbb::flow::function_node<int,int> p(g, tbb::flow::unlimited, passthru_body());
203
204 adder_node a0(g, hidden);
205 CHECK_MESSAGE( (&tbb::flow::input_port<0>(a0) == &tbb::flow::input_port<0>(a0.j)), "input_port 0 of j not bound to input port 0 in composite_node a0");
206 CHECK_MESSAGE( (&tbb::flow::input_port<1>(a0) == &tbb::flow::input_port<1>(a0.j)), "input_port 1 of j not bound to input port 1 in composite_node a0");
207 CHECK_MESSAGE( (&tbb::flow::output_port<0>(a0) == &a0.f), "f not bound to output port 0 in composite_node a0");
208
209 adder_node a1(g, hidden);
210 CHECK_MESSAGE( (&std::get<0>(a0.input_ports()) == &tbb::flow::input_port<0>(a0.j)), "input_port 0 of j not bound to input port 0 in composite_node a1");
211 CHECK_MESSAGE( (&std::get<1>(a0.input_ports()) == &tbb::flow::input_port<1>(a0.j)), "input_port1 of j not bound to input port 1 in composite_node a1");
212 CHECK_MESSAGE( (&std::get<0>(a0.output_ports()) == &a0.f), "f not bound to output port 0 in composite_node a1");
213
214 adder_node a2(g, hidden);
215 CHECK_MESSAGE( (&tbb::flow::input_port<0>(a2) == &tbb::flow::input_port<0>(a2.j)), "input_port 0 of j not bound to input port 0 in composite_node a2");
216 CHECK_MESSAGE( (&tbb::flow::input_port<1>(a2) == &tbb::flow::input_port<1>(a2.j)), "input_port 1 of j not bound to input port 1 in composite_node a2");
217 CHECK_MESSAGE( (&tbb::flow::output_port<0>(a2) == &a2.f), "f not bound to output port 0 in composite_node a2");
218
219 adder_node a3(g, hidden);
220 CHECK_MESSAGE( (&std::get<0>(a3.input_ports()) == &tbb::flow::input_port<0>(a3.j)), "input_port 0 of j not bound to input port 0 in composite_node a3");
221 CHECK_MESSAGE( (&std::get<1>(a3.input_ports()) == &tbb::flow::input_port<1>(a3.j)), "input_port1 of j not bound to input port 1 in composite_node a3");
222 CHECK_MESSAGE( (&std::get<0>(a3.output_ports()) == &a3.f), "f not bound to output port 0 in composite_node a3");
223
224 tbb::flow::function_node<int,int> s2(g, tbb::flow::unlimited, square_body());
225 tbb::flow::queue_node<int> q(g);
226
227 tbb::flow::make_edge( s, tbb::flow::input_port<0>(a0) );
228 tbb::flow::make_edge( c, tbb::flow::input_port<1>(a0) );
229
230 tbb::flow::make_edge( c, tbb::flow::input_port<0>(a1) );
231 tbb::flow::make_edge( c, tbb::flow::input_port<1>(a1) );
232
233 tbb::flow::make_edge( tbb::flow::output_port<0>(a0), tbb::flow::input_port<0>(a2) );
234 tbb::flow::make_edge( tbb::flow::output_port<0>(a1), tbb::flow::input_port<1>(a2) );
235
236 tbb::flow::make_edge( tbb::flow::output_port<0>(a2), s2 );
237 tbb::flow::make_edge( s2, q );
238
239 int sum_total=0;
240 int result=0;
241 for ( int i = 1; i < 4; ++i ) {
242 s.try_put(i);
243 c.try_put(i);
244 sum_total += adder_sum(i);
245 g.wait_for_all();
246 }
247
248 int j;
249 for ( int i = 1; i < 4; ++i ) {
250 q.try_get(j);
251 result += j;
252 }
253 g.wait_for_all();
254 CHECK_MESSAGE( (result == sum_total), "the sum from the graph does not match the calculated value");
255
256 tbb::flow::remove_edge(s2, q);
257 tbb::flow::remove_edge( a2, s2 );
258 tbb::flow::make_edge( a0, a3 );
259 tbb::flow::make_edge( a1, tbb::flow::input_port<1>(a3) );
260 tbb::flow::make_edge( a3, s2 );
261 tbb::flow::make_edge( s2, q );
262
263 sum_total=0;
264 result=0;
265 for ( int i = 10; i < 20; ++i ) {
266 s.try_put(i);
267 c.try_put(i);
268 sum_total += adder_sum(i);
269 g.wait_for_all();
270 }
271
272 for ( int i = 10; i < 20; ++i ) {
273 q.try_get(j);
274 result += j;
275 }
276 g.wait_for_all();
277 CHECK_MESSAGE( (result == sum_total), "the new sum after the replacement of the nodes does not match the calculated value");
278
279 return 0;
280 }
281
282 /*
283 outer composite node (outer_node)
284 |-------------------------------------------------------------------|
285 | |
286 | |------------------| |------------------| |------------------| |
287 |---------------------| |--| inner composite | /| inner composite | /| inner composite | | |-------------------|
288 |broadcast node(input)|/| | node |/ | node |/ | node |-+-| queue node(output)|
289 |---------------------|\| |(inner_node1) |\ | (inner_node2) |\ | (inner_node3) | | |-------------------|
290 |--| | \| | \| | |
291 | |------------------| |------------------| |------------------| |
292 | |
293 |-------------------------------------------------------------------|
294
295 */
test_nested_adder(bool hidden=false)296 int test_nested_adder(bool hidden=false) {
297 tbb::flow::graph g;
298 tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > outer_node(g);
299 typedef tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > base_type;
300 tbb::flow::broadcast_node<int> input(g);
301 tbb::flow::queue_node<int> output(g);
302
303 adder_node inner_node1(g, hidden);
304 adder_node inner_node2(g, hidden);
305 adder_node inner_node3(g, hidden);
306
307 outer_node.set_external_ports(base_type::input_ports_type(tbb::flow::input_port<0>(inner_node1), tbb::flow::input_port<1>(inner_node1)), base_type::output_ports_type(tbb::flow::output_port<0>(inner_node3)));
308
309 CHECK_MESSAGE( (&tbb::flow::input_port<0>(outer_node) == &tbb::flow::input_port<0>(inner_node1)), "input port 0 of inner_node1 not bound to input port 0 in outer_node");
310 CHECK_MESSAGE( (&tbb::flow::input_port<1>(outer_node) == &tbb::flow::input_port<1>(inner_node1)), "input port 1 of inner_node1 not bound to input port 1 in outer_node");
311 CHECK_MESSAGE( (&tbb::flow::output_port<0>(outer_node) == &tbb::flow::output_port<0>(inner_node3)), "output port 0 of inner_node3 not bound to output port 0 in outer_node");
312
313 tbb::flow::make_edge(input, tbb::flow::input_port<0>(outer_node)/*inner_node1*/);
314 tbb::flow::make_edge(input, tbb::flow::input_port<1>(outer_node)/*inner_node1*/);
315
316 tbb::flow::make_edge(inner_node1, tbb::flow::input_port<0>(inner_node2));
317 tbb::flow::make_edge(inner_node1, tbb::flow::input_port<1>(inner_node2));
318
319 tbb::flow::make_edge(inner_node2, tbb::flow::input_port<0>(inner_node3));
320 tbb::flow::make_edge(inner_node2, tbb::flow::input_port<1>(inner_node3));
321
322 tbb::flow::make_edge(outer_node/*inner_node3*/, output);
323
324 if(hidden)
325 outer_node.add_nodes(inner_node1, inner_node2, inner_node3);
326 else
327 outer_node.add_visible_nodes(inner_node1, inner_node2, inner_node3);
328
329 int out;
330 for (int i = 1; i < 200000; ++i) {
331 input.try_put(i);
332 g.wait_for_all();
333 output.try_get(out);
334 CHECK_MESSAGE( (tbb::flow::output_port<0>(outer_node).try_get(out) == output.try_get(out)), "output from outer_node does not match output from graph");
335 CHECK_MESSAGE( (out == 8*i), "output from outer_node not correct");
336 }
337 g.wait_for_all();
338
339 return 0;
340 }
341
342 template< typename T >
343 class prefix_node : public tbb::flow::composite_node< std::tuple< T, T, T, T, T >, std::tuple< T, T, T, T, T > > {
344 typedef std::tuple< T, T, T, T, T > my_tuple_t;
345 public:
346 tbb::flow::join_node< my_tuple_t, tbb::flow::queueing > j;
347 tbb::flow::split_node< my_tuple_t > s;
348 private:
349 tbb::flow::function_node< my_tuple_t, my_tuple_t > f;
350 typedef tbb::flow::composite_node< my_tuple_t, my_tuple_t > base_type;
351
352 struct f_body {
operator ()prefix_node::f_body353 my_tuple_t operator()( const my_tuple_t &t ) {
354 return my_tuple_t( std::get<0>(t),
355 std::get<0>(t) + std::get<1>(t),
356 std::get<0>(t) + std::get<1>(t) + std::get<2>(t),
357 std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t),
358 std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t) + std::get<4>(t) );
359 }
360 };
361
362 public:
prefix_node(tbb::flow::graph & g,bool hidden=false)363 prefix_node(tbb::flow::graph &g, bool hidden = false ) : base_type(g), j(g), s(g), f(g, tbb::flow::serial, f_body() ) {
364 tbb::flow::make_edge( j, f );
365 tbb::flow::make_edge( f, s );
366
367 typename base_type::input_ports_type input_tuple(tbb::flow::input_port<0>(j), tbb::flow::input_port<1>(j), tbb::flow::input_port<2>(j), tbb::flow::input_port<3>(j), tbb::flow::input_port<4>(j));
368
369 typename base_type::output_ports_type output_tuple(tbb::flow::output_port<0>(s), tbb::flow::output_port<1>(s), tbb::flow::output_port<2>(s), tbb::flow::output_port<3>(s), tbb::flow::output_port<4>(s));
370
371 base_type::set_external_ports(input_tuple, output_tuple);
372
373 if(hidden)
374 base_type::add_nodes(j,s,f);
375 else
376 base_type::add_visible_nodes(j,s,f);
377
378 }
379 };
380
test_prefix(bool hidden=false)381 int test_prefix(bool hidden = false) {
382 tbb::flow::graph g;
383 prefix_node<double> p(g, hidden);
384
385 CHECK_MESSAGE( (&std::get<0>(p.input_ports()) == &tbb::flow::input_port<0>(p.j)), "input port 0 of j is not bound to input port 0 of composite node p");
386 CHECK_MESSAGE( (&tbb::flow::input_port<1>(p.j) == &tbb::flow::input_port<1>(p.j)), "input port 1 of j is not bound to input port 1 of composite node p");
387 CHECK_MESSAGE( (&std::get<2>(p.input_ports()) == &tbb::flow::input_port<2>(p.j)), "input port 2 of j is not bound to input port 2 of composite node p");
388 CHECK_MESSAGE( (&tbb::flow::input_port<3>(p.j) == &tbb::flow::input_port<3>(p.j)), "input port 3 of j is not bound to input port 3 of composite node p");
389 CHECK_MESSAGE( (&std::get<4>(p.input_ports()) == &tbb::flow::input_port<4>(p.j)), "input port 4 of j is not bound to input port 4 of composite node p");
390
391
392 CHECK_MESSAGE( (&std::get<0>(p.output_ports()) == &tbb::flow::output_port<0>(p.s)), "output port 0 of s is not bound to output port 0 of composite node p");
393 CHECK_MESSAGE( (&tbb::flow::output_port<1>(p.s) == &tbb::flow::output_port<1>(p.s)), "output port 1 of s is not bound to output port 1 of composite node p");
394 CHECK_MESSAGE( (&std::get<2>(p.output_ports()) == &tbb::flow::output_port<2>(p.s)), "output port 2 of s is not bound to output port 2 of composite node p");
395 CHECK_MESSAGE( (&tbb::flow::output_port<3>(p.s) == &tbb::flow::output_port<3>(p.s)), "output port 3 of s is not bound to output port 3 of composite node p");
396 CHECK_MESSAGE( (&std::get<4>(p.output_ports()) == &tbb::flow::output_port<4>(p.s)), "output port 4 of s is not bound to output port 4 of composite node p");
397
398 std::vector< tbb::flow::queue_node<double> > v( 5, tbb::flow::queue_node<double>(g) );
399 tbb::flow::make_edge( tbb::flow::output_port<0>(p), v[0] );
400 tbb::flow::make_edge( tbb::flow::output_port<1>(p), v[1] );
401 tbb::flow::make_edge( tbb::flow::output_port<2>(p), v[2] );
402 tbb::flow::make_edge( tbb::flow::output_port<3>(p), v[3] );
403 tbb::flow::make_edge( tbb::flow::output_port<4>(p), v[4] );
404
405 for( double offset = 1; offset < 10000; offset *= 10 ) {
406 tbb::flow::input_port<0>(p).try_put( offset );
407 tbb::flow::input_port<1>(p).try_put( offset + 1 );
408 tbb::flow::input_port<2>(p).try_put( offset + 2 );
409 tbb::flow::input_port<3>(p).try_put( offset + 3 );
410 tbb::flow::input_port<4>(p).try_put( offset + 4 );
411 }
412 g.wait_for_all();
413
414 double x;
415 while ( v[0].try_get(x) ) {
416 g.wait_for_all();
417 for ( int i = 1; i < 5; ++i ) {
418 v[i].try_get(x);
419 g.wait_for_all();
420 }
421 }
422 return 0;
423 }
424
425 struct input_only_output_only_seq {
operator ()input_only_output_only_seq426 std::size_t operator()(int i) {
427 CHECK(i > 0);
428 return std::size_t((i + 3) / 4 - 1);
429 }
430 };
431
input_only_output_only_composite(bool hidden)432 void input_only_output_only_composite(bool hidden) {
433 tbb::flow::graph g;
434
435 tbb::flow::composite_node<std::tuple<int>, std::tuple<int> > input_output(g);
436
437 typedef tbb::flow::composite_node<std::tuple<int>, std::tuple<> > input_only_composite;
438 typedef tbb::flow::composite_node<std::tuple<>, std::tuple<int> > output_only_composite;
439
440 typedef tbb::flow::input_node<int> src_type;
441 typedef tbb::flow::queue_node<int> q_type;
442 typedef tbb::flow::function_node<int, int> f_type;
443 typedef tbb::flow::sequencer_node<int> sequencer_type;
444
445 int num = 0;
446 int finish=1000;
447 int step = 4;
448
449 input_only_composite a_in(g);
450 output_only_composite a_out(g);
451
452 src_type src(g, my_input_body(finish, step));
453 q_type que(g);
454 f_type f(g, 1, passthru_body());
455
456 // Sequencer_node is needed, because serial function_node guarantees only serial body execution,
457 // not a sequential order of messages dispatch
458 sequencer_type seq(g, input_only_output_only_seq());
459
460 std::tuple<f_type& > input_tuple(f);
461 a_in.set_external_ports(input_tuple);
462 CHECK_MESSAGE( (&std::get<0>(a_in.input_ports()) == &f), "f not bound to input port 0 in composite_node a_in");
463
464 std::tuple<src_type&> output_tuple(src);
465 a_out.set_external_ports(output_tuple);
466 CHECK_MESSAGE( (&std::get<0>(a_out.output_ports()) == &src), "src not bound to output port 0 in composite_node a_out");
467
468 if(hidden) {
469 a_in.add_nodes(f, seq, que);
470 a_out.add_nodes(src);
471 } else {
472 a_in.add_visible_nodes(f, seq, que);
473 a_out.add_visible_nodes(src);
474 }
475
476 tbb::flow::make_edge(a_out, a_in);
477 tbb::flow::make_edge(f, seq);
478 tbb::flow::make_edge(seq, que);
479 src.activate();
480 g.wait_for_all();
481
482 for(int i = 1; i<finish/step; ++i) {
483 que.try_get(num);
484 CHECK_MESSAGE( (num == 4*i - 3), "number does not match position in sequence");
485 }
486 g.wait_for_all();
487 }
488
489 //! Test single node inside composite nodes
490 //! \brief \ref error_guessing
491 TEST_CASE("Tiny tests"){
492 test_tiny(false);
493 test_tiny(true);
494 }
495
496 //! Test basic adders in composite node
497 //! \brief \ref error_guessing
498 TEST_CASE("Adder tests"){
499 test_adder(false);
500 test_adder(true);
501 }
502
503 //! Test nested adders in composite node
504 //! \brief \ref error_guessing
505 TEST_CASE("Nested adder tests"){
506 test_nested_adder(true);
507 test_nested_adder(false);
508 }
509
510 //! Test returning a subset of inputs
511 //! \brief \ref error_guessing
512 TEST_CASE("Prefix test"){
513 test_prefix(false);
514 test_prefix(true);
515 }
516
517 //! Test input-only composite node
518 //! \brief \ref error_guessing \ref boundary
519 TEST_CASE("Input-only composite"){
520 input_only_output_only_composite(true);
521 input_only_output_only_composite(false);
522 }
523
524