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