1 | // (C) Copyright Gennadiy Rozental 2001. |
2 | // Distributed under the Boost Software License, Version 1.0. |
3 | // (See accompanying file LICENSE_1_0.txt or copy at |
4 | // http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | // See http://www.boost.org/libs/test for the library home page. |
7 | // |
8 | /// @file |
9 | /// Provides core implementation for Unit Test Framework. |
10 | /// Extensions can be provided in separate files |
11 | // *************************************************************************** |
12 | |
13 | #ifndef BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER |
14 | #define BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER |
15 | |
16 | // Boost.Test |
17 | #include <boost/detail/workaround.hpp> |
18 | |
19 | #include <boost/test/framework.hpp> |
20 | #include <boost/test/results_collector.hpp> |
21 | |
22 | #include <boost/test/tree/test_unit.hpp> |
23 | #include <boost/test/tree/visitor.hpp> |
24 | #include <boost/test/tree/traverse.hpp> |
25 | #include <boost/test/tree/auto_registration.hpp> |
26 | #include <boost/test/tree/global_fixture.hpp> |
27 | |
28 | #include <boost/test/utils/foreach.hpp> |
29 | #include <boost/test/utils/basic_cstring/io.hpp> |
30 | |
31 | #include <boost/test/unit_test_parameters.hpp> |
32 | |
33 | // Boost |
34 | #include <boost/timer.hpp> |
35 | |
36 | // STL |
37 | #include <algorithm> |
38 | #include <vector> |
39 | |
40 | #include <boost/test/detail/suppress_warnings.hpp> |
41 | |
42 | //____________________________________________________________________________// |
43 | |
44 | namespace boost { |
45 | namespace unit_test { |
46 | |
47 | // ************************************************************************** // |
48 | // ************** test_unit ************** // |
49 | // ************************************************************************** // |
50 | |
51 | test_unit::test_unit( const_string name, const_string file_name, std::size_t line_num, test_unit_type t ) |
52 | : p_type( t ) |
53 | , p_type_name( t == TUT_CASE ? "case" : "suite" ) |
54 | , p_file_name( file_name ) |
55 | , p_line_num( line_num ) |
56 | , p_id( INV_TEST_UNIT_ID ) |
57 | , p_parent_id( INV_TEST_UNIT_ID ) |
58 | , p_name( std::string( name.begin(), name.size() ) ) |
59 | , p_timeout( 0 ) |
60 | , p_expected_failures( 0 ) |
61 | , p_default_status( RS_INHERIT ) |
62 | , p_run_status( RS_INVALID ) |
63 | , p_sibling_rank(0) |
64 | { |
65 | } |
66 | |
67 | //____________________________________________________________________________// |
68 | |
69 | test_unit::test_unit( const_string module_name ) |
70 | : p_type( TUT_SUITE ) |
71 | , p_type_name( "module" ) |
72 | , p_line_num( 0 ) |
73 | , p_id( INV_TEST_UNIT_ID ) |
74 | , p_parent_id( INV_TEST_UNIT_ID ) |
75 | , p_name( std::string( module_name.begin(), module_name.size() ) ) |
76 | , p_timeout( 0 ) |
77 | , p_expected_failures( 0 ) |
78 | , p_default_status( RS_INHERIT ) |
79 | , p_run_status( RS_INVALID ) |
80 | , p_sibling_rank(0) |
81 | { |
82 | } |
83 | |
84 | //____________________________________________________________________________// |
85 | |
86 | test_unit::~test_unit() |
87 | { |
88 | framework::deregister_test_unit( tu: this ); |
89 | } |
90 | |
91 | //____________________________________________________________________________// |
92 | |
93 | void |
94 | test_unit::depends_on( test_unit* tu ) |
95 | { |
96 | BOOST_TEST_SETUP_ASSERT( p_id != framework::master_test_suite().p_id, |
97 | "Can't add dependency to the master test suite" ); |
98 | |
99 | p_dependencies.value.push_back( x: tu->p_id ); |
100 | } |
101 | |
102 | //____________________________________________________________________________// |
103 | |
104 | void |
105 | test_unit::add_precondition( precondition_t const& pc ) |
106 | { |
107 | p_preconditions.value.push_back( x: pc ); |
108 | } |
109 | |
110 | //____________________________________________________________________________// |
111 | |
112 | test_tools::assertion_result |
113 | test_unit::check_preconditions() const |
114 | { |
115 | BOOST_TEST_FOREACH( test_unit_id, dep_id, p_dependencies.get() ) { |
116 | test_unit const& dep = framework::get( id: dep_id, t: TUT_ANY ); |
117 | |
118 | if( !dep.is_enabled() ) { |
119 | test_tools::assertion_result res(false); |
120 | res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" is disabled" ; |
121 | return res; |
122 | } |
123 | |
124 | test_results const& test_rslt = unit_test::results_collector.results( id: dep_id ); |
125 | if( !test_rslt.passed() ) { |
126 | test_tools::assertion_result res(false); |
127 | res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has failed" ; |
128 | return res; |
129 | } |
130 | |
131 | if( test_rslt.p_test_cases_skipped > 0 ) { |
132 | test_tools::assertion_result res(false); |
133 | res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has skipped test cases" ; |
134 | return res; |
135 | } |
136 | } |
137 | |
138 | BOOST_TEST_FOREACH( precondition_t, precondition, p_preconditions.get() ) { |
139 | test_tools::assertion_result res = precondition( p_id ); |
140 | if( !res ) { |
141 | test_tools::assertion_result res_out(false); |
142 | res_out.message() << "precondition failed" ; |
143 | if( !res.has_empty_message() ) |
144 | res_out.message() << ": " << res.message(); |
145 | return res_out; |
146 | } |
147 | } |
148 | |
149 | return true; |
150 | } |
151 | |
152 | //____________________________________________________________________________// |
153 | |
154 | void |
155 | test_unit::increase_exp_fail( counter_t num ) |
156 | { |
157 | p_expected_failures.value += num; |
158 | |
159 | if( p_parent_id != INV_TEST_UNIT_ID ) |
160 | framework::get<test_suite>( id: p_parent_id ).increase_exp_fail( num ); |
161 | } |
162 | |
163 | //____________________________________________________________________________// |
164 | |
165 | std::string |
166 | test_unit::full_name() const |
167 | { |
168 | if( p_parent_id == INV_TEST_UNIT_ID || p_parent_id == framework::master_test_suite().p_id ) |
169 | return p_name; |
170 | |
171 | std::string res = framework::get<test_suite>( id: p_parent_id ).full_name(); |
172 | res.append(s: "/" ); |
173 | |
174 | res.append( str: p_name ); |
175 | |
176 | return res; |
177 | } |
178 | |
179 | //____________________________________________________________________________// |
180 | |
181 | void |
182 | test_unit::add_label( const_string l ) |
183 | { |
184 | p_labels.value.push_back( x: std::string() + l ); |
185 | } |
186 | |
187 | //____________________________________________________________________________// |
188 | |
189 | bool |
190 | test_unit::has_label( const_string l ) const |
191 | { |
192 | return std::find( first: p_labels->begin(), last: p_labels->end(), val: l ) != p_labels->end(); |
193 | } |
194 | |
195 | //____________________________________________________________________________// |
196 | |
197 | // ************************************************************************** // |
198 | // ************** test_case ************** // |
199 | // ************************************************************************** // |
200 | |
201 | test_case::test_case( const_string name, boost::function<void ()> const& test_func ) |
202 | : test_unit( name, "" , 0, static_cast<test_unit_type>(type) ) |
203 | , p_test_func( test_func ) |
204 | { |
205 | framework::register_test_unit( tc: this ); |
206 | } |
207 | |
208 | //____________________________________________________________________________// |
209 | |
210 | test_case::test_case( const_string name, const_string file_name, std::size_t line_num, boost::function<void ()> const& test_func ) |
211 | : test_unit( name, file_name, line_num, static_cast<test_unit_type>(type) ) |
212 | , p_test_func( test_func ) |
213 | { |
214 | framework::register_test_unit( tc: this ); |
215 | } |
216 | |
217 | //____________________________________________________________________________// |
218 | |
219 | // ************************************************************************** // |
220 | // ************** test_suite ************** // |
221 | // ************************************************************************** // |
222 | |
223 | //____________________________________________________________________________// |
224 | |
225 | test_suite::test_suite( const_string name, const_string file_name, std::size_t line_num ) |
226 | : test_unit( name, file_name, line_num, static_cast<test_unit_type>(type) ) |
227 | { |
228 | framework::register_test_unit( ts: this ); |
229 | } |
230 | |
231 | //____________________________________________________________________________// |
232 | |
233 | test_suite::test_suite( const_string module_name ) |
234 | : test_unit( module_name ) |
235 | { |
236 | framework::register_test_unit( ts: this ); |
237 | } |
238 | |
239 | //____________________________________________________________________________// |
240 | |
241 | void |
242 | test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout ) |
243 | { |
244 | tu->p_timeout.value = timeout; |
245 | |
246 | m_children.push_back( x: tu->p_id ); |
247 | tu->p_parent_id.value = p_id; |
248 | |
249 | if( tu->p_expected_failures != 0 ) |
250 | increase_exp_fail( num: tu->p_expected_failures ); |
251 | |
252 | if( expected_failures ) |
253 | tu->increase_exp_fail( num: expected_failures ); |
254 | } |
255 | |
256 | //____________________________________________________________________________// |
257 | |
258 | void |
259 | test_suite::add( test_unit_generator const& gen, unsigned timeout ) |
260 | { |
261 | test_unit* tu; |
262 | while((tu = gen.next()) != 0) |
263 | add( tu, expected_failures: 0, timeout ); |
264 | } |
265 | |
266 | //____________________________________________________________________________// |
267 | |
268 | void |
269 | test_suite::add( test_unit_generator const& gen, decorator::collector& decorators ) |
270 | { |
271 | test_unit* tu; |
272 | while((tu = gen.next()) != 0) { |
273 | decorators.store_in( tu&: *tu ); |
274 | add( tu, expected_failures: 0 ); |
275 | } |
276 | |
277 | decorators.reset(); |
278 | } |
279 | |
280 | //____________________________________________________________________________// |
281 | |
282 | void |
283 | test_suite::remove( test_unit_id id ) |
284 | { |
285 | test_unit_id_list::iterator it = std::find( first: m_children.begin(), last: m_children.end(), val: id ); |
286 | |
287 | if( it != m_children.end() ) |
288 | m_children.erase( position: it ); |
289 | } |
290 | |
291 | //____________________________________________________________________________// |
292 | |
293 | test_unit_id |
294 | test_suite::get( const_string tu_name ) const |
295 | { |
296 | BOOST_TEST_FOREACH( test_unit_id, id, m_children ) { |
297 | if( tu_name == framework::get( id, t: ut_detail::test_id_2_unit_type( id ) ).p_name.get() ) |
298 | return id; |
299 | } |
300 | |
301 | return INV_TEST_UNIT_ID; |
302 | } |
303 | |
304 | //____________________________________________________________________________// |
305 | |
306 | // ************************************************************************** // |
307 | // ************** master_test_suite ************** // |
308 | // ************************************************************************** // |
309 | |
310 | master_test_suite_t::master_test_suite_t() |
311 | : test_suite( "Master Test Suite" ) |
312 | , argc( 0 ) |
313 | , argv( 0 ) |
314 | { |
315 | p_default_status.value = RS_ENABLED; |
316 | } |
317 | |
318 | // ************************************************************************** // |
319 | // ************** traverse_test_tree ************** // |
320 | // ************************************************************************** // |
321 | |
322 | void |
323 | traverse_test_tree( test_case const& tc, test_tree_visitor& V, bool ignore_status ) |
324 | { |
325 | if( tc.is_enabled() || ignore_status ) |
326 | V.visit( tc ); |
327 | } |
328 | |
329 | //____________________________________________________________________________// |
330 | |
331 | void |
332 | traverse_test_tree( test_suite const& suite, test_tree_visitor& V, bool ignore_status ) |
333 | { |
334 | // skip disabled test suite unless we asked to ignore this condition |
335 | if( !ignore_status && !suite.is_enabled() ) |
336 | return; |
337 | |
338 | // Invoke test_suite_start callback |
339 | if( !V.test_suite_start( ts: suite ) ) |
340 | return; |
341 | |
342 | // Recurse into children |
343 | std::size_t total_children = suite.m_children.size(); |
344 | for( std::size_t i=0; i < total_children; ) { |
345 | // this statement can remove the test unit from this list |
346 | traverse_test_tree( suite.m_children[i], V, ignore_status ); |
347 | if( total_children > suite.m_children.size() ) |
348 | total_children = suite.m_children.size(); |
349 | else |
350 | ++i; |
351 | } |
352 | |
353 | // Invoke test_suite_finish callback |
354 | V.test_suite_finish( suite ); |
355 | } |
356 | |
357 | //____________________________________________________________________________// |
358 | |
359 | void |
360 | traverse_test_tree( test_unit_id id, test_tree_visitor& V, bool ignore_status ) |
361 | { |
362 | if( ut_detail::test_id_2_unit_type( id ) == TUT_CASE ) |
363 | traverse_test_tree( tc: framework::get<test_case>( id ), V, ignore_status ); |
364 | else |
365 | traverse_test_tree( suite: framework::get<test_suite>( id ), V, ignore_status ); |
366 | } |
367 | |
368 | //____________________________________________________________________________// |
369 | |
370 | // ************************************************************************** // |
371 | // ************** object generators ************** // |
372 | // ************************************************************************** // |
373 | |
374 | namespace ut_detail { |
375 | |
376 | std::string |
377 | normalize_test_case_name( const_string name ) |
378 | { |
379 | std::string norm_name( name.begin(), name.size() ); |
380 | |
381 | if( name[0] == '&' ) |
382 | norm_name = norm_name.substr( pos: 1 ); |
383 | |
384 | std::replace(first: norm_name.begin(), last: norm_name.end(), old_value: ' ', new_value: '_'); |
385 | |
386 | return norm_name; |
387 | } |
388 | |
389 | //____________________________________________________________________________// |
390 | |
391 | // ************************************************************************** // |
392 | // ************** auto_test_unit_registrar ************** // |
393 | // ************************************************************************** // |
394 | |
395 | auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, decorator::collector& decorators, counter_t exp_fail ) |
396 | { |
397 | framework::current_auto_test_suite().add( tu: tc, expected_failures: exp_fail ); |
398 | |
399 | decorators.store_in( tu&: *tc ); |
400 | decorators.reset(); |
401 | } |
402 | |
403 | //____________________________________________________________________________// |
404 | |
405 | auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_string ts_file, std::size_t ts_line, decorator::collector& decorators ) |
406 | { |
407 | test_unit_id id = framework::current_auto_test_suite().get( tu_name: ts_name ); |
408 | |
409 | test_suite* ts; |
410 | |
411 | if( id != INV_TEST_UNIT_ID ) { |
412 | ts = &framework::get<test_suite>( id ); |
413 | BOOST_ASSERT( ts->p_parent_id == framework::current_auto_test_suite().p_id ); |
414 | } |
415 | else { |
416 | ts = new test_suite( ts_name, ts_file, ts_line ); |
417 | framework::current_auto_test_suite().add( tu: ts ); |
418 | } |
419 | |
420 | decorators.store_in( tu&: *ts ); |
421 | decorators.reset(); |
422 | |
423 | framework::current_auto_test_suite( ts ); |
424 | } |
425 | |
426 | //____________________________________________________________________________// |
427 | |
428 | auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen, decorator::collector& decorators ) |
429 | { |
430 | framework::current_auto_test_suite().add( gen: tc_gen, decorators ); |
431 | } |
432 | |
433 | //____________________________________________________________________________// |
434 | |
435 | auto_test_unit_registrar::auto_test_unit_registrar( int ) |
436 | { |
437 | framework::current_auto_test_suite( ts: 0, push_or_pop: false ); |
438 | } |
439 | |
440 | //____________________________________________________________________________// |
441 | |
442 | } // namespace ut_detail |
443 | |
444 | // ************************************************************************** // |
445 | // ************** global_fixture ************** // |
446 | // ************************************************************************** // |
447 | |
448 | global_fixture::global_fixture() |
449 | { |
450 | framework::register_observer( to&: *this ); |
451 | } |
452 | |
453 | //____________________________________________________________________________// |
454 | |
455 | } // namespace unit_test |
456 | } // namespace boost |
457 | |
458 | #include <boost/test/detail/enable_warnings.hpp> |
459 | |
460 | #endif // BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER |
461 | |