1 /* 2 Copyright (c) 2020-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/test.h" 22 23 #include "common/utils.h" 24 #include "common/graph_utils.h" 25 26 #include "oneapi/tbb/flow_graph.h" 27 #include "oneapi/tbb/task_arena.h" 28 #include "oneapi/tbb/global_control.h" 29 30 #include "conformance_flowgraph.h" 31 32 //! \file conformance_join_node.cpp 33 //! \brief Test for [flow_graph.join_node] specification 34 35 /* 36 TODO: implement missing conformance tests for join_node: 37 - [ ] Check that `OutputTuple' is an instantiation of a tuple. 38 - [ ] The copy constructor and copy assignment are called for each type within the `OutputTuple'. 39 - [ ] Check all possible policies of the node: `reserving', `key_matching', `queueing', 40 `tag_matching'. Check the semantics the node has with each policy separately. 41 - [ ] Check that corresponding methods are invoked in specified `KHash' type. 42 - [ ] Improve test for constructors, including their availability based on used Policy for the 43 node. 44 - [ ] Unify code style in the test by extracting the implementation from the `TEST_CASE' scope 45 into separate functions. 46 - [ ] Check that corresponding methods mentioned in the requirements are called for `Bi' types. 47 - [ ] Explicitly check that `input_ports_type' is defined, accessible and is a tuple of 48 corresponding to `OutputTuple' receivers. 49 - [ ] Explicitly check the method `join_node::input_ports()' exists, is accessible and it returns 50 a reference to the `input_ports_type' type. 51 - [ ] Implement `test_buffering' (for node policy). 52 - [ ] Check `try_get()' copies the generated tuple into passed argument and returns `true'. If 53 node is empty returns `false'. 54 - [ ] Check `tag_value' is defined and has properties specified. 55 - [ ] Add test for CTAD. 56 */ 57 58 using namespace oneapi::tbb::flow; 59 using namespace std; 60 61 template<typename T> 62 void test_inheritance(){ 63 CHECK_MESSAGE( (std::is_base_of<graph_node, join_node<std::tuple<T, T>>>::value), "join_node should be derived from graph_node"); 64 CHECK_MESSAGE( (std::is_base_of<sender<std::tuple<T, T>>, join_node<std::tuple<T, T>>>::value), "join_node should be derived from graph_node"); 65 } 66 67 void test_copies(){ 68 using namespace oneapi::tbb::flow; 69 70 graph g; 71 join_node<std::tuple<int, int>> n(g); 72 join_node<std::tuple<int, int>> n2(n); 73 74 join_node <std::tuple<int, int, oneapi::tbb::flow::reserving>> nr(g); 75 join_node <std::tuple<int, int, oneapi::tbb::flow::reserving>> nr2(nr); 76 } 77 78 void test_forwarding(){ 79 oneapi::tbb::flow::graph g; 80 81 join_node<std::tuple<int, int>> node1(g); 82 83 using output_t = join_node<std::tuple<int, int>>::output_type; 84 85 test_push_receiver<output_t> node2(g); 86 test_push_receiver<output_t> node3(g); 87 88 oneapi::tbb::flow::make_edge(node1, node2); 89 oneapi::tbb::flow::make_edge(node1, node3); 90 91 input_port<0>(node1).try_put(1); 92 input_port<1>(node1).try_put(1); 93 94 g.wait_for_all(); 95 96 CHECK_MESSAGE( (get_count(node2) == 1), "Descendant of the node needs to be receive N messages"); 97 CHECK_MESSAGE( (get_count(node3) == 1), "Descendant of the node must receive one message."); 98 } 99 100 //! Test broadcast 101 //! \brief \ref interface 102 TEST_CASE("join_node broadcast") { 103 test_forwarding(); 104 } 105 106 107 //! Test copy constructor 108 //! \brief \ref interface 109 TEST_CASE("join_node copy constructor") { 110 test_copies(); 111 } 112 113 //! Test inheritance relations 114 //! \brief \ref interface 115 TEST_CASE("join_node inheritance"){ 116 test_inheritance<int>(); 117 } 118 119 //! Test join_node behavior 120 //! \brief \ref requirement 121 TEST_CASE("join_node") { 122 graph g; 123 function_node<int,int> 124 f1( g, unlimited, [](const int &i) { return 2*i; } ); 125 function_node<float,float> 126 f2( g, unlimited, [](const float &f) { return f/2; } ); 127 128 join_node< std::tuple<int,float> > j(g); 129 130 function_node< std::tuple<int,float> > 131 f3( g, unlimited, 132 []( const std::tuple<int,float> &t ) { 133 CHECK_MESSAGE( (std::get<0>(t) == 6), "Expected to receive 6" ); 134 CHECK_MESSAGE( (std::get<1>(t) == 1.5), "Expected to receive 1.5" ); 135 } ); 136 137 make_edge( f1, input_port<0>( j ) ); 138 make_edge( f2, input_port<1>( j ) ); 139 make_edge( j, f3 ); 140 141 f1.try_put( 3 ); 142 f2.try_put( 3 ); 143 g.wait_for_all( ); 144 } 145 146 //! Test join_node key matching behavior 147 //! \brief \ref requirement 148 TEST_CASE("remove edge to join_node"){ 149 graph g; 150 continue_node<int> c(g, [](const continue_msg&){ return 1; }); 151 join_node<tuple<int> > jn(g); 152 queue_node<tuple<int> > q(g); 153 154 make_edge(jn, q); 155 156 make_edge(c, jn); 157 158 c.try_put(continue_msg()); 159 g.wait_for_all(); 160 161 tuple<int> tmp = tuple<int>(0); 162 CHECK_MESSAGE( (q.try_get(tmp)== true), "Message should pass when edge exists"); 163 CHECK_MESSAGE( (tmp == tuple<int>(1) ), "Message should pass when edge exists"); 164 CHECK_MESSAGE( (q.try_get(tmp)== false), "Message should not pass after item is consumed"); 165 166 remove_edge(c, jn); 167 168 c.try_put(continue_msg()); 169 g.wait_for_all(); 170 171 tmp = tuple<int>(0); 172 CHECK_MESSAGE( (q.try_get(tmp)== false), "Message should not pass when edge doesn't exist"); 173 CHECK_MESSAGE( (tmp == tuple<int>(0)), "Value should not be altered"); 174 } 175 176 //! Test join_node key matching behavior 177 //! \brief \ref requirement 178 TEST_CASE("join_node key_matching"){ 179 graph g; 180 auto body1 = [](const continue_msg &) -> int { return 1; }; 181 auto body2 = [](const double &val) -> int { return int(val); }; 182 183 join_node<std::tuple<continue_msg, double>, key_matching<int>> jn(g, body1, body2); 184 185 input_port<0>(jn).try_put(continue_msg()); 186 input_port<1>(jn).try_put(1.3); 187 188 g.wait_for_all( ); 189 190 tuple<continue_msg, double> tmp; 191 CHECK_MESSAGE( (jn.try_get(tmp) == true), "Mapped keys should match"); 192 } 193