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
38namespace 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 * my_comment;
50 assertion_failure(const char* filename, int line, const char* expression, const char * comment):
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 * comment){
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}
101using 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
113namespace 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
222int 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