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_sequencer_node.cpp
33 //! \brief Test for [flow_graph.sequencer_node] specification
34 
35 /*
36 TODO: implement missing conformance tests for sequencer_node:
37   - [ ] The copy constructor and copy assignment are called for the node's type template parameter.
38   - [ ] Explicit test that `Sequencer' requirements are necessary.
39   - [ ] Write tests for the constructors.
40   - [ ] Add CTAD test.
41   - [ ] Improve `test_buffering' by checking that additional `try_get()' does not receive the same
42     value.
43   - [ ] Add explicit test on the example from the specification.
44 */
45 
46 template<typename T>
47 void test_inheritance(){
48     using namespace oneapi::tbb::flow;
49 
50     CHECK_MESSAGE( (std::is_base_of<graph_node, sequencer_node<T>>::value), "sequencer_node should be derived from graph_node");
51     CHECK_MESSAGE( (std::is_base_of<receiver<T>, sequencer_node<T>>::value), "sequencer_node should be derived from receiver<T>");
52     CHECK_MESSAGE( (std::is_base_of<sender<T>, sequencer_node<T>>::value), "sequencer_node should be derived from sender<T>");
53 }
54 
55 template<typename T>
56 struct id_sequencer{
57     using input_type = T;
58 
59     T operator()(T v){
60         return v;
61     }
62 };
63 
64 void test_copies(){
65     using namespace oneapi::tbb::flow;
66 
67     graph g;
68     id_sequencer<int> sequencer;
69 
70     sequencer_node<int> n(g, sequencer);
71     sequencer_node<int> n2(n);
72 
73 }
74 
75 void test_buffering(){
76     oneapi::tbb::flow::graph g;
77 
78     id_sequencer<int> sequencer;
79 
80     oneapi::tbb::flow::sequencer_node<int> node(g, sequencer);
81     oneapi::tbb::flow::limiter_node<int> rejecter(g, 0);
82 
83     oneapi::tbb::flow::make_edge(node, rejecter);
84     node.try_put(1);
85     g.wait_for_all();
86 
87     int tmp = -1;
88     CHECK_MESSAGE( (node.try_get(tmp) == false), "try_get after rejection should not succeed");
89     CHECK_MESSAGE( (tmp == -1), "try_get after rejection should not set value");
90 }
91 
92 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
93 void test_deduction_guides(){
94     // oneapi::tbb::flow::graph g;
95     // id_sequencer<int> sequ;
96     // oneapi::tbb::flow::sequencer_node node1(g, sequ);
97 }
98 #endif
99 
100 void test_forwarding(){
101     oneapi::tbb::flow::graph g;
102     id_sequencer<int> sequencer;
103 
104     oneapi::tbb::flow::sequencer_node<int> node1(g, sequencer);
105     test_push_receiver<int> node2(g);
106     test_push_receiver<int> node3(g);
107 
108     oneapi::tbb::flow::make_edge(node1, node2);
109     oneapi::tbb::flow::make_edge(node1, node3);
110 
111     node1.try_put(0);
112 
113     g.wait_for_all();
114 
115     int c2 = get_count(node2), c3 = get_count(node3);
116     CHECK_MESSAGE( (c2 != c3 ), "Only one descendant the node needs to receive");
117     CHECK_MESSAGE( (c2 + c3 == 1 ), "Messages need to be received");
118 }
119 
120 void test_sequencer(){
121     oneapi::tbb::flow::graph g;
122     id_sequencer<int> sequencer;
123 
124     oneapi::tbb::flow::sequencer_node<int> node(g, sequencer);
125 
126     node.try_put(1);
127     node.try_put(0);
128     node.try_put(1);
129     g.wait_for_all();
130 
131     int tmp = -1;
132     CHECK_MESSAGE((node.try_get(tmp) == true), "Getting from sequencer should succeed");
133     CHECK_MESSAGE((tmp == 0), "Received value should be correct");
134 
135     tmp = -1;
136     CHECK_MESSAGE((node.try_get(tmp) == true), "Getting from sequencer should succeed");
137     CHECK_MESSAGE((tmp == 1), "Received value should be correct");
138 
139     tmp = -1;
140     CHECK_MESSAGE((node.try_get(tmp) == false), "Getting from sequencer should not succeed");
141 
142 }
143 
144 //! Test function_node buffering
145 //! \brief \ref requirement
146 TEST_CASE("sequencer_node buffering"){
147     test_sequencer();
148 }
149 
150 //! Test function_node buffering
151 //! \brief \ref requirement
152 TEST_CASE("sequencer_node buffering"){
153     test_forwarding();
154 }
155 
156 //! Test deduction guides
157 //! \brief \ref interface \ref requirement
158 TEST_CASE("Deduction guides"){
159 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
160     test_deduction_guides();
161 #endif
162 }
163 
164 //! Test priority_queue_node buffering
165 //! \brief \ref requirement
166 TEST_CASE("sequencer_node buffering"){
167     test_buffering();
168 }
169 
170 //! Test copy constructor
171 //! \brief \ref interface
172 TEST_CASE("sequencer_node copy constructor"){
173     test_copies();
174 }
175 
176 //! Test inheritance relations
177 //! \brief \ref interface
178 TEST_CASE("sequencer_node superclasses"){
179     test_inheritance<int>();
180     test_inheritance<void*>();
181 }
182 
183