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 #define CONFORMANCE_MULTIFUNCTION_NODE
22 
23 #include "conformance_flowgraph.h"
24 
25 //! \file conformance_multifunction_node.cpp
26 //! \brief Test for [flow_graph.function_node] specification
27 
28 using input_msg = conformance::message</*default_ctor*/true, /*copy_ctor*/true, /*copy_assign*/false>;
29 using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/false, /*copy_assign*/false>;
30 
31 /*
32     Test function_node is a graph_node, receiver<Input>, and sender<Output>
33 */
34 template<typename I, typename O>
35 void test_inheritance(){
36     using namespace oneapi::tbb::flow;
37 
38     CHECK_MESSAGE((std::is_base_of<graph_node, multifunction_node<I, O>>::value), "multifunction_node should be derived from graph_node");
39     CHECK_MESSAGE((std::is_base_of<receiver<I>, multifunction_node<I, O>>::value), "multifunction_node should be derived from receiver<Input>");
40 }
41 
42 //! Test node reject the incoming message if the concurrency limit achieved.
43 //! \brief \ref interface
44 TEST_CASE("multifunction_node with rejecting policy"){
45     conformance::test_rejecting<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>, oneapi::tbb::flow::rejecting>>();
46 }
47 
48 //! Test nodes for execution with priority in single-threaded configuration
49 //! \brief \ref interface
50 TEST_CASE("multifunction_node priority"){
51     conformance::test_priority<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<int>>, input_msg>(oneapi::tbb::flow::unlimited);
52 }
53 
54 //! Test function_node has a user-settable concurrency limit. It can be set to one of predefined values.
55 //! The user can also provide a value of type std::size_t to limit concurrency.
56 //! Test that not more than limited threads works in parallel.
57 //! \brief \ref interface
58 TEST_CASE("multifunction_node concurrency"){
59     conformance::test_concurrency<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>>();
60 }
61 
62 //! Test all node constructors
63 //! \brief \ref interface
64 TEST_CASE("multifunction_node constructors"){
65     using namespace oneapi::tbb::flow;
66     graph g;
67 
68     conformance::counting_functor<int> fun;
69 
70     multifunction_node<int, std::tuple<int>> fn1(g, unlimited, fun);
71     multifunction_node<int, std::tuple<int>> fn2(g, unlimited, fun, oneapi::tbb::flow::node_priority_t(1));
72 
73     multifunction_node<int, std::tuple<int>, lightweight> lw_node1(g, serial, fun, lightweight());
74     multifunction_node<int, std::tuple<int>, lightweight> lw_node2(g, serial, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
75 }
76 
77 //! The node that is constructed has a reference to the same graph object as src, has a copy of the initial body used by src, and has the same concurrency threshold as src.
78 //! The predecessors and successors of src are not copied.
79 //! \brief \ref interface
80 TEST_CASE("multifunction_node copy constructor"){
81     conformance::test_copy_ctor<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>>();
82 }
83 
84 //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
85 //! \brief \ref requirement
86 TEST_CASE("multifunction_node buffering"){
87     conformance::dummy_functor<int> fun;
88     conformance::test_buffering<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<int>,
89     oneapi::tbb::flow::rejecting>, input_msg>(oneapi::tbb::flow::unlimited, fun);
90 }
91 
92 //! Test multifunction_node broadcasting
93 //! \brief \ref requirement
94 TEST_CASE("multifunction_node broadcast"){
95     conformance::counting_functor<int> fun(conformance::expected);
96     conformance::test_forwarding<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<int>>, input_msg, int>(1, oneapi::tbb::flow::unlimited, fun);
97 }
98 
99 //! Test the body object passed to a node is copied
100 //! \brief \ref interface
101 TEST_CASE("multifunction_node copy body"){
102     conformance::test_copy_body_function<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>, conformance::copy_counting_object<int>>(oneapi::tbb::flow::unlimited);
103 }
104 
105 //! Test execution of node body
106 //! Test node can do try_put call
107 //! \brief \ref interface \ref requirement
108 TEST_CASE("multifunction_node body") {
109     conformance::test_body_exec<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<output_msg>, oneapi::tbb::flow::rejecting>, input_msg, output_msg>(oneapi::tbb::flow::unlimited);
110 }
111 
112 //! Test multifunction_node output_ports() returns a tuple of output ports.
113 //! \brief \ref interface \ref requirement
114 TEST_CASE("multifunction_node output_ports") {
115     using namespace oneapi::tbb::flow;
116     graph g;
117     conformance::dummy_functor<int> fun;
118     oneapi::tbb::flow::multifunction_node <int, std::tuple<int>> node(g, unlimited, fun);
119 
120     CHECK_MESSAGE((std::is_same<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>::output_ports_type&,
121         decltype(node.output_ports())>::value), "multifunction_node output_ports should returns a tuple of output ports");
122 }
123 
124 //! Test inheritance relations
125 //! \brief \ref interface
126 TEST_CASE("multifunction_node superclasses"){
127     test_inheritance<int, std::tuple<int>>();
128     test_inheritance<void*, std::tuple<float>>();
129     test_inheritance<input_msg, std::tuple<output_msg>>();
130 }
131 
132 //! Test node Input class meet the DefaultConstructible and CopyConstructible requirements and Output class meet the CopyConstructible requirements.
133 //! \brief \ref interface \ref requirement
134 TEST_CASE("Test function_node Output and Input class") {
135     using Body = conformance::copy_counting_object<int>;
136     conformance::test_output_input_class<oneapi::tbb::flow::multifunction_node<Body, std::tuple<Body>>, Body>();
137 }
138