1 // (C) Copyright Gennadiy Rozental 2001-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: 54633 $
11 //
12 // Description : defines test_unit, test_case, test_case_results, test_suite and test_tree_visitor
13 // ***************************************************************************
14
15 #ifndef BOOST_TEST_UNIT_TEST_SUITE_IMPL_HPP_071894GER
16 #define BOOST_TEST_UNIT_TEST_SUITE_IMPL_HPP_071894GER
17
18 // Boost.Test
19 #include <boost/test/detail/config.hpp>
20 #include <boost/test/detail/global_typedef.hpp>
21 #include <boost/test/utils/class_properties.hpp>
22 #include <boost/test/utils/callback.hpp>
23 #include <boost/test/detail/fwd_decl.hpp>
24 #include <boost/test/detail/workaround.hpp>
25 #include <boost/test/test_observer.hpp>
26
27 // Boost
28 #include <boost/shared_ptr.hpp>
29 #include <boost/mpl/for_each.hpp>
30 #include <boost/mpl/identity.hpp>
31 #include <boost/type.hpp>
32 #include <boost/type_traits/is_const.hpp>
33
34 // STL
35 #include <typeinfo> // for typeid
36 #include <string> // for std::string
37 #include <list> // for std::list
38 #include <vector> // for std::vector
39
40 #include <boost/test/detail/suppress_warnings.hpp>
41
42 //____________________________________________________________________________//
43
44 namespace boost {
45
46 namespace unit_test {
47
48 // ************************************************************************** //
49 // ************** test_unit ************** //
50 // ************************************************************************** //
51
52 class BOOST_TEST_DECL test_unit {
53 public:
54 enum { type = tut_any };
55
56 // Constructor
57 test_unit( const_string tu_name, test_unit_type t );
58
59 // dependencies management
60 void depends_on( test_unit* tu );
61 bool check_dependencies() const;
62
63 // Public r/o properties
64 typedef BOOST_READONLY_PROPERTY(test_unit_id,(framework_impl)) id_t;
65 typedef BOOST_READONLY_PROPERTY(test_unit_id,(test_suite)) parent_id_t;
66 readonly_property<test_unit_type> p_type; // type for this test unit
67 readonly_property<const_string> p_type_name; // "case"/"suite"
68 id_t p_id; // unique id for this test unit
69 parent_id_t p_parent_id; // parent test suite id
70
71 // Public r/w properties
72 readwrite_property<std::string> p_name; // name for this test unit
73 readwrite_property<unsigned> p_timeout; // timeout for the test unit execution
74 readwrite_property<counter_t> p_expected_failures; // number of expected failures in this test unit
75 mutable readwrite_property<bool> p_enabled; // enabled status for this unit
76
77 void increase_exp_fail( unsigned num );
78
79 protected:
80 ~test_unit();
81
82 private:
83 // Data members
84 std::list<test_unit_id> m_dependencies;
85 };
86
87 // ************************************************************************** //
88 // ************** test_case_generator ************** //
89 // ************************************************************************** //
90
91 class BOOST_TEST_DECL test_unit_generator {
92 public:
93 virtual test_unit* next() const = 0;
94
95 protected:
~test_unit_generator()96 BOOST_TEST_PROTECTED_VIRTUAL ~test_unit_generator() {}
97 };
98
99 // ************************************************************************** //
100 // ************** test_case ************** //
101 // ************************************************************************** //
102
103 class BOOST_TEST_DECL test_case : public test_unit {
104 public:
105 enum { type = tut_case };
106
107 // Constructor
108 test_case( const_string tc_name, callback0<> const& test_func );
109
110 // Access methods
test_func() const111 callback0<> const& test_func() const { return m_test_func; }
112
113 private:
114 friend class framework_impl;
~test_case()115 ~test_case() {}
116
117 // BOOST_MSVC <= 1200 have problems with callback as property
118 // Data members
119 callback0<> m_test_func;
120 };
121
122 // ************************************************************************** //
123 // ************** test_suite ************** //
124 // ************************************************************************** //
125
126 class BOOST_TEST_DECL test_suite : public test_unit {
127 public:
128 enum { type = tut_suite };
129
130 // Constructor
131 explicit test_suite( const_string ts_name );
132
133 // test unit list management
134 void add( test_unit* tu, counter_t expected_failures = 0, unsigned timeout = 0 );
135 void add( test_unit_generator const& gen, unsigned timeout = 0 );
136 void remove( test_unit_id id );
137
138 // access methods
139 test_unit_id get( const_string tu_name ) const;
size() const140 std::size_t size() const { return m_members.size(); }
141
142 protected:
143 friend BOOST_TEST_DECL
144 void traverse_test_tree( test_suite const&, test_tree_visitor& );
145 friend class framework_impl;
~test_suite()146 virtual ~test_suite() {}
147
148 // Data members
149 std::vector<test_unit_id> m_members;
150 };
151
152 // ************************************************************************** //
153 // ************** master_test_suite ************** //
154 // ************************************************************************** //
155
156 class BOOST_TEST_DECL master_test_suite_t : public test_suite {
157 public:
master_test_suite_t()158 master_test_suite_t() : test_suite( "Master Test Suite" )
159 , argc( 0 )
160 , argv( 0 )
161 {}
162
163 // Data members
164 int argc;
165 char** argv;
166 };
167
168
169 // ************************************************************************** //
170 // ************** test_tree_visitor ************** //
171 // ************************************************************************** //
172
173 class BOOST_TEST_DECL test_tree_visitor {
174 public:
175 // test tree visitor interface
visit(test_case const &)176 virtual void visit( test_case const& ) {}
test_suite_start(test_suite const &)177 virtual bool test_suite_start( test_suite const& ) { return true; }
test_suite_finish(test_suite const &)178 virtual void test_suite_finish( test_suite const& ) {}
179
180 protected:
~test_tree_visitor()181 BOOST_TEST_PROTECTED_VIRTUAL ~test_tree_visitor() {}
182 };
183
184 // ************************************************************************** //
185 // ************** traverse_test_tree ************** //
186 // ************************************************************************** //
187
188 BOOST_TEST_DECL void traverse_test_tree( test_case const&, test_tree_visitor& );
189 BOOST_TEST_DECL void traverse_test_tree( test_suite const&, test_tree_visitor& );
190 BOOST_TEST_DECL void traverse_test_tree( test_unit_id , test_tree_visitor& );
191
192 //____________________________________________________________________________//
193
194 inline void
traverse_test_tree(test_unit const & tu,test_tree_visitor & V)195 traverse_test_tree( test_unit const& tu, test_tree_visitor& V )
196 {
197 if( tu.p_type == tut_case )
198 traverse_test_tree( static_cast<test_case const&>( tu ), V );
199 else
200 traverse_test_tree( static_cast<test_suite const&>( tu ), V );
201 }
202
203 //____________________________________________________________________________//
204
205 // ************************************************************************** //
206 // ************** test_case_counter ************** //
207 // ************************************************************************** //
208
209 class test_case_counter : public test_tree_visitor {
210 public:
211 // Constructor
test_case_counter()212 test_case_counter() : p_count( 0 ) {}
213
214 BOOST_READONLY_PROPERTY( counter_t, (test_case_counter)) p_count;
215 private:
216 // test tree visitor interface
217 virtual void visit( test_case const& );
test_suite_start(test_suite const & ts)218 virtual bool test_suite_start( test_suite const& ts ) { return ts.p_enabled; }
219 };
220
221 // ************************************************************************** //
222 // ************** test_being_aborted ************** //
223 // ************************************************************************** //
224
225 struct BOOST_TEST_DECL test_being_aborted {};
226
227 // ************************************************************************** //
228 // ************** object generators ************** //
229 // ************************************************************************** //
230
231 namespace ut_detail {
232
233 BOOST_TEST_DECL std::string normalize_test_case_name( const_string tu_name );
234
235 template<typename InstanceType,typename UserTestCase>
236 struct user_tc_method_invoker {
237 typedef void (UserTestCase::*TestMethod )();
238
user_tc_method_invokerboost::unit_test::ut_detail::user_tc_method_invoker239 user_tc_method_invoker( shared_ptr<InstanceType> inst, TestMethod test_method )
240 : m_inst( inst ), m_test_method( test_method ) {}
241
operator ()boost::unit_test::ut_detail::user_tc_method_invoker242 void operator()() { ((*m_inst).*m_test_method)(); }
243
244 shared_ptr<InstanceType> m_inst;
245 TestMethod m_test_method;
246 };
247
248 } // namespace ut_detail
249
250 //____________________________________________________________________________//
251
252 inline test_case*
make_test_case(callback0<> const & test_func,const_string tc_name)253 make_test_case( callback0<> const& test_func, const_string tc_name )
254 {
255 return new test_case( ut_detail::normalize_test_case_name( tc_name ), test_func );
256 }
257
258 //____________________________________________________________________________//
259
260 template<typename UserTestCase, typename InstanceType>
261 inline test_case*
make_test_case(void (UserTestCase::* test_method)(),const_string tc_name,boost::shared_ptr<InstanceType> user_test_case)262 make_test_case( void (UserTestCase::* test_method )(),
263 const_string tc_name,
264 boost::shared_ptr<InstanceType> user_test_case )
265 {
266 return new test_case( ut_detail::normalize_test_case_name( tc_name ),
267 ut_detail::user_tc_method_invoker<InstanceType,UserTestCase>( user_test_case, test_method ) );
268 }
269
270 //____________________________________________________________________________//
271
272 // ************************************************************************** //
273 // ************** auto_test_unit_registrar ************** //
274 // ************************************************************************** //
275
276 namespace ut_detail {
277
278 struct BOOST_TEST_DECL auto_test_unit_registrar
279 {
280 // Constructors
281 auto_test_unit_registrar( test_case* tc, counter_t exp_fail );
282 explicit auto_test_unit_registrar( const_string ts_name );
283 explicit auto_test_unit_registrar( test_unit_generator const& tc_gen );
284 explicit auto_test_unit_registrar( int );
285
286 private:
287 static std::list<test_suite*>& curr_ts_store();
288 };
289
290 //____________________________________________________________________________//
291
292 template<typename T>
293 struct auto_tc_exp_fail {
auto_tc_exp_failboost::unit_test::ut_detail::auto_tc_exp_fail294 auto_tc_exp_fail() : m_value( 0 ) {}
295
auto_tc_exp_failboost::unit_test::ut_detail::auto_tc_exp_fail296 explicit auto_tc_exp_fail( unsigned v )
297 : m_value( v )
298 {
299 instance() = this;
300 }
301
instanceboost::unit_test::ut_detail::auto_tc_exp_fail302 static auto_tc_exp_fail*& instance()
303 {
304 static auto_tc_exp_fail inst;
305 static auto_tc_exp_fail* inst_ptr = &inst;
306
307 return inst_ptr;
308 }
309
valueboost::unit_test::ut_detail::auto_tc_exp_fail310 unsigned value() const { return m_value; }
311
312 private:
313 // Data members
314 unsigned m_value;
315 };
316
317 //____________________________________________________________________________//
318
319 } // namespace ut_detail
320
321 // ************************************************************************** //
322 // ************** global_fixture ************** //
323 // ************************************************************************** //
324
325 class BOOST_TEST_DECL global_fixture : public test_observer {
326 public:
327 // Constructor
328 global_fixture();
329 };
330
331 //____________________________________________________________________________//
332
333 namespace ut_detail {
334
335 template<typename F>
336 struct global_fixture_impl : public global_fixture {
337 // Constructor
global_fixture_implboost::unit_test::ut_detail::global_fixture_impl338 global_fixture_impl(): m_fixure( 0 ) {}
339
340 // test observer interface
test_startboost::unit_test::ut_detail::global_fixture_impl341 virtual void test_start( counter_t ) { m_fixure = new F; }
test_finishboost::unit_test::ut_detail::global_fixture_impl342 virtual void test_finish() { delete m_fixure; m_fixure = 0; }
test_abortedboost::unit_test::ut_detail::global_fixture_impl343 virtual void test_aborted() { delete m_fixure; m_fixure = 0; }
344
345 private:
346 // Data members
347 F* m_fixure;
348 };
349
350 // ************************************************************************** //
351 // ************** test_case_template_invoker ************** //
352 // ************************************************************************** //
353
354 template<typename TestCaseTemplate,typename TestType>
355 class test_case_template_invoker {
356 public:
operator ()()357 void operator()() { TestCaseTemplate::run( (boost::type<TestType>*)0 ); }
358 };
359
360 // ************************************************************************** //
361 // ************** generate_test_case_4_type ************** //
362 // ************************************************************************** //
363
364 template<typename Generator,typename TestCaseTemplate>
365 struct generate_test_case_4_type {
generate_test_case_4_typeboost::unit_test::ut_detail::generate_test_case_4_type366 explicit generate_test_case_4_type( const_string tc_name, Generator& G )
367 : m_test_case_name( tc_name )
368 , m_holder( G )
369 {}
370
371 template<typename TestType>
operator ()boost::unit_test::ut_detail::generate_test_case_4_type372 void operator()( mpl::identity<TestType> )
373 {
374 std::string full_name;
375 assign_op( full_name, m_test_case_name, 0 );
376 full_name += '<';
377 full_name += typeid(TestType).name();
378 if( boost::is_const<TestType>::value )
379 full_name += " const";
380 full_name += '>';
381
382 m_holder.m_test_cases.push_back(
383 new test_case( full_name, test_case_template_invoker<TestCaseTemplate,TestType>() ) );
384 }
385
386 private:
387 // Data members
388 const_string m_test_case_name;
389 Generator& m_holder;
390 };
391
392 // ************************************************************************** //
393 // ************** test_case_template ************** //
394 // ************************************************************************** //
395
396 template<typename TestCaseTemplate,typename TestTypesList>
397 class template_test_case_gen : public test_unit_generator {
398 public:
399 // Constructor
template_test_case_gen(const_string tc_name)400 template_test_case_gen( const_string tc_name )
401 {
402 typedef generate_test_case_4_type<template_test_case_gen<TestCaseTemplate,TestTypesList>,
403 TestCaseTemplate
404 > single_test_gen;
405 mpl::for_each<TestTypesList,mpl::make_identity<mpl::_> >( single_test_gen( tc_name, *this ) );
406 }
407
next() const408 virtual test_unit* next() const
409 {
410 if( m_test_cases.empty() )
411 return 0;
412
413 test_unit* res = m_test_cases.front();
414 m_test_cases.pop_front();
415
416 return res;
417 }
418
419 // Data members
420 mutable std::list<test_unit*> m_test_cases;
421 };
422
423 //____________________________________________________________________________//
424
425 } // namespace ut_detail
426
427 } // unit_test
428
429 } // namespace boost
430
431 #include <boost/test/detail/enable_warnings.hpp>
432
433 #endif // BOOST_TEST_UNIT_TEST_SUITE_IMPL_HPP_071894GER
434
435