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