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// STL
34#include <algorithm>
35#include <vector>
36#include <set>
37
38#include <boost/test/detail/suppress_warnings.hpp>
39
40//____________________________________________________________________________//
41
42namespace boost {
43namespace unit_test {
44
45// ************************************************************************** //
46// ************** test_unit ************** //
47// ************************************************************************** //
48
49test_unit::test_unit( const_string name, const_string file_name, std::size_t line_num, test_unit_type t )
50: p_type( t )
51, p_type_name( t == TUT_CASE ? "case" : "suite" )
52, p_file_name( file_name )
53, p_line_num( line_num )
54, p_id( INV_TEST_UNIT_ID )
55, p_parent_id( INV_TEST_UNIT_ID )
56, p_name( std::string( name.begin(), name.size() ) )
57, p_timeout( 0 )
58, p_expected_failures( 0 )
59, p_default_status( RS_INHERIT )
60, p_run_status( RS_INVALID )
61, p_sibling_rank(0)
62{
63}
64
65//____________________________________________________________________________//
66
67test_unit::test_unit( const_string module_name )
68: p_type( TUT_SUITE )
69, p_type_name( "module" )
70, p_line_num( 0 )
71, p_id( INV_TEST_UNIT_ID )
72, p_parent_id( INV_TEST_UNIT_ID )
73, p_name( std::string( module_name.begin(), module_name.size() ) )
74, p_timeout( 0 )
75, p_expected_failures( 0 )
76, p_default_status( RS_INHERIT )
77, p_run_status( RS_INVALID )
78, p_sibling_rank(0)
79{
80}
81
82//____________________________________________________________________________//
83
84test_unit::~test_unit()
85{
86 framework::deregister_test_unit( tu: this );
87}
88
89//____________________________________________________________________________//
90
91void
92test_unit::depends_on( test_unit* tu )
93{
94 BOOST_TEST_SETUP_ASSERT( p_id != framework::master_test_suite().p_id,
95 "Can't add dependency to the master test suite" );
96
97 p_dependencies.value.push_back( x: tu->p_id );
98}
99
100//____________________________________________________________________________//
101
102void
103test_unit::add_precondition( precondition_t const& pc )
104{
105 p_preconditions.value.push_back( x: pc );
106}
107
108//____________________________________________________________________________//
109
110test_tools::assertion_result
111test_unit::check_preconditions() const
112{
113 BOOST_TEST_FOREACH( test_unit_id, dep_id, p_dependencies.get() ) {
114 test_unit const& dep = framework::get( id: dep_id, t: TUT_ANY );
115
116 if( !dep.is_enabled() ) {
117 test_tools::assertion_result res(false);
118 res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" is disabled";
119 return res;
120 }
121
122 test_results const& test_rslt = unit_test::results_collector.results( id: dep_id );
123 if( !test_rslt.passed() ) {
124 test_tools::assertion_result res(false);
125 res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << (test_rslt.skipped() ? "\" was skipped":"\" has failed");
126 return res;
127 }
128
129 if( test_rslt.p_test_cases_skipped > 0 ) {
130 test_tools::assertion_result res(false);
131 res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has skipped test cases";
132 return res;
133 }
134 }
135
136 BOOST_TEST_FOREACH( precondition_t, precondition, p_preconditions.get() ) {
137 test_tools::assertion_result res = precondition( p_id );
138 if( !res ) {
139 test_tools::assertion_result res_out(false);
140 res_out.message() << "precondition failed";
141 if( !res.has_empty_message() )
142 res_out.message() << ": " << res.message();
143 return res_out;
144 }
145 }
146
147 return true;
148}
149
150//____________________________________________________________________________//
151
152void
153test_unit::increase_exp_fail( counter_t num )
154{
155 p_expected_failures.value += num;
156
157 if( p_parent_id != INV_TEST_UNIT_ID )
158 framework::get<test_suite>( id: p_parent_id ).increase_exp_fail( num );
159}
160
161//____________________________________________________________________________//
162
163std::string
164test_unit::full_name() const
165{
166 if( p_parent_id == INV_TEST_UNIT_ID || p_parent_id == framework::master_test_suite().p_id )
167 return p_name;
168
169 std::string res = framework::get<test_suite>( id: p_parent_id ).full_name();
170 res.append(s: "/");
171
172 res.append( str: p_name );
173
174 return res;
175}
176
177//____________________________________________________________________________//
178
179void
180test_unit::add_label( const_string l )
181{
182 p_labels.value.push_back( x: std::string() + l );
183}
184
185//____________________________________________________________________________//
186
187bool
188test_unit::has_label( const_string l ) const
189{
190 return std::find( first: p_labels->begin(), last: p_labels->end(), val: l ) != p_labels->end();
191}
192
193//____________________________________________________________________________//
194
195// ************************************************************************** //
196// ************** test_case ************** //
197// ************************************************************************** //
198
199test_case::test_case( const_string name, boost::function<void ()> const& test_func )
200: test_unit( name, "", 0, static_cast<test_unit_type>(type) )
201, p_test_func( test_func )
202{
203 framework::register_test_unit( tc: this );
204}
205
206//____________________________________________________________________________//
207
208test_case::test_case( const_string name, const_string file_name, std::size_t line_num, boost::function<void ()> const& test_func )
209: test_unit( name, file_name, line_num, static_cast<test_unit_type>(type) )
210, p_test_func( test_func )
211{
212 framework::register_test_unit( tc: this );
213}
214
215//____________________________________________________________________________//
216
217// ************************************************************************** //
218// ************** test_suite ************** //
219// ************************************************************************** //
220
221//____________________________________________________________________________//
222
223test_suite::test_suite( const_string name, const_string file_name, std::size_t line_num )
224: test_unit( ut_detail::normalize_test_case_name( tu_name: name ), file_name, line_num, static_cast<test_unit_type>(type) )
225{
226 framework::register_test_unit( ts: this );
227}
228
229//____________________________________________________________________________//
230
231test_suite::test_suite( const_string module_name )
232: test_unit( module_name )
233{
234 framework::register_test_unit( ts: this );
235}
236
237//____________________________________________________________________________//
238
239void
240test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout )
241{
242 tu->p_timeout.value = timeout;
243
244 m_children.push_back( x: tu->p_id );
245 tu->p_parent_id.value = p_id;
246
247 if( tu->p_expected_failures != 0 )
248 increase_exp_fail( num: tu->p_expected_failures );
249
250 if( expected_failures )
251 tu->increase_exp_fail( num: expected_failures );
252}
253
254//____________________________________________________________________________//
255
256void
257test_suite::add( test_unit_generator const& gen, unsigned timeout )
258{
259 test_unit* tu;
260 while((tu = gen.next()) != 0)
261 add( tu, expected_failures: 0, timeout );
262}
263
264//____________________________________________________________________________//
265
266void
267test_suite::add( test_unit_generator const& gen, decorator::collector_t& decorators )
268{
269 test_unit* tu;
270 while((tu = gen.next()) != 0) {
271 decorators.store_in( tu&: *tu );
272 add( tu, expected_failures: 0 );
273 }
274 decorators.reset();
275}
276
277//____________________________________________________________________________//
278
279void
280test_suite::add( boost::shared_ptr<test_unit_generator> gen_ptr, decorator::collector_t& decorators )
281{
282 std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > tmp_p(gen_ptr, decorators.get_lazy_decorators() );
283 m_generators.push_back(x: tmp_p);
284 decorators.reset();
285}
286
287//____________________________________________________________________________//
288
289void
290test_suite::generate( )
291{
292 typedef std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > element_t;
293
294 for(std::vector<element_t>::iterator it(m_generators.begin()), ite(m_generators.end());
295 it < ite;
296 ++it)
297 {
298 test_unit* tu;
299 while((tu = it->first->next()) != 0) {
300 tu->p_decorators.value.insert( position: tu->p_decorators.value.end(), first: it->second.begin(), last: it->second.end() );
301 //it->second.store_in( *tu );
302 add( tu, expected_failures: 0 );
303 }
304
305 }
306 m_generators.clear();
307
308 #if 0
309 test_unit* tu;
310 while((tu = gen.next()) != 0) {
311 decorators.store_in( *tu );
312 add( tu, 0 );
313 }
314 #endif
315}
316
317//____________________________________________________________________________//
318
319void
320test_suite::check_for_duplicate_test_cases() {
321 // check for clashing names #12597
322 std::set<std::string> names;
323 for( test_unit_id_list::const_iterator it(m_children.begin()), ite(m_children.end());
324 it < ite;
325 ++it) {
326 std::string name = framework::get(id: *it, t: TUT_ANY).p_name;
327 std::pair<std::set<std::string>::iterator, bool> ret = names.insert(x: name);
328 BOOST_TEST_SETUP_ASSERT(ret.second,
329 "test unit with name '"
330 + name
331 + std::string("' registered multiple times in the test suite '")
332 + this->p_name.value
333 + "'");
334 }
335
336 return;
337}
338
339//____________________________________________________________________________//
340
341void
342test_suite::remove( test_unit_id id )
343{
344 test_unit_id_list::iterator it = std::find( first: m_children.begin(), last: m_children.end(), val: id );
345
346 if( it != m_children.end() )
347 m_children.erase( position: it );
348}
349
350//____________________________________________________________________________//
351
352test_unit_id
353test_suite::get( const_string tu_name ) const
354{
355 BOOST_TEST_FOREACH( test_unit_id, id, m_children ) {
356 if( tu_name == framework::get( id, t: ut_detail::test_id_2_unit_type( id ) ).p_name.get() )
357 return id;
358 }
359
360 return INV_TEST_UNIT_ID;
361}
362
363//____________________________________________________________________________//
364
365// ************************************************************************** //
366// ************** master_test_suite ************** //
367// ************************************************************************** //
368
369master_test_suite_t::master_test_suite_t()
370: test_suite( "Master Test Suite" )
371, argc( 0 )
372, argv( 0 )
373{
374 p_default_status.value = RS_ENABLED;
375}
376
377// ************************************************************************** //
378// ************** traverse_test_tree ************** //
379// ************************************************************************** //
380
381void
382traverse_test_tree( test_case const& tc, test_tree_visitor& V, bool ignore_status )
383{
384 if( tc.is_enabled() || ignore_status )
385 V.visit( tc );
386}
387
388//____________________________________________________________________________//
389
390void
391traverse_test_tree( test_suite const& suite, test_tree_visitor& V, bool ignore_status )
392{
393 // skip disabled test suite unless we asked to ignore this condition
394 if( !ignore_status && !suite.is_enabled() )
395 return;
396
397 // Invoke test_suite_start callback
398 if( !V.test_suite_start( ts: suite ) )
399 return;
400
401 // Recurse into children
402 std::size_t total_children = suite.m_children.size();
403 for( std::size_t i=0; i < total_children; ) {
404 // this statement can remove the test unit from this list
405 traverse_test_tree( suite.m_children[i], V, ignore_status );
406 if( total_children > suite.m_children.size() )
407 total_children = suite.m_children.size();
408 else
409 ++i;
410 }
411
412 // Invoke test_suite_finish callback
413 V.test_suite_finish( suite );
414}
415
416//____________________________________________________________________________//
417
418void
419traverse_test_tree( test_unit_id id, test_tree_visitor& V, bool ignore_status )
420{
421 if( ut_detail::test_id_2_unit_type( id ) == TUT_CASE )
422 traverse_test_tree( tc: framework::get<test_case>( id ), V, ignore_status );
423 else
424 traverse_test_tree( suite: framework::get<test_suite>( id ), V, ignore_status );
425}
426
427//____________________________________________________________________________//
428
429// ************************************************************************** //
430// ************** object generators ************** //
431// ************************************************************************** //
432
433namespace ut_detail {
434
435std::string
436normalize_test_case_name( const_string name )
437{
438 std::string norm_name( name.begin(), name.size() );
439
440 if( name[0] == '&' )
441 norm_name = norm_name.substr( pos: 1 );
442
443 // trim spaces
444 std::size_t first_not_space = norm_name.find_first_not_of(c: ' ');
445 if( first_not_space ) {
446 norm_name.erase(pos: 0, n: first_not_space);
447 }
448
449 std::size_t last_not_space = norm_name.find_last_not_of(c: ' ');
450 if( last_not_space !=std::string::npos ) {
451 norm_name.erase(pos: last_not_space + 1);
452 }
453
454 // sanitize all chars that might be used in runtime filters
455 static const char to_replace[] = { ':', '*', '@', '+', '!', '/', ',' };
456 for(std::size_t index = 0;
457 index < sizeof(to_replace)/sizeof(to_replace[0]);
458 index++) {
459 std::replace(first: norm_name.begin(), last: norm_name.end(), old_value: to_replace[index], new_value: '_');
460 }
461
462 return norm_name;
463}
464
465//____________________________________________________________________________//
466
467// ************************************************************************** //
468// ************** auto_test_unit_registrar ************** //
469// ************************************************************************** //
470
471auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, decorator::collector_t& decorators, counter_t exp_fail )
472{
473 framework::current_auto_test_suite().add( tu: tc, expected_failures: exp_fail );
474
475 decorators.store_in( tu&: *tc );
476 decorators.reset();
477}
478
479//____________________________________________________________________________//
480
481auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_string ts_file, std::size_t ts_line, decorator::collector_t& decorators )
482{
483 test_unit_id id = framework::current_auto_test_suite().get( tu_name: ts_name );
484
485 test_suite* ts;
486
487 if( id != INV_TEST_UNIT_ID ) {
488 ts = &framework::get<test_suite>( id );
489 BOOST_ASSERT( ts->p_parent_id == framework::current_auto_test_suite().p_id );
490 }
491 else {
492 ts = new test_suite( ts_name, ts_file, ts_line );
493 framework::current_auto_test_suite().add( tu: ts );
494 }
495
496 decorators.store_in( tu&: *ts );
497 decorators.reset();
498
499 framework::current_auto_test_suite( ts );
500}
501
502//____________________________________________________________________________//
503
504auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen, decorator::collector_t& decorators )
505{
506 framework::current_auto_test_suite().add( gen: tc_gen, decorators );
507}
508
509//____________________________________________________________________________//
510
511auto_test_unit_registrar::auto_test_unit_registrar( boost::shared_ptr<test_unit_generator> tc_gen, decorator::collector_t& decorators )
512{
513 framework::current_auto_test_suite().add( gen_ptr: tc_gen, decorators );
514}
515
516
517//____________________________________________________________________________//
518
519auto_test_unit_registrar::auto_test_unit_registrar( int )
520{
521 framework::current_auto_test_suite( ts: 0, push_or_pop: false );
522}
523
524//____________________________________________________________________________//
525
526} // namespace ut_detail
527
528// ************************************************************************** //
529// ************** global_fixture ************** //
530// ************************************************************************** //
531
532global_fixture::global_fixture(): registered(false)
533{
534 framework::register_global_fixture( tuf&: *this );
535 registered = true;
536}
537
538void global_fixture::unregister_from_framework() {
539 // not accessing the framework singleton after deregistering -> release
540 // of the observer from the framework
541 if(registered) {
542 framework::deregister_global_fixture( tuf&: *this );
543 }
544 registered = false;
545}
546
547global_fixture::~global_fixture()
548{
549 this->unregister_from_framework();
550}
551
552// ************************************************************************** //
553// ************** global_configuration ************** //
554// ************************************************************************** //
555
556global_configuration::global_configuration(): registered(false)
557{
558 framework::register_observer( to&: *this );
559 registered = true;
560}
561
562void global_configuration::unregister_from_framework()
563{
564 // not accessing the framework singleton after deregistering -> release
565 // of the observer from the framework
566 if(registered) {
567 framework::deregister_observer( to&: *this );
568 }
569 registered = false;
570}
571
572global_configuration::~global_configuration()
573{
574 this->unregister_from_framework();
575}
576
577//____________________________________________________________________________//
578
579} // namespace unit_test
580} // namespace boost
581
582#include <boost/test/detail/enable_warnings.hpp>
583
584#endif // BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER
585

source code of include/boost/test/impl/test_tree.ipp