blob: 2da90c65bd20d5c2ccfaa0ed8b87f751446334c3 [file] [log] [blame]
Jeff Thompsonef2d5a42013-08-22 19:09:24 -07001// (C) Copyright Gennadiy Rozental 2005-2008.
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 : $RCSfile$
9//
10// Version : $Revision: 57991 $
11//
12// Description : implements framework API - main driver for the test
13// ***************************************************************************
14
Jeff Thompson3d613fd2013-10-15 15:39:04 -070015#ifndef NDNBOOST_TEST_FRAMEWORK_IPP_021005GER
16#define NDNBOOST_TEST_FRAMEWORK_IPP_021005GER
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070017
18// Boost.Test
19#include <ndnboost/test/framework.hpp>
20#include <ndnboost/test/execution_monitor.hpp>
21#include <ndnboost/test/debug.hpp>
22#include <ndnboost/test/unit_test_suite_impl.hpp>
23#include <ndnboost/test/unit_test_log.hpp>
24#include <ndnboost/test/unit_test_monitor.hpp>
25#include <ndnboost/test/test_observer.hpp>
26#include <ndnboost/test/results_collector.hpp>
27#include <ndnboost/test/progress_monitor.hpp>
28#include <ndnboost/test/results_reporter.hpp>
29#include <ndnboost/test/test_tools.hpp>
30
31#include <ndnboost/test/detail/unit_test_parameters.hpp>
32#include <ndnboost/test/detail/global_typedef.hpp>
33
34#include <ndnboost/test/utils/foreach.hpp>
35
36// Boost
37#include <ndnboost/timer.hpp>
38
39// STL
40#include <map>
41#include <set>
42#include <cstdlib>
43#include <ctime>
44
Jeff Thompson3d613fd2013-10-15 15:39:04 -070045#ifdef NDNBOOST_NO_STDC_NAMESPACE
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070046namespace std { using ::time; using ::srand; }
47#endif
48
49#include <ndnboost/test/detail/suppress_warnings.hpp>
50
51//____________________________________________________________________________//
52
53namespace ndnboost {
54
55namespace unit_test {
56
57// ************************************************************************** //
58// ************** test_start calls wrapper ************** //
59// ************************************************************************** //
60
61namespace ut_detail {
62
63struct test_start_caller {
64 test_start_caller( test_observer* to, counter_t tc_amount )
65 : m_to( to )
66 , m_tc_amount( tc_amount )
67 {}
68
69 int operator()()
70 {
71 m_to->test_start( m_tc_amount );
72 return 0;
73 }
74
75private:
76 // Data members
77 test_observer* m_to;
78 counter_t m_tc_amount;
79};
80
81//____________________________________________________________________________//
82
83struct test_init_caller {
84 explicit test_init_caller( init_unit_test_func init_func )
85 : m_init_func( init_func )
86 {}
87 int operator()()
88 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -070089#ifdef NDNBOOST_TEST_ALTERNATIVE_INIT_API
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070090 if( !(*m_init_func)() )
91 throw std::runtime_error( "test module initialization failed" );
92#else
93 test_suite* manual_test_units = (*m_init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv );
94
95 if( manual_test_units )
96 framework::master_test_suite().add( manual_test_units );
97#endif
98 return 0;
99 }
100
101 // Data members
102 init_unit_test_func m_init_func;
103};
104
105}
106
107// ************************************************************************** //
108// ************** framework ************** //
109// ************************************************************************** //
110
111class framework_impl : public test_tree_visitor {
112public:
113 framework_impl()
114 : m_master_test_suite( 0 )
115 , m_curr_test_case( INV_TEST_UNIT_ID )
116 , m_next_test_case_id( MIN_TEST_CASE_ID )
117 , m_next_test_suite_id( MIN_TEST_SUITE_ID )
118 , m_is_initialized( false )
119 , m_test_in_progress( false )
120 {}
121
122 ~framework_impl() { clear(); }
123
124 void clear()
125 {
126 while( !m_test_units.empty() ) {
127 test_unit_store::value_type const& tu = *m_test_units.begin();
128 test_unit* tu_ptr = tu.second;
129
130 // the delete will erase this element from map
131 if( ut_detail::test_id_2_unit_type( tu.second->p_id ) == tut_suite )
132 delete (test_suite const*)tu_ptr;
133 else
134 delete (test_case const*)tu_ptr;
135 }
136 }
137
138 void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; }
139
140 // test_tree_visitor interface implementation
141 void visit( test_case const& tc )
142 {
143 if( !tc.check_dependencies() ) {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700144 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700145 to->test_unit_skipped( tc );
146
147 return;
148 }
149
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700150 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700151 to->test_unit_start( tc );
152
153 ndnboost::timer tc_timer;
154 test_unit_id bkup = m_curr_test_case;
155 m_curr_test_case = tc.p_id;
156 unit_test_monitor_t::error_level run_result = unit_test_monitor.execute_and_translate( tc );
157
158 unsigned long elapsed = static_cast<unsigned long>( tc_timer.elapsed() * 1e6 );
159
160 if( unit_test_monitor.is_critical_error( run_result ) ) {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700161 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700162 to->test_aborted();
163 }
164
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700165 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700166 to->test_unit_finish( tc, elapsed );
167
168 m_curr_test_case = bkup;
169
170 if( unit_test_monitor.is_critical_error( run_result ) )
171 throw test_being_aborted();
172 }
173
174 bool test_suite_start( test_suite const& ts )
175 {
176 if( !ts.check_dependencies() ) {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700177 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700178 to->test_unit_skipped( ts );
179
180 return false;
181 }
182
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700183 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700184 to->test_unit_start( ts );
185
186 return true;
187 }
188
189 void test_suite_finish( test_suite const& ts )
190 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700191 NDNBOOST_TEST_FOREACH( test_observer*, to, m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700192 to->test_unit_finish( ts, 0 );
193 }
194
195 //////////////////////////////////////////////////////////////////
196 struct priority_order {
197 bool operator()( test_observer* lhs, test_observer* rhs ) const
198 {
199 return (lhs->priority() < rhs->priority()) || ((lhs->priority() == rhs->priority()) && (lhs < rhs));
200 }
201 };
202
203 typedef std::map<test_unit_id,test_unit*> test_unit_store;
204 typedef std::set<test_observer*,priority_order> observer_store;
205
206 master_test_suite_t* m_master_test_suite;
207 test_unit_id m_curr_test_case;
208 test_unit_store m_test_units;
209
210 test_unit_id m_next_test_case_id;
211 test_unit_id m_next_test_suite_id;
212
213 bool m_is_initialized;
214 bool m_test_in_progress;
215
216 observer_store m_observers;
217};
218
219//____________________________________________________________________________//
220
221namespace {
222
223#if defined(__CYGWIN__)
224framework_impl& s_frk_impl() { static framework_impl* the_inst = 0; if(!the_inst) the_inst = new framework_impl; return *the_inst; }
225#else
226framework_impl& s_frk_impl() { static framework_impl the_inst; return the_inst; }
227#endif
228
229} // local namespace
230
231//____________________________________________________________________________//
232
233namespace framework {
234
235void
236init( init_unit_test_func init_func, int argc, char* argv[] )
237{
238 runtime_config::init( argc, argv );
239
240 // set the log level and format
241 unit_test_log.set_threshold_level( runtime_config::log_level() );
242 unit_test_log.set_format( runtime_config::log_format() );
243
244 // set the report level and format
245 results_reporter::set_level( runtime_config::report_level() );
246 results_reporter::set_format( runtime_config::report_format() );
247
248 register_observer( results_collector );
249 register_observer( unit_test_log );
250
251 if( runtime_config::show_progress() )
252 register_observer( progress_monitor );
253
254 if( runtime_config::detect_memory_leaks() > 0 ) {
255 debug::detect_memory_leaks( true );
256 debug::break_memory_alloc( runtime_config::detect_memory_leaks() );
257 }
258
259 // init master unit test suite
260 master_test_suite().argc = argc;
261 master_test_suite().argv = argv;
262
263 try {
264 ndnboost::execution_monitor em;
265
266 ut_detail::test_init_caller tic( init_func );
267
268 em.execute( tic );
269 }
270 catch( execution_exception const& ex ) {
271 throw setup_error( ex.what() );
272 }
273
274 s_frk_impl().m_is_initialized = true;
275}
276
277//____________________________________________________________________________//
278
279bool
280is_initialized()
281{
282 return s_frk_impl().m_is_initialized;
283}
284
285//____________________________________________________________________________//
286
287void
288register_test_unit( test_case* tc )
289{
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700290 NDNBOOST_TEST_SETUP_ASSERT( tc->p_id == INV_TEST_UNIT_ID, NDNBOOST_TEST_L( "test case already registered" ) );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700291
292 test_unit_id new_id = s_frk_impl().m_next_test_case_id;
293
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700294 NDNBOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_CASE_ID, NDNBOOST_TEST_L( "too many test cases" ) );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700295
296 typedef framework_impl::test_unit_store::value_type map_value_type;
297
298 s_frk_impl().m_test_units.insert( map_value_type( new_id, tc ) );
299 s_frk_impl().m_next_test_case_id++;
300
301 s_frk_impl().set_tu_id( *tc, new_id );
302}
303
304//____________________________________________________________________________//
305
306void
307register_test_unit( test_suite* ts )
308{
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700309 NDNBOOST_TEST_SETUP_ASSERT( ts->p_id == INV_TEST_UNIT_ID, NDNBOOST_TEST_L( "test suite already registered" ) );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700310
311 test_unit_id new_id = s_frk_impl().m_next_test_suite_id;
312
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700313 NDNBOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_SUITE_ID, NDNBOOST_TEST_L( "too many test suites" ) );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700314
315 typedef framework_impl::test_unit_store::value_type map_value_type;
316 s_frk_impl().m_test_units.insert( map_value_type( new_id, ts ) );
317 s_frk_impl().m_next_test_suite_id++;
318
319 s_frk_impl().set_tu_id( *ts, new_id );
320}
321
322//____________________________________________________________________________//
323
324void
325deregister_test_unit( test_unit* tu )
326{
327 s_frk_impl().m_test_units.erase( tu->p_id );
328}
329
330//____________________________________________________________________________//
331
332void
333clear()
334{
335 s_frk_impl().clear();
336}
337
338//____________________________________________________________________________//
339
340void
341register_observer( test_observer& to )
342{
343 s_frk_impl().m_observers.insert( &to );
344}
345
346//____________________________________________________________________________//
347
348void
349deregister_observer( test_observer& to )
350{
351 s_frk_impl().m_observers.erase( &to );
352}
353
354//____________________________________________________________________________//
355
356void
357reset_observers()
358{
359 s_frk_impl().m_observers.clear();
360}
361
362//____________________________________________________________________________//
363
364master_test_suite_t&
365master_test_suite()
366{
367 if( !s_frk_impl().m_master_test_suite )
368 s_frk_impl().m_master_test_suite = new master_test_suite_t;
369
370 return *s_frk_impl().m_master_test_suite;
371}
372
373//____________________________________________________________________________//
374
375test_case const&
376current_test_case()
377{
378 return get<test_case>( s_frk_impl().m_curr_test_case );
379}
380
381//____________________________________________________________________________//
382
383test_unit&
384get( test_unit_id id, test_unit_type t )
385{
386 test_unit* res = s_frk_impl().m_test_units[id];
387
388 if( (res->p_type & t) == 0 )
389 throw internal_error( "Invalid test unit type" );
390
391 return *res;
392}
393
394//____________________________________________________________________________//
395
396void
397run( test_unit_id id, bool continue_test )
398{
399 if( id == INV_TEST_UNIT_ID )
400 id = master_test_suite().p_id;
401
402 test_case_counter tcc;
403 traverse_test_tree( id, tcc );
404
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700405 NDNBOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::test_to_run().is_empty()
406 ? NDNBOOST_TEST_L( "test tree is empty" )
407 : NDNBOOST_TEST_L( "no test cases matching filter" ) );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700408
409 bool call_start_finish = !continue_test || !s_frk_impl().m_test_in_progress;
410 bool was_in_progress = s_frk_impl().m_test_in_progress;
411
412 s_frk_impl().m_test_in_progress = true;
413
414 if( call_start_finish ) {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700415 NDNBOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) {
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700416 ndnboost::execution_monitor em;
417
418 try {
419 em.execute( ut_detail::test_start_caller( to, tcc.p_count ) );
420 }
421 catch( execution_exception const& ex ) {
422 throw setup_error( ex.what() );
423 }
424 }
425 }
426
427 switch( runtime_config::random_seed() ) {
428 case 0:
429 break;
430 case 1: {
431 unsigned int seed = static_cast<unsigned int>( std::time( 0 ) );
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700432 NDNBOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700433 std::srand( seed );
434 break;
435 }
436 default:
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700437 NDNBOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << runtime_config::random_seed() );
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700438 std::srand( runtime_config::random_seed() );
439 }
440
441 try {
442 traverse_test_tree( id, s_frk_impl() );
443 }
444 catch( test_being_aborted const& ) {
445 // abort already reported
446 }
447
448 if( call_start_finish ) {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700449 NDNBOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700450 to->test_finish();
451 }
452
453 s_frk_impl().m_test_in_progress = was_in_progress;
454}
455
456//____________________________________________________________________________//
457
458void
459run( test_unit const* tu, bool continue_test )
460{
461 run( tu->p_id, continue_test );
462}
463
464//____________________________________________________________________________//
465
466void
467assertion_result( bool passed )
468{
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700469 NDNBOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700470 to->assertion_result( passed );
471}
472
473//____________________________________________________________________________//
474
475void
476exception_caught( execution_exception const& ex )
477{
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700478 NDNBOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700479 to->exception_caught( ex );
480}
481
482//____________________________________________________________________________//
483
484void
485test_unit_aborted( test_unit const& tu )
486{
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700487 NDNBOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700488 to->test_unit_aborted( tu );
489}
490
491//____________________________________________________________________________//
492
493} // namespace framework
494
495} // namespace unit_test
496
497} // namespace ndnboost
498
499//____________________________________________________________________________//
500
501#include <ndnboost/test/detail/enable_warnings.hpp>
502
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700503#endif // NDNBOOST_TEST_FRAMEWORK_IPP_021005GER