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 //! \file conformance_indexer_node.cpp
31 //! \brief Test for [flow_graph.indexer_node] specification
32 
33 /*
34 TODO: implement missing conformance tests for buffer_node:
35   - [ ] The copy constructor is called for the node's type template parameter.
36   - [ ] Improve `test_forwarding' by checking that the value passed is the actual one received.
37   - [ ] Improve `test_buffering' by checking that additional `try_get()' does not receive the same value.
38   - [ ] Improve tests of the constructors.
39   - [ ] Based on the decision about the details for `try_put()' and `try_get()' write corresponding tests.
40   - [ ] Fix description in `TEST_CASEs'.
41 */
42 using namespace oneapi::tbb::flow;
43 using namespace std;
44 
45 template<typename I1, typename I2>
46 void test_inheritance(){
47     using namespace oneapi::tbb::flow;
48 
49     CHECK_MESSAGE( (std::is_base_of<graph_node, indexer_node<I1, I2>>::value), "indexer_node should be derived from graph_node");
50 }
51 
52 void test_copies(){
53     using namespace oneapi::tbb::flow;
54 
55     graph g;
56     indexer_node<int, int> fn(g);
57 
58     indexer_node<int, int> f2(fn);
59 }
60 
61 //! Test body copying and copy_body logic
62 //! \brief \ref interface
63 TEST_CASE("indexer_node and body copying"){
64     test_copies();
65 }
66 
67 void test_broadcasting(){
68     oneapi::tbb::flow::graph g;
69 
70     typedef indexer_node<int,float> my_indexer_type;
71     typedef my_indexer_type::output_type my_output_type;
72 
73     my_indexer_type o(g);
74 
75     my_indexer_type node1(g);
76     queue_node<my_output_type> node2(g);
77     queue_node<my_output_type> node3(g);
78 
79     oneapi::tbb::flow::make_edge(node1, node2);
80     oneapi::tbb::flow::make_edge(node1, node3);
81 
82     input_port<0>(node1).try_put(6);
83     input_port<1>(node1).try_put(1.5);
84     g.wait_for_all();
85 
86     my_output_type tmp;
87     CHECK_MESSAGE( (node2.try_get(tmp)), "Descendant of the node needs to receive message once");
88     CHECK_MESSAGE( (node3.try_get(tmp)), "Descendant of the node needs to receive message once");
89 }
90 
91 //! Test broadcasting property
92 //! \brief \ref requirement
93 TEST_CASE("indexer_node broadcasts"){
94     test_broadcasting();
95 }
96 
97 //! Test inheritance relations
98 //! \brief \ref interface
99 TEST_CASE("indexer_node superclasses"){
100     test_inheritance<int, int>();
101 }
102 
103 //! Test discarding property
104 //! \brief \ref requirement
105 TEST_CASE("indexer_node discarding") {
106   graph g;
107 
108   typedef indexer_node<int,float> my_indexer_type;
109   my_indexer_type o(g);
110 
111   limiter_node< my_indexer_type::output_type > rejecter( g,0);
112   make_edge( o, rejecter );
113 
114   input_port<0>(o).try_put(6);
115   input_port<1>(o).try_put(1.5);
116 
117   my_indexer_type::output_type tmp;
118   CHECK_MESSAGE((o.try_get(tmp) == false), "Value should be discarded after rejection");
119   g.wait_for_all();
120 }
121 
122 //! Test indexer body
123 //! \brief \ref requirement
124 TEST_CASE("indexer_node body") {
125   graph g;
126   function_node<int,int> f1( g, unlimited,
127                                [](const int &i) { return 2*i; } );
128   function_node<float,float> f2( g, unlimited,
129                                [](const float &f) { return f/2; } );
130 
131   typedef indexer_node<int,float> my_indexer_type;
132   my_indexer_type o(g);
133 
134   function_node< my_indexer_type::output_type >
135     f3( g, unlimited,
136         []( const my_indexer_type::output_type &v ) {
137             if (v.tag() == 0) {
138                 CHECK_MESSAGE( (cast_to<int>(v) == 6), "Expected to receive 6" );
139             } else {
140                 CHECK_MESSAGE( (cast_to<float>(v) == 1.5), "Expected to receive 1.5" );
141            }
142         }
143     );
144   make_edge( f1, input_port<0>(o) );
145   make_edge( f2, input_port<1>(o) );
146   make_edge( o, f3 );
147 
148   f1.try_put( 3 );
149   f2.try_put( 3 );
150   g.wait_for_all();
151 }
152