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$
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