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