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 "conformance_flowgraph.h"
22 
23 //! \file conformance_indexer_node.cpp
24 //! \brief Test for [flow_graph.indexer_node] specification
25 
26 using input_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true, /*copy_assign*/false>;
27 using my_indexer_type = oneapi::tbb::flow::indexer_node<int, float, input_msg>;
28 using my_output_type = my_indexer_type::output_type;
29 
30 //! Test node broadcast messages to successors
31 //! \brief \ref requirement
32 TEST_CASE("indexer_node broadcasts"){
33     oneapi::tbb::flow::graph g;
34 
35     my_indexer_type testing_node(g);
36     std::vector<conformance::test_push_receiver<my_output_type>*> receiver_nodes;
37 
38     for(std::size_t i = 0; i < 3; ++i) {
39         receiver_nodes.emplace_back(new conformance::test_push_receiver<my_output_type>(g));
40         oneapi::tbb::flow::make_edge(testing_node, *receiver_nodes.back());
41     }
42 
43     oneapi::tbb::flow::input_port<0>(testing_node).try_put(6);
44     oneapi::tbb::flow::input_port<1>(testing_node).try_put(1.5);
45     oneapi::tbb::flow::input_port<2>(testing_node).try_put(input_msg(1));
46     g.wait_for_all();
47 
48     for(auto receiver: receiver_nodes) {
49         auto values = conformance::get_values(*receiver);
50         CHECK_MESSAGE((values.size() == 3), std::string("Descendant of the node must receive 3 messages."));
51         for(auto& value : values){
52             if(value.is_a<int>()){
53                 CHECK_MESSAGE((value.cast_to<int>() == 6), "Value passed is the actual one received.");
54             } else if(value.is_a<float>()){
55                 CHECK_MESSAGE((value.cast_to<float>() == 1.5), "Value passed is the actual one received.");
56             } else {
57                 CHECK_MESSAGE((value.cast_to<input_msg>() == 1), "Value passed is the actual one received.");
58             }
59         }
60         delete receiver;
61     }
62 }
63 
64 //! Test inheritance relations
65 //! \brief \ref interface
66 TEST_CASE("indexer_node superclasses"){
67     CHECK_MESSAGE((std::is_base_of<oneapi::tbb::flow::graph_node, my_indexer_type>::value), "indexer_node should be derived from graph_node");
68 }
69 
70 //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
71 //! \brief \ref requirement
72 TEST_CASE("indexer_node buffering") {
73     oneapi::tbb::flow::graph g;
74 
75     my_indexer_type testing_node(g);
76 
77     oneapi::tbb::flow::limiter_node<my_output_type> rejecter(g,0);
78     oneapi::tbb::flow::make_edge(testing_node, rejecter);
79 
80     oneapi::tbb::flow::input_port<0>(testing_node).try_put(6);
81     oneapi::tbb::flow::input_port<1>(testing_node).try_put(1.5);
82     oneapi::tbb::flow::input_port<2>(testing_node).try_put(input_msg(1));
83 
84     my_output_type tmp;
85     CHECK_MESSAGE((testing_node.try_get(tmp) == false), "Value should be discarded after rejection");
86     g.wait_for_all();
87 }
88 
89 //! Test indexer behaviour
90 //! \brief \ref requirement
91 TEST_CASE("indexer_node behaviour") {
92     oneapi::tbb::flow::graph g;
93     oneapi::tbb::flow::function_node<int, int> f1( g, oneapi::tbb::flow::unlimited,
94                                 [](const int &i) { return 2*i; } );
95     oneapi::tbb::flow::function_node<float, float> f2( g, oneapi::tbb::flow::unlimited,
96                                 [](const float &f) { return f/2; } );
97     oneapi::tbb::flow::continue_node<input_msg> c1( g,
98                                 [](oneapi::tbb::flow::continue_msg) { return input_msg(5); } );
99 
100     my_indexer_type testing_node(g);
101 
102     oneapi::tbb::flow::function_node<my_output_type>
103         f3( g, oneapi::tbb::flow::unlimited,
104             []( const my_output_type &v ) {
105                 if (v.tag() == 0) {
106                     CHECK_MESSAGE((v.is_a<int>()), "Expected to int" );
107                     CHECK_MESSAGE((oneapi::tbb::flow::cast_to<int>(v) == 6), "Expected to receive 6" );
108                 } else if (v.tag() == 1) {
109                     CHECK_MESSAGE((v.is_a<float>()), "Expected to float" );
110                     CHECK_MESSAGE((oneapi::tbb::flow::cast_to<float>(v) == 1.5), "Expected to receive 1.5" );
111                 } else {
112                     CHECK_MESSAGE((v.is_a<input_msg>()), "Expected to float" );
113                     CHECK_MESSAGE((oneapi::tbb::flow::cast_to<input_msg>(v) == 5), "Expected to receive input_msg(5)" );
114                 }
115             }
116         );
117 
118     oneapi::tbb::flow::make_edge(f1, oneapi::tbb::flow::input_port<0>(testing_node));
119     oneapi::tbb::flow::make_edge(f2, oneapi::tbb::flow::input_port<1>(testing_node));
120     oneapi::tbb::flow::make_edge(c1, oneapi::tbb::flow::input_port<2>(testing_node));
121     oneapi::tbb::flow::make_edge(testing_node, f3);
122 
123     f1.try_put(3);
124     f2.try_put(3);
125     c1.try_put(oneapi::tbb::flow::continue_msg());
126     g.wait_for_all();
127 }
128 
129 //! The node that is constructed has a reference to the same graph object as src.
130 //! The list of predecessors, messages in the input ports, and successors are not copied.
131 //! \brief \ref interface
132 TEST_CASE("indexer_node copy constructor"){
133     oneapi::tbb::flow::graph g;
134     oneapi::tbb::flow::continue_node<int> node0( g,
135                                 [](oneapi::tbb::flow::continue_msg) { return 1; } );
136 
137     my_indexer_type node1(g);
138     conformance::test_push_receiver<my_output_type> node2(g);
139     conformance::test_push_receiver<my_output_type> node3(g);
140 
141     oneapi::tbb::flow::make_edge(node0, oneapi::tbb::flow::input_port<0>(node1));
142     oneapi::tbb::flow::make_edge(node1, node2);
143 
144     my_indexer_type node_copy(node1);
145 
146     oneapi::tbb::flow::make_edge(node_copy, node3);
147 
148     oneapi::tbb::flow::input_port<0>(node_copy).try_put(1);
149     g.wait_for_all();
150 
151     CHECK_MESSAGE((conformance::get_values(node2).size() == 0 && conformance::get_values(node3).size() == 1), "Copied node doesn`t copy successor");
152 
153     node0.try_put(oneapi::tbb::flow::continue_msg());
154     g.wait_for_all();
155 
156     CHECK_MESSAGE((conformance::get_values(node2).size() == 1 && conformance::get_values(node3).size() == 0), "Copied node doesn`t copy predecessor");
157 }
158 
159 //! Test indexer_node output_type
160 //! \brief \ref interface \ref requirement
161 TEST_CASE("indexer_node output_type") {
162     CHECK_MESSAGE((conformance::check_output_type<my_output_type, oneapi::tbb::flow::tagged_msg<size_t, int, float, input_msg>>()), "indexer_node output_type should returns a tagged_msg");
163 }
164