xref: /oneTBB/test/tbb/test_composite_node.cpp (revision b15aabb3)
151c0b2f7Stbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2005-2021 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
17*b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18*b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19*b15aabb3Stbbdev #endif
20*b15aabb3Stbbdev 
2151c0b2f7Stbbdev #include "common/config.h"
2251c0b2f7Stbbdev 
2351c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these
2451c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually
2551c0b2f7Stbbdev // released.
2651c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1
2751c0b2f7Stbbdev #include "tbb/flow_graph.h"
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev #include "common/test.h"
3051c0b2f7Stbbdev #include "common/utils.h"
3151c0b2f7Stbbdev #include "common/graph_utils.h"
3251c0b2f7Stbbdev 
3351c0b2f7Stbbdev #include <tuple>
3451c0b2f7Stbbdev #include <cmath>
3551c0b2f7Stbbdev #include <vector>
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev //! \file test_composite_node.cpp
3951c0b2f7Stbbdev //! \brief Test for [flow_graph.composite_node] specification
4051c0b2f7Stbbdev 
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev struct passthru_body {
4351c0b2f7Stbbdev     int operator()( int i ) {
4451c0b2f7Stbbdev         return i;
4551c0b2f7Stbbdev     }
4651c0b2f7Stbbdev };
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev class my_input_body{
4951c0b2f7Stbbdev     int start;
5051c0b2f7Stbbdev     int finish;
5151c0b2f7Stbbdev     int step;
5251c0b2f7Stbbdev public:
5351c0b2f7Stbbdev     my_input_body(int f, int s) : start(1), finish(f), step(s) {}
5451c0b2f7Stbbdev     int operator()(tbb::flow_control& fc) {
5551c0b2f7Stbbdev        int a = start;
5651c0b2f7Stbbdev        if (start <= finish) {
5751c0b2f7Stbbdev            a = start;
5851c0b2f7Stbbdev            start+=step;
5951c0b2f7Stbbdev            return a;
6051c0b2f7Stbbdev        }
6151c0b2f7Stbbdev        else {
6251c0b2f7Stbbdev            fc.stop();
6351c0b2f7Stbbdev            return int();
6451c0b2f7Stbbdev        };
6551c0b2f7Stbbdev    }
6651c0b2f7Stbbdev };
6751c0b2f7Stbbdev 
6851c0b2f7Stbbdev struct m_fxn_body{
6951c0b2f7Stbbdev     void operator()(int, tbb::flow::multifunction_node<int, std::tuple<int,int> >::output_ports_type ) {}
7051c0b2f7Stbbdev };
7151c0b2f7Stbbdev 
7251c0b2f7Stbbdev struct ct_body {
7351c0b2f7Stbbdev ct_body(){}
7451c0b2f7Stbbdev     void operator()(tbb::flow::continue_msg){}
7551c0b2f7Stbbdev };
7651c0b2f7Stbbdev 
7751c0b2f7Stbbdev struct seq_body {
7851c0b2f7Stbbdev int operator()(int i){return i;}
7951c0b2f7Stbbdev };
8051c0b2f7Stbbdev 
8151c0b2f7Stbbdev template<int N, typename T1, typename T2>
8251c0b2f7Stbbdev struct compare {
8351c0b2f7Stbbdev     static void compare_refs(T1 tuple1, T2 tuple2) {
8451c0b2f7Stbbdev     CHECK_MESSAGE( ( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly");
8551c0b2f7Stbbdev     compare<N-1, T1, T2>::compare_refs(tuple1, tuple2);
8651c0b2f7Stbbdev     }
8751c0b2f7Stbbdev };
8851c0b2f7Stbbdev 
8951c0b2f7Stbbdev template<typename T1, typename T2>
9051c0b2f7Stbbdev struct compare<1, T1, T2> {
9151c0b2f7Stbbdev     static void compare_refs(T1 tuple1, T2 tuple2) {
9251c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set");
9351c0b2f7Stbbdev     }
9451c0b2f7Stbbdev };
9551c0b2f7Stbbdev 
9651c0b2f7Stbbdev void add_all_nodes (){
9751c0b2f7Stbbdev     tbb::flow::graph g;
9851c0b2f7Stbbdev 
9951c0b2f7Stbbdev     typedef std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, int, int, int, int,
10051c0b2f7Stbbdev                              int, int, int, int, int, int, int, int > InputTupleType;
10151c0b2f7Stbbdev 
10251c0b2f7Stbbdev     typedef std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, tbb::flow::tagged_msg<size_t, int, float>,
10351c0b2f7Stbbdev                              int, int, int, int, int, int, int, int, int, int, int, int >  OutputTupleType;
10451c0b2f7Stbbdev 
10551c0b2f7Stbbdev     typedef std::tuple< > EmptyTupleType;
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev     typedef tbb::flow::composite_node<InputTupleType, OutputTupleType > input_output_type;
10851c0b2f7Stbbdev     typedef tbb::flow::composite_node<InputTupleType, EmptyTupleType > input_only_type;
10951c0b2f7Stbbdev     typedef tbb::flow::composite_node<EmptyTupleType, OutputTupleType > output_only_type;
11051c0b2f7Stbbdev 
11151c0b2f7Stbbdev     const size_t NUM_INPUTS = std::tuple_size<InputTupleType>::value;
11251c0b2f7Stbbdev     const size_t NUM_OUTPUTS = std::tuple_size<OutputTupleType>::value;
11351c0b2f7Stbbdev 
11451c0b2f7Stbbdev     //node types
11551c0b2f7Stbbdev     tbb::flow::continue_node<tbb::flow::continue_msg> ct(g, ct_body());
11651c0b2f7Stbbdev     tbb::flow::split_node< std::tuple<int, int> > s(g);
11751c0b2f7Stbbdev     tbb::flow::input_node<int> src(g, my_input_body(20,5));
11851c0b2f7Stbbdev     tbb::flow::function_node<int, int> fxn(g, tbb::flow::unlimited, passthru_body());
11951c0b2f7Stbbdev     tbb::flow::multifunction_node<int, std::tuple<int, int> > m_fxn(g, tbb::flow::unlimited, m_fxn_body());
12051c0b2f7Stbbdev     tbb::flow::broadcast_node<int> bc(g);
12151c0b2f7Stbbdev     tbb::flow::limiter_node<int> lim(g, 2);
12251c0b2f7Stbbdev     tbb::flow::indexer_node<int, float> ind(g);
12351c0b2f7Stbbdev     tbb::flow::join_node< std::tuple< int, int >, tbb::flow::queueing > j(g);
12451c0b2f7Stbbdev     tbb::flow::queue_node<int> q(g);
12551c0b2f7Stbbdev     tbb::flow::buffer_node<int> bf(g);
12651c0b2f7Stbbdev     tbb::flow::priority_queue_node<int> pq(g);
12751c0b2f7Stbbdev     tbb::flow::write_once_node<int> wo(g);
12851c0b2f7Stbbdev     tbb::flow::overwrite_node<int> ovw(g);
12951c0b2f7Stbbdev     tbb::flow::sequencer_node<int> seq(g, seq_body());
13051c0b2f7Stbbdev 
13151c0b2f7Stbbdev     auto input_tuple = std::tie(ct, s, m_fxn, fxn, bc, tbb::flow::input_port<0>(j), lim, q, tbb::flow::input_port<0>(ind),
13251c0b2f7Stbbdev                                 pq, ovw, wo, bf, seq);
13351c0b2f7Stbbdev     auto output_tuple = std::tie(ct,j, ind, fxn, src, bc, tbb::flow::output_port<0>(s), lim, tbb::flow::output_port<0>(m_fxn),
13451c0b2f7Stbbdev                                  q, pq, ovw, wo, bf, seq );
13551c0b2f7Stbbdev 
13651c0b2f7Stbbdev     //composite_node with both input_ports and output_ports
13751c0b2f7Stbbdev     input_output_type a_node(g);
13851c0b2f7Stbbdev     a_node.set_external_ports(input_tuple, output_tuple);
13951c0b2f7Stbbdev 
14051c0b2f7Stbbdev     a_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
14151c0b2f7Stbbdev     a_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
14251c0b2f7Stbbdev 
14351c0b2f7Stbbdev     auto a_node_input_ports_ptr = a_node.input_ports();
14451c0b2f7Stbbdev     compare<NUM_INPUTS-1, decltype(a_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(a_node_input_ports_ptr, input_tuple);
14551c0b2f7Stbbdev     CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(a_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes");
14651c0b2f7Stbbdev 
14751c0b2f7Stbbdev     auto a_node_output_ports_ptr = a_node.output_ports();
14851c0b2f7Stbbdev     compare<NUM_OUTPUTS-1, decltype(a_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(a_node_output_ports_ptr, output_tuple);
14951c0b2f7Stbbdev     CHECK_MESSAGE( (NUM_OUTPUTS == std::tuple_size<decltype(a_node_output_ports_ptr)>::value), "not all declared output ports were bound to nodes");
15051c0b2f7Stbbdev 
15151c0b2f7Stbbdev     //composite_node with only input_ports
15251c0b2f7Stbbdev     input_only_type b_node(g);
15351c0b2f7Stbbdev     b_node.set_external_ports(input_tuple);
15451c0b2f7Stbbdev 
15551c0b2f7Stbbdev     b_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
15651c0b2f7Stbbdev     b_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
15751c0b2f7Stbbdev 
15851c0b2f7Stbbdev     auto b_node_input_ports_ptr = b_node.input_ports();
15951c0b2f7Stbbdev     compare<NUM_INPUTS-1, decltype(b_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(b_node_input_ports_ptr, input_tuple);
16051c0b2f7Stbbdev     CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(b_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes");
16151c0b2f7Stbbdev 
16251c0b2f7Stbbdev     //composite_node with only output_ports
16351c0b2f7Stbbdev     output_only_type c_node(g);
16451c0b2f7Stbbdev     c_node.set_external_ports(output_tuple);
16551c0b2f7Stbbdev 
16651c0b2f7Stbbdev     // Reset is not suppose to do anything. Check that it can be called.
16751c0b2f7Stbbdev     g.reset();
16851c0b2f7Stbbdev 
16951c0b2f7Stbbdev     c_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
17051c0b2f7Stbbdev 
17151c0b2f7Stbbdev     c_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
17251c0b2f7Stbbdev 
17351c0b2f7Stbbdev     auto c_node_output_ports_ptr = c_node.output_ports();
17451c0b2f7Stbbdev     compare<NUM_OUTPUTS-1, decltype(c_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(c_node_output_ports_ptr, output_tuple);
17551c0b2f7Stbbdev     CHECK_MESSAGE(NUM_OUTPUTS == std::tuple_size<decltype(c_node_output_ports_ptr)>::value, "not all declared input ports were bound to nodes");
17651c0b2f7Stbbdev }
17751c0b2f7Stbbdev 
17851c0b2f7Stbbdev struct tiny_node : public tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > {
17951c0b2f7Stbbdev     tbb::flow::function_node< int, int > f1;
18051c0b2f7Stbbdev     tbb::flow::function_node< int, int > f2;
18151c0b2f7Stbbdev     typedef tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > base_type;
18251c0b2f7Stbbdev 
18351c0b2f7Stbbdev public:
18451c0b2f7Stbbdev     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() ) {
18551c0b2f7Stbbdev         tbb::flow::make_edge( f1, f2 );
18651c0b2f7Stbbdev 
18751c0b2f7Stbbdev         std::tuple<tbb::flow::function_node< int, int >& > input_tuple(f1);
18851c0b2f7Stbbdev         std::tuple<tbb::flow::function_node< int, int >& > output_tuple(f2);
18951c0b2f7Stbbdev         base_type::set_external_ports( input_tuple, output_tuple );
19051c0b2f7Stbbdev 
19151c0b2f7Stbbdev         if(hidden)
19251c0b2f7Stbbdev             base_type::add_nodes(f1, f2);
19351c0b2f7Stbbdev         else
19451c0b2f7Stbbdev             base_type::add_visible_nodes(f1, f2);
19551c0b2f7Stbbdev 
19651c0b2f7Stbbdev     }
19751c0b2f7Stbbdev };
19851c0b2f7Stbbdev 
19951c0b2f7Stbbdev int test_tiny(bool hidden = false) {
20051c0b2f7Stbbdev     tbb::flow::graph g;
20151c0b2f7Stbbdev     tbb::flow::function_node< int, int > f0( g, tbb::flow::unlimited, passthru_body() );
20251c0b2f7Stbbdev     tiny_node t(g, hidden);
20351c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(t) == &t.f1), "f1 not bound to input port 0 in composite_node t");
20451c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(t) == &t.f2), "f2 not bound to output port 0 in composite_node t");
20551c0b2f7Stbbdev 
20651c0b2f7Stbbdev     tiny_node t1(g, hidden);
20751c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(t1.input_ports()) == &t1.f1), "f1 not bound to input port 0 in composite_node t1");
20851c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(t1.output_ports()) == &t1.f2), "f2 not bound to output port 0 in composite_node t1");
20951c0b2f7Stbbdev 
21051c0b2f7Stbbdev     test_input_ports_return_ref(t1);
21151c0b2f7Stbbdev     test_output_ports_return_ref(t1);
21251c0b2f7Stbbdev 
21351c0b2f7Stbbdev     tiny_node t2(g, hidden);
21451c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(t2) == &t2.f1), "f1 not bound to input port 0 in composite_node t2");
21551c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(t2) == &t2.f2), "f2 not bound to output port 0 in composite_node t2");
21651c0b2f7Stbbdev 
21751c0b2f7Stbbdev     tbb::flow::function_node< int, int > f3( g, tbb::flow::unlimited, passthru_body() );
21851c0b2f7Stbbdev     tbb::flow::make_edge( f0, t );
21951c0b2f7Stbbdev     tbb::flow::make_edge( t, t1 );
22051c0b2f7Stbbdev     tbb::flow::make_edge( t1, t2 );
22151c0b2f7Stbbdev     tbb::flow::make_edge( t2 , f3 );
22251c0b2f7Stbbdev     tbb::flow::queue_node<int> q(g);
22351c0b2f7Stbbdev     tbb::flow::make_edge(f3, q);
22451c0b2f7Stbbdev     f0.try_put(1);
22551c0b2f7Stbbdev     g.wait_for_all();
22651c0b2f7Stbbdev 
22751c0b2f7Stbbdev     int i, j =0;
22851c0b2f7Stbbdev     q.try_get(i);
22951c0b2f7Stbbdev     CHECK_MESSAGE( ( i == 1), "item did not go through graph");
23051c0b2f7Stbbdev     q.try_get(j);
23151c0b2f7Stbbdev     CHECK_MESSAGE( ( !j), "unexpected item in graph");
23251c0b2f7Stbbdev     g.wait_for_all();
23351c0b2f7Stbbdev 
23451c0b2f7Stbbdev     tbb::flow::remove_edge(f3, q);
23551c0b2f7Stbbdev     tbb::flow::remove_edge(t2, f3);
23651c0b2f7Stbbdev     tbb::flow::remove_edge(t1, t2);
23751c0b2f7Stbbdev 
23851c0b2f7Stbbdev     tbb::flow::make_edge( t1 , f3 );
23951c0b2f7Stbbdev     tbb::flow::make_edge(f3, q);
24051c0b2f7Stbbdev 
24151c0b2f7Stbbdev     f0.try_put(2);
24251c0b2f7Stbbdev     g.wait_for_all();
24351c0b2f7Stbbdev 
24451c0b2f7Stbbdev     q.try_get(i);
24551c0b2f7Stbbdev     CHECK_MESSAGE( ( i == 2), "item did not go through graph after removal of edge");
24651c0b2f7Stbbdev     q.try_get(j);
24751c0b2f7Stbbdev     CHECK_MESSAGE( ( !j), "unexpected item in graph after removal of edge");
24851c0b2f7Stbbdev 
24951c0b2f7Stbbdev     return 0;
25051c0b2f7Stbbdev }
25151c0b2f7Stbbdev 
25251c0b2f7Stbbdev class adder_node : public tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > {
25351c0b2f7Stbbdev public:
25451c0b2f7Stbbdev     tbb::flow::join_node< std::tuple< int, int >, tbb::flow::queueing > j;
25551c0b2f7Stbbdev     tbb::flow::function_node< std::tuple< int, int >, int > f;
25651c0b2f7Stbbdev private:
25751c0b2f7Stbbdev     typedef tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > base_type;
25851c0b2f7Stbbdev 
25951c0b2f7Stbbdev     struct f_body {
26051c0b2f7Stbbdev         int operator()( const std::tuple< int, int > &t ) {
26151c0b2f7Stbbdev             return std::get<0>(t) + std::get<1>(t);
26251c0b2f7Stbbdev         }
26351c0b2f7Stbbdev     };
26451c0b2f7Stbbdev 
26551c0b2f7Stbbdev public:
26651c0b2f7Stbbdev     adder_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), j(g), f(g, tbb::flow::unlimited, f_body() ) {
26751c0b2f7Stbbdev         tbb::flow::make_edge( j, f );
26851c0b2f7Stbbdev 
26951c0b2f7Stbbdev         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));
27051c0b2f7Stbbdev 
27151c0b2f7Stbbdev         if (hidden)
27251c0b2f7Stbbdev             base_type::add_nodes(j, f);
27351c0b2f7Stbbdev         else
27451c0b2f7Stbbdev             base_type::add_visible_nodes(j, f);
27551c0b2f7Stbbdev 
27651c0b2f7Stbbdev     }
27751c0b2f7Stbbdev };
27851c0b2f7Stbbdev 
27951c0b2f7Stbbdev struct square_body { int operator()(int v) { return v*v; } };
28051c0b2f7Stbbdev struct cube_body { int operator()(int v) { return v*v*v; } };
28151c0b2f7Stbbdev int adder_sum(int i) {
28251c0b2f7Stbbdev     return (int)(pow(3*pow(i,3) + pow(i, 2),2));
28351c0b2f7Stbbdev }
28451c0b2f7Stbbdev int test_adder(bool hidden = false) {
28551c0b2f7Stbbdev     tbb::flow::graph g;
28651c0b2f7Stbbdev     tbb::flow::function_node<int,int> s(g, tbb::flow::unlimited, square_body());
28751c0b2f7Stbbdev     tbb::flow::function_node<int,int> c(g, tbb::flow::unlimited, cube_body());
28851c0b2f7Stbbdev     tbb::flow::function_node<int,int> p(g, tbb::flow::unlimited, passthru_body());
28951c0b2f7Stbbdev 
29051c0b2f7Stbbdev     adder_node a0(g, hidden);
29151c0b2f7Stbbdev     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");
29251c0b2f7Stbbdev     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");
29351c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(a0) == &a0.f), "f not bound to output port 0 in composite_node a0");
29451c0b2f7Stbbdev 
29551c0b2f7Stbbdev     adder_node a1(g, hidden);
29651c0b2f7Stbbdev     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");
29751c0b2f7Stbbdev     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");
29851c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a0.output_ports()) == &a0.f), "f not bound to output port 0 in composite_node a1");
29951c0b2f7Stbbdev 
30051c0b2f7Stbbdev     adder_node a2(g, hidden);
30151c0b2f7Stbbdev     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");
30251c0b2f7Stbbdev     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");
30351c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(a2) == &a2.f), "f not bound to output port 0 in composite_node a2");
30451c0b2f7Stbbdev 
30551c0b2f7Stbbdev     adder_node a3(g, hidden);
30651c0b2f7Stbbdev     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");
30751c0b2f7Stbbdev     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");
30851c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a3.output_ports()) == &a3.f), "f not bound to output port 0 in composite_node a3");
30951c0b2f7Stbbdev 
31051c0b2f7Stbbdev     tbb::flow::function_node<int,int> s2(g, tbb::flow::unlimited, square_body());
31151c0b2f7Stbbdev     tbb::flow::queue_node<int> q(g);
31251c0b2f7Stbbdev 
31351c0b2f7Stbbdev     tbb::flow::make_edge( s, tbb::flow::input_port<0>(a0) );
31451c0b2f7Stbbdev     tbb::flow::make_edge( c, tbb::flow::input_port<1>(a0) );
31551c0b2f7Stbbdev 
31651c0b2f7Stbbdev     tbb::flow::make_edge( c, tbb::flow::input_port<0>(a1) );
31751c0b2f7Stbbdev     tbb::flow::make_edge( c, tbb::flow::input_port<1>(a1) );
31851c0b2f7Stbbdev 
31951c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(a0), tbb::flow::input_port<0>(a2) );
32051c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(a1), tbb::flow::input_port<1>(a2) );
32151c0b2f7Stbbdev 
32251c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(a2), s2 );
32351c0b2f7Stbbdev     tbb::flow::make_edge( s2, q );
32451c0b2f7Stbbdev 
32551c0b2f7Stbbdev     int sum_total=0;
32651c0b2f7Stbbdev     int result=0;
32751c0b2f7Stbbdev     for ( int i = 1; i < 4; ++i ) {
32851c0b2f7Stbbdev         s.try_put(i);
32951c0b2f7Stbbdev         c.try_put(i);
33051c0b2f7Stbbdev         sum_total += adder_sum(i);
33151c0b2f7Stbbdev         g.wait_for_all();
33251c0b2f7Stbbdev     }
33351c0b2f7Stbbdev 
33451c0b2f7Stbbdev     int j;
33551c0b2f7Stbbdev     for ( int i = 1; i < 4; ++i ) {
33651c0b2f7Stbbdev         q.try_get(j);
33751c0b2f7Stbbdev         result += j;
33851c0b2f7Stbbdev     }
33951c0b2f7Stbbdev     g.wait_for_all();
34051c0b2f7Stbbdev     CHECK_MESSAGE( (result == sum_total), "the sum from the graph does not match the calculated value");
34151c0b2f7Stbbdev 
34251c0b2f7Stbbdev     tbb::flow::remove_edge(s2, q);
34351c0b2f7Stbbdev     tbb::flow::remove_edge( a2, s2 );
34451c0b2f7Stbbdev     tbb::flow::make_edge( a0, a3 );
34551c0b2f7Stbbdev     tbb::flow::make_edge( a1, tbb::flow::input_port<1>(a3) );
34651c0b2f7Stbbdev     tbb::flow::make_edge( a3, s2 );
34751c0b2f7Stbbdev     tbb::flow::make_edge( s2, q );
34851c0b2f7Stbbdev 
34951c0b2f7Stbbdev     sum_total=0;
35051c0b2f7Stbbdev     result=0;
35151c0b2f7Stbbdev     for ( int i = 10; i < 20; ++i ) {
35251c0b2f7Stbbdev         s.try_put(i);
35351c0b2f7Stbbdev         c.try_put(i);
35451c0b2f7Stbbdev         sum_total += adder_sum(i);
35551c0b2f7Stbbdev         g.wait_for_all();
35651c0b2f7Stbbdev     }
35751c0b2f7Stbbdev 
35851c0b2f7Stbbdev     for ( int i = 10; i < 20; ++i ) {
35951c0b2f7Stbbdev         q.try_get(j);
36051c0b2f7Stbbdev         result += j;
36151c0b2f7Stbbdev     }
36251c0b2f7Stbbdev     g.wait_for_all();
36351c0b2f7Stbbdev     CHECK_MESSAGE( (result == sum_total), "the new sum after the replacement of the nodes does not match the calculated value");
36451c0b2f7Stbbdev 
36551c0b2f7Stbbdev     return 0;
36651c0b2f7Stbbdev }
36751c0b2f7Stbbdev 
36851c0b2f7Stbbdev /*
36951c0b2f7Stbbdev                                               outer composite node (outer_node)
37051c0b2f7Stbbdev                                      |-------------------------------------------------------------------|
37151c0b2f7Stbbdev                                      |                                                                   |
37251c0b2f7Stbbdev                                      |  |------------------|  |------------------|  |------------------| |
37351c0b2f7Stbbdev              |---------------------| |--| inner composite  | /| inner composite  | /| inner composite  | | |-------------------|
37451c0b2f7Stbbdev              |broadcast node(input)|/|  | node             |/ | node             |/ | node             |-+-| queue node(output)|
37551c0b2f7Stbbdev              |---------------------|\|  |(inner_node1)     |\ | (inner_node2)    |\ | (inner_node3)    | | |-------------------|
37651c0b2f7Stbbdev                                      |--|                  | \|                  | \|                  | |
37751c0b2f7Stbbdev                                      |  |------------------|  |------------------|  |------------------| |
37851c0b2f7Stbbdev                                      |                                                                   |
37951c0b2f7Stbbdev                                      |-------------------------------------------------------------------|
38051c0b2f7Stbbdev 
38151c0b2f7Stbbdev */
38251c0b2f7Stbbdev int test_nested_adder(bool hidden=false) {
38351c0b2f7Stbbdev     tbb::flow::graph g;
38451c0b2f7Stbbdev     tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > outer_node(g);
38551c0b2f7Stbbdev     typedef tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > base_type;
38651c0b2f7Stbbdev     tbb::flow::broadcast_node<int> input(g);
38751c0b2f7Stbbdev     tbb::flow::queue_node<int> output(g);
38851c0b2f7Stbbdev 
38951c0b2f7Stbbdev     adder_node inner_node1(g, hidden);
39051c0b2f7Stbbdev     adder_node inner_node2(g, hidden);
39151c0b2f7Stbbdev     adder_node inner_node3(g, hidden);
39251c0b2f7Stbbdev 
39351c0b2f7Stbbdev     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)));
39451c0b2f7Stbbdev 
39551c0b2f7Stbbdev     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");
39651c0b2f7Stbbdev     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");
39751c0b2f7Stbbdev     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");
39851c0b2f7Stbbdev 
39951c0b2f7Stbbdev     tbb::flow::make_edge(input, tbb::flow::input_port<0>(outer_node)/*inner_node1*/);
40051c0b2f7Stbbdev     tbb::flow::make_edge(input, tbb::flow::input_port<1>(outer_node)/*inner_node1*/);
40151c0b2f7Stbbdev 
40251c0b2f7Stbbdev     tbb::flow::make_edge(inner_node1, tbb::flow::input_port<0>(inner_node2));
40351c0b2f7Stbbdev     tbb::flow::make_edge(inner_node1, tbb::flow::input_port<1>(inner_node2));
40451c0b2f7Stbbdev 
40551c0b2f7Stbbdev     tbb::flow::make_edge(inner_node2, tbb::flow::input_port<0>(inner_node3));
40651c0b2f7Stbbdev     tbb::flow::make_edge(inner_node2, tbb::flow::input_port<1>(inner_node3));
40751c0b2f7Stbbdev 
40851c0b2f7Stbbdev     tbb::flow::make_edge(outer_node/*inner_node3*/, output);
40951c0b2f7Stbbdev 
41051c0b2f7Stbbdev     if(hidden)
41151c0b2f7Stbbdev         outer_node.add_nodes(inner_node1, inner_node2, inner_node3);
41251c0b2f7Stbbdev     else
41351c0b2f7Stbbdev         outer_node.add_visible_nodes(inner_node1, inner_node2, inner_node3);
41451c0b2f7Stbbdev 
41551c0b2f7Stbbdev     int out;
41651c0b2f7Stbbdev     for (int i = 1; i < 200000; ++i) {
41751c0b2f7Stbbdev         input.try_put(i);
41851c0b2f7Stbbdev         g.wait_for_all();
41951c0b2f7Stbbdev         output.try_get(out);
42051c0b2f7Stbbdev         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");
42151c0b2f7Stbbdev         CHECK_MESSAGE( (out == 8*i), "output from outer_node not correct");
42251c0b2f7Stbbdev     }
42351c0b2f7Stbbdev     g.wait_for_all();
42451c0b2f7Stbbdev 
42551c0b2f7Stbbdev     return 0;
42651c0b2f7Stbbdev }
42751c0b2f7Stbbdev 
42851c0b2f7Stbbdev template< typename T >
42951c0b2f7Stbbdev class prefix_node : public tbb::flow::composite_node< std::tuple< T, T, T, T, T >, std::tuple< T, T, T, T, T > > {
43051c0b2f7Stbbdev     typedef std::tuple< T, T, T, T, T > my_tuple_t;
43151c0b2f7Stbbdev public:
43251c0b2f7Stbbdev     tbb::flow::join_node< my_tuple_t, tbb::flow::queueing > j;
43351c0b2f7Stbbdev     tbb::flow::split_node< my_tuple_t > s;
43451c0b2f7Stbbdev private:
43551c0b2f7Stbbdev     tbb::flow::function_node< my_tuple_t, my_tuple_t > f;
43651c0b2f7Stbbdev     typedef tbb::flow::composite_node< my_tuple_t, my_tuple_t > base_type;
43751c0b2f7Stbbdev 
43851c0b2f7Stbbdev     struct f_body {
43951c0b2f7Stbbdev         my_tuple_t operator()( const my_tuple_t &t ) {
44051c0b2f7Stbbdev             return my_tuple_t( std::get<0>(t),
44151c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t),
44251c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t) + std::get<2>(t),
44351c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t),
44451c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t) + std::get<4>(t) );
44551c0b2f7Stbbdev         }
44651c0b2f7Stbbdev     };
44751c0b2f7Stbbdev 
44851c0b2f7Stbbdev public:
44951c0b2f7Stbbdev     prefix_node(tbb::flow::graph &g, bool hidden = false ) : base_type(g), j(g), s(g), f(g, tbb::flow::serial, f_body() ) {
45051c0b2f7Stbbdev         tbb::flow::make_edge( j, f );
45151c0b2f7Stbbdev         tbb::flow::make_edge( f, s );
45251c0b2f7Stbbdev 
45351c0b2f7Stbbdev     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));
45451c0b2f7Stbbdev 
45551c0b2f7Stbbdev     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));
45651c0b2f7Stbbdev 
45751c0b2f7Stbbdev     base_type::set_external_ports(input_tuple, output_tuple);
45851c0b2f7Stbbdev 
45951c0b2f7Stbbdev         if(hidden)
46051c0b2f7Stbbdev             base_type::add_nodes(j,s,f);
46151c0b2f7Stbbdev         else
46251c0b2f7Stbbdev             base_type::add_visible_nodes(j,s,f);
46351c0b2f7Stbbdev 
46451c0b2f7Stbbdev     }
46551c0b2f7Stbbdev };
46651c0b2f7Stbbdev 
46751c0b2f7Stbbdev int test_prefix(bool hidden = false) {
46851c0b2f7Stbbdev     tbb::flow::graph g;
46951c0b2f7Stbbdev     prefix_node<double> p(g, hidden);
47051c0b2f7Stbbdev 
47151c0b2f7Stbbdev     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");
47251c0b2f7Stbbdev     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");
47351c0b2f7Stbbdev     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");
47451c0b2f7Stbbdev     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");
47551c0b2f7Stbbdev     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");
47651c0b2f7Stbbdev 
47751c0b2f7Stbbdev 
47851c0b2f7Stbbdev     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");
47951c0b2f7Stbbdev     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");
48051c0b2f7Stbbdev     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");
48151c0b2f7Stbbdev     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");
48251c0b2f7Stbbdev     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");
48351c0b2f7Stbbdev 
48451c0b2f7Stbbdev     std::vector< tbb::flow::queue_node<double> > v( 5, tbb::flow::queue_node<double>(g) );
48551c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(p), v[0] );
48651c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<1>(p), v[1] );
48751c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<2>(p), v[2] );
48851c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<3>(p), v[3] );
48951c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<4>(p), v[4] );
49051c0b2f7Stbbdev 
49151c0b2f7Stbbdev     for(  double offset = 1; offset < 10000; offset *= 10 ) {
49251c0b2f7Stbbdev         tbb::flow::input_port<0>(p).try_put( offset );
49351c0b2f7Stbbdev         tbb::flow::input_port<1>(p).try_put( offset + 1 );
49451c0b2f7Stbbdev         tbb::flow::input_port<2>(p).try_put( offset + 2 );
49551c0b2f7Stbbdev         tbb::flow::input_port<3>(p).try_put( offset + 3 );
49651c0b2f7Stbbdev         tbb::flow::input_port<4>(p).try_put( offset + 4 );
49751c0b2f7Stbbdev     }
49851c0b2f7Stbbdev     g.wait_for_all();
49951c0b2f7Stbbdev 
50051c0b2f7Stbbdev     double x;
50151c0b2f7Stbbdev     while ( v[0].try_get(x) ) {
50251c0b2f7Stbbdev         g.wait_for_all();
50351c0b2f7Stbbdev         for ( int i = 1; i < 5; ++i ) {
50451c0b2f7Stbbdev             v[i].try_get(x);
50551c0b2f7Stbbdev             g.wait_for_all();
50651c0b2f7Stbbdev         }
50751c0b2f7Stbbdev     }
50851c0b2f7Stbbdev     return 0;
50951c0b2f7Stbbdev }
51051c0b2f7Stbbdev 
51151c0b2f7Stbbdev struct input_only_output_only_seq {
51251c0b2f7Stbbdev     int operator()(int i){ return (i + 3) / 4 - 1;}
51351c0b2f7Stbbdev };
51451c0b2f7Stbbdev 
51551c0b2f7Stbbdev void input_only_output_only_composite(bool hidden) {
51651c0b2f7Stbbdev     tbb::flow::graph g;
51751c0b2f7Stbbdev 
51851c0b2f7Stbbdev     tbb::flow::composite_node<std::tuple<int>, std::tuple<int> > input_output(g);
51951c0b2f7Stbbdev 
52051c0b2f7Stbbdev     typedef tbb::flow::composite_node<std::tuple<int>, std::tuple<> > input_only_composite;
52151c0b2f7Stbbdev     typedef tbb::flow::composite_node<std::tuple<>, std::tuple<int> > output_only_composite;
52251c0b2f7Stbbdev 
52351c0b2f7Stbbdev     typedef tbb::flow::input_node<int> src_type;
52451c0b2f7Stbbdev     typedef tbb::flow::queue_node<int> q_type;
52551c0b2f7Stbbdev     typedef tbb::flow::function_node<int, int> f_type;
52651c0b2f7Stbbdev     typedef tbb::flow::sequencer_node<int> sequencer_type;
52751c0b2f7Stbbdev 
52851c0b2f7Stbbdev     int num = 0;
52951c0b2f7Stbbdev     int finish=1000;
53051c0b2f7Stbbdev     int step = 4;
53151c0b2f7Stbbdev 
53251c0b2f7Stbbdev     input_only_composite a_in(g);
53351c0b2f7Stbbdev     output_only_composite a_out(g);
53451c0b2f7Stbbdev 
53551c0b2f7Stbbdev     src_type src(g, my_input_body(finish, step));
53651c0b2f7Stbbdev     q_type que(g);
53751c0b2f7Stbbdev     f_type f(g, 1, passthru_body());
53851c0b2f7Stbbdev 
53951c0b2f7Stbbdev     // Sequencer_node is needed, because serial function_node guarantees only serial body execution,
54051c0b2f7Stbbdev     // not a sequential order of messages dispatch
54151c0b2f7Stbbdev     sequencer_type seq(g, input_only_output_only_seq());
54251c0b2f7Stbbdev 
54351c0b2f7Stbbdev     std::tuple<f_type& > input_tuple(f);
54451c0b2f7Stbbdev     a_in.set_external_ports(input_tuple);
54551c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a_in.input_ports()) == &f), "f not bound to input port 0 in composite_node a_in");
54651c0b2f7Stbbdev 
54751c0b2f7Stbbdev     std::tuple<src_type&> output_tuple(src);
54851c0b2f7Stbbdev     a_out.set_external_ports(output_tuple);
54951c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a_out.output_ports()) == &src), "src not bound to output port 0 in composite_node a_out");
55051c0b2f7Stbbdev 
55151c0b2f7Stbbdev     if(hidden) {
55251c0b2f7Stbbdev         a_in.add_nodes(f, seq, que);
55351c0b2f7Stbbdev         a_out.add_nodes(src);
55451c0b2f7Stbbdev     } else {
55551c0b2f7Stbbdev         a_in.add_visible_nodes(f, seq, que);
55651c0b2f7Stbbdev         a_out.add_visible_nodes(src);
55751c0b2f7Stbbdev     }
55851c0b2f7Stbbdev 
55951c0b2f7Stbbdev     tbb::flow::make_edge(a_out, a_in);
56051c0b2f7Stbbdev     tbb::flow::make_edge(f, seq);
56151c0b2f7Stbbdev     tbb::flow::make_edge(seq, que);
56251c0b2f7Stbbdev     src.activate();
56351c0b2f7Stbbdev     g.wait_for_all();
56451c0b2f7Stbbdev 
56551c0b2f7Stbbdev     for(int i = 1; i<finish/step; ++i) {
56651c0b2f7Stbbdev         que.try_get(num);
56751c0b2f7Stbbdev         CHECK_MESSAGE( (num == 4*i - 3), "number does not match position in sequence");
56851c0b2f7Stbbdev     }
56951c0b2f7Stbbdev     g.wait_for_all();
57051c0b2f7Stbbdev }
57151c0b2f7Stbbdev 
57251c0b2f7Stbbdev //! Test all node types inside composite node
57351c0b2f7Stbbdev //! \brief \ref error_guessing
57451c0b2f7Stbbdev TEST_CASE("Add all nodes"){
57551c0b2f7Stbbdev     add_all_nodes();
57651c0b2f7Stbbdev }
57751c0b2f7Stbbdev 
57851c0b2f7Stbbdev //! Test single node inside composite nodes
57951c0b2f7Stbbdev //! \brief \ref error_guessing
58051c0b2f7Stbbdev TEST_CASE("Tiny tests"){
58151c0b2f7Stbbdev     test_tiny(false);
58251c0b2f7Stbbdev     test_tiny(true);
58351c0b2f7Stbbdev }
58451c0b2f7Stbbdev 
58551c0b2f7Stbbdev //! Test basic adders in composite node
58651c0b2f7Stbbdev //! \brief \ref error_guessing
58751c0b2f7Stbbdev TEST_CASE("Adder tests"){
58851c0b2f7Stbbdev     test_adder(false);
58951c0b2f7Stbbdev     test_adder(true);
59051c0b2f7Stbbdev }
59151c0b2f7Stbbdev 
59251c0b2f7Stbbdev //! Test nested adders in composite node
59351c0b2f7Stbbdev //! \brief \ref error_guessing
59451c0b2f7Stbbdev TEST_CASE("Nested adder tests"){
59551c0b2f7Stbbdev     test_nested_adder(true);
59651c0b2f7Stbbdev     test_nested_adder(false);
59751c0b2f7Stbbdev }
59851c0b2f7Stbbdev 
59951c0b2f7Stbbdev //! Test returning a subset of inputs
60051c0b2f7Stbbdev //! \brief \ref error_guessing
60151c0b2f7Stbbdev TEST_CASE("Prefix test"){
60251c0b2f7Stbbdev     test_prefix(false);
60351c0b2f7Stbbdev     test_prefix(true);
60451c0b2f7Stbbdev }
60551c0b2f7Stbbdev 
60651c0b2f7Stbbdev //! Test input-only composite node
60751c0b2f7Stbbdev //! \brief \ref error_guessing \ref boundary
60851c0b2f7Stbbdev TEST_CASE("Input-only composite"){
60951c0b2f7Stbbdev     input_only_output_only_composite(true);
61051c0b2f7Stbbdev     input_only_output_only_composite(false);
61151c0b2f7Stbbdev }
61251c0b2f7Stbbdev 
613