1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev 
18*51c0b2f7Stbbdev #include "common/test.h"
19*51c0b2f7Stbbdev 
20*51c0b2f7Stbbdev #include "common/utils.h"
21*51c0b2f7Stbbdev #include "common/graph_utils.h"
22*51c0b2f7Stbbdev 
23*51c0b2f7Stbbdev #include "tbb/flow_graph.h"
24*51c0b2f7Stbbdev #include "tbb/task_arena.h"
25*51c0b2f7Stbbdev #include "tbb/global_control.h"
26*51c0b2f7Stbbdev 
27*51c0b2f7Stbbdev #include "conformance_flowgraph.h"
28*51c0b2f7Stbbdev 
29*51c0b2f7Stbbdev //! \file conformance_split_node.cpp
30*51c0b2f7Stbbdev //! \brief Test for [flow_graph.split_node] specification
31*51c0b2f7Stbbdev 
32*51c0b2f7Stbbdev /*
33*51c0b2f7Stbbdev TODO: implement missing conformance tests for split_node:
34*51c0b2f7Stbbdev   - [ ] Check that copy constructor and copy assignment is called for each type the tuple stores.
35*51c0b2f7Stbbdev   - [ ] Rewrite `test_forwarding' to check broadcast semantics of the node.
36*51c0b2f7Stbbdev   - [ ] Improve test for constructors.
37*51c0b2f7Stbbdev   - [ ] Unify code style in the test by extracting the implementation from the `TEST_CASE' scope
38*51c0b2f7Stbbdev     into separate functions.
39*51c0b2f7Stbbdev   - [ ] Rename discarding test to `test_buffering' and add checking that the value does not change
40*51c0b2f7Stbbdev     in the `try_get()' method of the output ports of the node.
41*51c0b2f7Stbbdev   - [ ] Add checking of the unlimited concurrency.
42*51c0b2f7Stbbdev   - [ ] Check that `try_put()' always returns `true'.
43*51c0b2f7Stbbdev   - [ ] Explicitly check that `output_ports_type' is defined, accessible.
44*51c0b2f7Stbbdev   - [ ] Explicitly check the method `indexer_node::output_ports()' exists, is accessible and it
45*51c0b2f7Stbbdev     returns a reference to the `output_ports_type' type.
46*51c0b2f7Stbbdev */
47*51c0b2f7Stbbdev 
48*51c0b2f7Stbbdev using namespace tbb::flow;
49*51c0b2f7Stbbdev using namespace std;
50*51c0b2f7Stbbdev 
51*51c0b2f7Stbbdev template<typename T>
52*51c0b2f7Stbbdev void test_inheritance(){
53*51c0b2f7Stbbdev     CHECK_MESSAGE( (std::is_base_of<graph_node, split_node<std::tuple<T,T>>>::value), "split_node should be derived from graph_node");
54*51c0b2f7Stbbdev     CHECK_MESSAGE( (std::is_base_of<receiver<std::tuple<T,T>>, split_node<std::tuple<T,T>>>::value), "split_node should be derived from receiver<T>");
55*51c0b2f7Stbbdev }
56*51c0b2f7Stbbdev 
57*51c0b2f7Stbbdev void test_split(){
58*51c0b2f7Stbbdev     graph g;
59*51c0b2f7Stbbdev 
60*51c0b2f7Stbbdev     queue_node<int> first_queue(g);
61*51c0b2f7Stbbdev     queue_node<int> second_queue(g);
62*51c0b2f7Stbbdev     split_node< std::tuple<int,int> > my_split_node(g);
63*51c0b2f7Stbbdev     make_edge(output_port<0>(my_split_node), first_queue);
64*51c0b2f7Stbbdev     make_edge(output_port<1>(my_split_node), second_queue);
65*51c0b2f7Stbbdev 
66*51c0b2f7Stbbdev     tuple<int, int> my_tuple(0, 1);
67*51c0b2f7Stbbdev     my_split_node.try_put(my_tuple);
68*51c0b2f7Stbbdev 
69*51c0b2f7Stbbdev     g.wait_for_all();
70*51c0b2f7Stbbdev 
71*51c0b2f7Stbbdev     int tmp = -1;
72*51c0b2f7Stbbdev     CHECK_MESSAGE((first_queue.try_get(tmp) == true), "Getting from target queue should succeed");
73*51c0b2f7Stbbdev     CHECK_MESSAGE((tmp == 0), "Received value should be correct");
74*51c0b2f7Stbbdev 
75*51c0b2f7Stbbdev     tmp = -1;
76*51c0b2f7Stbbdev     CHECK_MESSAGE((second_queue.try_get(tmp) == true), "Getting from target queue should succeed");
77*51c0b2f7Stbbdev     CHECK_MESSAGE((tmp == 1), "Received value should be correct");
78*51c0b2f7Stbbdev }
79*51c0b2f7Stbbdev 
80*51c0b2f7Stbbdev void test_copies(){
81*51c0b2f7Stbbdev     using namespace tbb::flow;
82*51c0b2f7Stbbdev 
83*51c0b2f7Stbbdev     graph g;
84*51c0b2f7Stbbdev     split_node<std::tuple<int, int>> n(g);
85*51c0b2f7Stbbdev     split_node<std::tuple<int, int>> n2(n);
86*51c0b2f7Stbbdev }
87*51c0b2f7Stbbdev 
88*51c0b2f7Stbbdev void test_forwarding(){
89*51c0b2f7Stbbdev     tbb::flow::graph g;
90*51c0b2f7Stbbdev 
91*51c0b2f7Stbbdev     tbb::flow::split_node<std::tuple<int, int>> node1(g);
92*51c0b2f7Stbbdev     test_push_receiver<int> node2(g);
93*51c0b2f7Stbbdev     test_push_receiver<int> node3(g);
94*51c0b2f7Stbbdev 
95*51c0b2f7Stbbdev     tbb::flow::make_edge(output_port<0>(node1), node2);
96*51c0b2f7Stbbdev     tbb::flow::make_edge(output_port<1>(node1), node3);
97*51c0b2f7Stbbdev 
98*51c0b2f7Stbbdev     tuple<int, int> my_tuple(0, 1);
99*51c0b2f7Stbbdev     node1.try_put(my_tuple);
100*51c0b2f7Stbbdev 
101*51c0b2f7Stbbdev     g.wait_for_all();
102*51c0b2f7Stbbdev 
103*51c0b2f7Stbbdev     CHECK_MESSAGE( (get_count(node2) == 1), "Descendant of the node needs to be receive N messages");
104*51c0b2f7Stbbdev     CHECK_MESSAGE( (get_count(node3) == 1), "Descendant of the node must receive one message.");
105*51c0b2f7Stbbdev }
106*51c0b2f7Stbbdev 
107*51c0b2f7Stbbdev //! Test broadcast
108*51c0b2f7Stbbdev //! \brief \ref interface
109*51c0b2f7Stbbdev TEST_CASE("split_node broadcast") {
110*51c0b2f7Stbbdev     test_forwarding();
111*51c0b2f7Stbbdev }
112*51c0b2f7Stbbdev 
113*51c0b2f7Stbbdev //! Test discarding property
114*51c0b2f7Stbbdev //! \brief \ref requirement
115*51c0b2f7Stbbdev TEST_CASE("split_node discarding") {
116*51c0b2f7Stbbdev     graph g;
117*51c0b2f7Stbbdev 
118*51c0b2f7Stbbdev     split_node< std::tuple<int,int> > my_split_node(g);
119*51c0b2f7Stbbdev 
120*51c0b2f7Stbbdev     limiter_node< int > rejecter1( g,0);
121*51c0b2f7Stbbdev     limiter_node< int > rejecter2( g,0);
122*51c0b2f7Stbbdev 
123*51c0b2f7Stbbdev     make_edge(output_port<0>(my_split_node), rejecter2);
124*51c0b2f7Stbbdev     make_edge(output_port<1>(my_split_node), rejecter1);
125*51c0b2f7Stbbdev 
126*51c0b2f7Stbbdev     tuple<int, int> my_tuple(0, 1);
127*51c0b2f7Stbbdev     my_split_node.try_put(my_tuple);
128*51c0b2f7Stbbdev     g.wait_for_all();
129*51c0b2f7Stbbdev 
130*51c0b2f7Stbbdev     int tmp = -1;
131*51c0b2f7Stbbdev     CHECK_MESSAGE((output_port<0>(my_split_node).try_get(tmp) == false), "Value should be discarded after rejection");
132*51c0b2f7Stbbdev     CHECK_MESSAGE((output_port<1>(my_split_node).try_get(tmp) == false), "Value should be discarded after rejection");
133*51c0b2f7Stbbdev }
134*51c0b2f7Stbbdev 
135*51c0b2f7Stbbdev //! Test copy constructor
136*51c0b2f7Stbbdev //! \brief \ref interface
137*51c0b2f7Stbbdev TEST_CASE("split_node copy constructor") {
138*51c0b2f7Stbbdev     test_copies();
139*51c0b2f7Stbbdev }
140*51c0b2f7Stbbdev 
141*51c0b2f7Stbbdev //! Test copy constructor
142*51c0b2f7Stbbdev //! \brief \ref interface \ref requirement
143*51c0b2f7Stbbdev TEST_CASE("split_node messages") {
144*51c0b2f7Stbbdev     test_split();
145*51c0b2f7Stbbdev }
146*51c0b2f7Stbbdev 
147*51c0b2f7Stbbdev //! Test copy constructor
148*51c0b2f7Stbbdev //! \brief \ref interface
149*51c0b2f7Stbbdev TEST_CASE("split_node superclasses") {
150*51c0b2f7Stbbdev     test_inheritance<int>();
151*51c0b2f7Stbbdev }
152*51c0b2f7Stbbdev 
153