1 | /* |
2 | Copyright (c) 2005-2019 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 | #ifndef tbb_harness_test_cases_framework_H |
18 | #define tbb_harness_test_cases_framework_H |
19 | |
20 | #if defined(_MSC_VER) |
21 | #define _SCL_SECURE_NO_WARNINGS |
22 | #endif |
23 | |
24 | #undef DO_ITT_NOTIFY |
25 | |
26 | #include "harness.h" |
27 | #include "harness_assert.h" |
28 | #include "tbb/tbb_stddef.h" |
29 | |
30 | #include <cstdlib> |
31 | |
32 | #include <vector> |
33 | #include <algorithm> |
34 | #include <string> |
35 | #include <sstream> |
36 | #include <iostream> |
37 | |
38 | namespace test_framework{ |
39 | template<typename test_class> |
40 | void run_test(){ |
41 | test_class()(); |
42 | } |
43 | |
44 | #if TBB_USE_EXCEPTIONS |
45 | struct assertion_failure:std::exception{ |
46 | const char* my_filename; |
47 | int my_line; |
48 | const char* my_expression; |
49 | const char * ; |
50 | assertion_failure(const char* filename, int line, const char* expression, const char * ): |
51 | my_filename(filename), |
52 | my_line(line), |
53 | my_expression(expression), |
54 | my_comment(comment) |
55 | {} |
56 | virtual const char* what() const throw() __TBB_override { |
57 | return "test assertion failed" ; |
58 | } |
59 | }; |
60 | void throw_assertion_failure(){throw assertion_failure("" ,0,"" ,"" );} |
61 | void throw_assertion_failure(const char* filename, int line, const char* expression, const char * ){ |
62 | throw assertion_failure(filename, line, expression, comment); |
63 | } |
64 | #endif // TBB_USE_EXCEPTIONS |
65 | |
66 | class test_suite{ |
67 | typedef void(*run_test_function_pointer_type)(); |
68 | typedef std::pair<std::string, run_test_function_pointer_type> tc_record_pair; |
69 | std::vector<tc_record_pair > test_cases; |
70 | public: |
71 | template<class test_class> |
72 | void register_test_case(std::string const& name, test_class * ){ |
73 | test_cases.push_back(tc_record_pair(name,& run_test<test_class>)); |
74 | } |
75 | std::string operator()(bool silent=false){ |
76 | std::stringstream str; |
77 | size_t failed=0; |
78 | for (size_t i=0;i<test_cases.size();++i){ |
79 | #if TBB_USE_EXCEPTIONS |
80 | try{ |
81 | (test_cases[i].second)(); |
82 | }catch(std::exception& e){ |
83 | failed++; |
84 | str<<"test case \"" <<test_cases[i].first<<"\" failed with exception. what():\"" <<e.what()<<"\"" <<std::endl; |
85 | } |
86 | #else |
87 | (test_cases[i].second)(); |
88 | #endif |
89 | } |
90 | if (!silent) { |
91 | str<<test_cases.size()<<" test cases are run; " <<failed<<" failed" <<std::endl; |
92 | } |
93 | return str.str(); |
94 | } |
95 | }; |
96 | test_suite& get_suite_ref(){static test_suite ts; return ts;} |
97 | void run_all_and_print_results(test_suite& ts,std::ostream& o , bool silent=false){ |
98 | o<<ts(silent); |
99 | } |
100 | } |
101 | using test_framework::get_suite_ref; |
102 | #define TEST_CASE_WITH_FIXTURE(TC_NAME,FIXTURE_NAME) \ |
103 | struct TC_NAME; \ |
104 | struct TC_NAME:FIXTURE_NAME { \ |
105 | /* explicitly implemented default constructor \ |
106 | is need here to please gcc 4.3.2*/ \ |
107 | TC_NAME(){} \ |
108 | void operator()(); \ |
109 | }; \ |
110 | bool TC_NAME##_registerd = (get_suite_ref().register_test_case(#TC_NAME,static_cast<TC_NAME*>(0)),true);\ |
111 | void TC_NAME::operator()() |
112 | |
113 | namespace test_framework_unit_tests{ |
114 | namespace test_helper{ |
115 | template <size_t id> struct tag{}; |
116 | template<typename tag> |
117 | struct test_case{ |
118 | static bool is_run; |
119 | void operator()(){ |
120 | is_run=true; |
121 | } |
122 | }; |
123 | template<typename tag> bool test_case<tag>::is_run = false; |
124 | |
125 | } |
126 | using namespace test_framework; |
127 | namespace test_test_suite_ref{ |
128 | void run_all_runs_all_registered_test_cases(){ |
129 | test_suite s; |
130 | using test_helper::tag; |
131 | test_helper::test_case<tag<__LINE__> > tc1; |
132 | test_helper::test_case<tag<__LINE__> > tc2; |
133 | s.register_test_case("tc1" ,&tc1); |
134 | s.register_test_case("tc2" ,&tc2); |
135 | s(); |
136 | ASSERT(tc1.is_run && tc2.is_run,"test_suite::operator() should run all the tests" ); |
137 | } |
138 | |
139 | struct silent_switch_fixture{ |
140 | test_helper::test_case<test_helper::tag<__LINE__> > empty_test_case; |
141 | }; |
142 | struct run_all_and_print_results_should_respect_silent_mode: silent_switch_fixture{ |
143 | void operator()(){ |
144 | using test_helper::tag; |
145 | test_helper::test_case<tag<__LINE__> > do_nothing_tc; |
146 | test_suite ts; |
147 | ts.register_test_case("tc_name" ,&do_nothing_tc); |
148 | bool silent =true; |
149 | ASSERT(ts(silent).empty(),"in silent mode no message except error should be output" ); |
150 | } |
151 | }; |
152 | struct run_all_and_print_results_should_respect_verbose_mode: silent_switch_fixture{ |
153 | void operator()(){ |
154 | using test_helper::tag; |
155 | test_helper::test_case<tag<__LINE__> > do_nothing_tc; |
156 | test_suite ts; |
157 | ts.register_test_case("tc_name" ,&do_nothing_tc); |
158 | bool silent =true; |
159 | ASSERT(!ts(!silent).empty(),"in verbose mode all messages should be outputted" ); |
160 | } |
161 | }; |
162 | } |
163 | namespace test_test_case_macro{ |
164 | test_suite& get_suite_ref(){static test_suite ts; return ts;} |
165 | typedef test_helper::test_case<test_helper::tag<__LINE__> > unique_test_type; |
166 | TEST_CASE_WITH_FIXTURE(test_auto_registration,unique_test_type){ |
167 | unique_test_type::operator()(); |
168 | } |
169 | void run_test_test_case_macro(){ |
170 | get_suite_ref()(); |
171 | ASSERT(unique_test_type::is_run,"test case macro should register the test case in suite" ); |
172 | } |
173 | void test_test_case_macro_does_not_create_test_case_object(){ |
174 | ASSERT(false,"to implement" ); |
175 | } |
176 | } |
177 | namespace internal_assertions_failure_test_cases{ |
178 | |
179 | test_suite& get_suite_ref(){static test_suite ts; return ts;} |
180 | |
181 | //TODO: investigate compilation errors regarding tbb::set_assertion_handler |
182 | // struct empty_fixture{}; |
183 | // TEST_CASE_WITH_FIXTURE(test_internal_assertion_does_not_stop_test_suite,empty_fixture){ |
184 | // struct handler{ |
185 | // static void _( const char* /*filename*/, int /*line*/, const char* /*expression*/, const char * /*comment*/ ){ |
186 | // } |
187 | // }; |
188 | // |
189 | // tbb::assertion_handler_type previous = tbb::set_assertion_handler(handler::_); |
190 | // __TBB_ASSERT(false,"this assert should not stop the test suite run"); |
191 | // tbb::set_assertion_handler(previous ); |
192 | //// ASSERT(assertion_handler::is_called,"__TBB_ASSERT should call installed assertion handler"); |
193 | // } |
194 | // TEST_CASE_WITH_FIXTURE(test_internal_assertion_does_mark_the_test_as_failed,empty_fixture){ |
195 | // test_suite ts; |
196 | // struct _{ |
197 | //// static |
198 | // static void assertion_handler_type( const char* /*filename*/, int /*line*/, const char* /*expression*/, const char * /*comment*/ ){ |
199 | // } |
200 | // }; |
201 | // tbb::assertion_handler_type previous = tbb::set_assertion_handler(_::assertion_handler_type); |
202 | // __TBB_ASSERT(false,"this assert should not stop the test suite run"); |
203 | // tbb::set_assertion_handler(previous ); |
204 | // std::string result = ts(); |
205 | // std::size_t test_case_name_begin_pos = result.find("test case \""); |
206 | // std::size_t failed_begin_pos = result.find("failed"); |
207 | // ASSERT(test_case_name_begin_pos!=std::string::npos && failed_begin_pos!=std::string::npos && test_case_name_begin_pos<failed_begin_pos,"internal assertion should result in test failure"); |
208 | // } |
209 | |
210 | } |
211 | void run_all_test(){ |
212 | test_test_suite_ref::run_all_runs_all_registered_test_cases(); |
213 | test_test_suite_ref::run_all_and_print_results_should_respect_silent_mode()(); |
214 | test_test_suite_ref::run_all_and_print_results_should_respect_verbose_mode()(); |
215 | test_test_case_macro::run_test_test_case_macro(); |
216 | //TODO: uncomment and implement |
217 | // test_test_case_macro::test_test_case_macro_does_not_create_test_case_object(); |
218 | run_all_and_print_results(internal_assertions_failure_test_cases::get_suite_ref(),std::cout,!Verbose); |
219 | } |
220 | } |
221 | |
222 | int TestMain (){ |
223 | #if TBB_USE_EXCEPTIONS |
224 | SetHarnessErrorProcessing(test_framework::throw_assertion_failure); |
225 | //TODO: deal with assertions during stack unwinding |
226 | //tbb::set_assertion_handler( test_framework::throw_assertion_failure ); |
227 | #endif |
228 | { |
229 | test_framework_unit_tests::run_all_test(); |
230 | } |
231 | bool silent = !Verbose; |
232 | run_all_and_print_results(test_framework::get_suite_ref(),std::cout,silent); |
233 | return Harness::Done; |
234 | } |
235 | |
236 | #endif //tbb_harness_test_cases_framework_H |
237 | |