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 /// Defines template_test_case_gen 10 // *************************************************************************** 11 12 #ifndef BOOST_TEST_TREE_TEST_CASE_TEMPLATE_HPP_091911GER 13 #define BOOST_TEST_TREE_TEST_CASE_TEMPLATE_HPP_091911GER 14 15 // Boost.Test 16 #include <boost/test/detail/config.hpp> 17 #include <boost/test/detail/global_typedef.hpp> 18 #include <boost/test/detail/fwd_decl.hpp> 19 #include <boost/test/tree/test_unit.hpp> 20 21 #include <boost/test/utils/class_properties.hpp> 22 #include <boost/test/tree/observer.hpp> 23 #include <boost/test/utils/algorithm.hpp> 24 25 26 // Boost 27 #include <boost/shared_ptr.hpp> 28 #include <boost/mpl/for_each.hpp> 29 #include <boost/mpl/identity.hpp> 30 #include <boost/type.hpp> 31 #include <boost/type_traits/is_const.hpp> 32 #include <boost/type_traits/is_volatile.hpp> 33 #include <boost/type_traits/is_lvalue_reference.hpp> 34 #include <boost/type_traits/is_rvalue_reference.hpp> 35 #include <boost/type_traits/remove_reference.hpp> 36 #include <boost/function/function0.hpp> 37 38 #if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI) 39 # include <boost/current_function.hpp> 40 #else 41 # include <boost/core/demangle.hpp> 42 #endif 43 44 // STL 45 #include <string> // for std::string 46 #include <list> // for std::list 47 48 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ 49 !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) 50 #include <type_traits> 51 #include <boost/mpl/is_sequence.hpp> 52 #endif 53 54 #include <boost/test/detail/suppress_warnings.hpp> 55 56 57 //____________________________________________________________________________// 58 59 namespace boost { 60 namespace unit_test { 61 namespace ut_detail { 62 63 // ************************************************************************** // 64 // ************** test_case_template_invoker ************** // 65 // ************************************************************************** // 66 67 template<typename TestCaseTemplate,typename TestType> 68 class test_case_template_invoker { 69 public: operator ()()70 void operator()() { TestCaseTemplate::run( (boost::type<TestType>*)0 ); } 71 }; 72 73 // ************************************************************************** // 74 // ************** generate_test_case_4_type ************** // 75 // ************************************************************************** // 76 77 template<typename Generator, typename TestCaseTemplate> 78 struct generate_test_case_4_type { generate_test_case_4_typeboost::unit_test::ut_detail::generate_test_case_4_type79 explicit generate_test_case_4_type( const_string tc_name, const_string tc_file, std::size_t tc_line, Generator& G ) 80 : m_test_case_name( tc_name ) 81 , m_test_case_file( tc_file ) 82 , m_test_case_line( tc_line ) 83 , m_holder( G ) 84 {} 85 86 template<typename TestType> operator ()boost::unit_test::ut_detail::generate_test_case_4_type87 void operator()( mpl::identity<TestType> ) 88 { 89 std::string full_name; 90 assign_op( full_name, m_test_case_name, 0 ); 91 full_name += '<'; 92 #if !defined(BOOST_NO_TYPEID) && !defined(BOOST_NO_RTTI) 93 full_name += boost::core::demangle(typeid(TestType).name()); // same as execution_monitor.ipp 94 #else 95 full_name += BOOST_CURRENT_FUNCTION; 96 #endif 97 98 // replacing ',' by ', ' first, and then removing any double space 99 static const std::string to_replace[] = { "class ", "struct ", ",", " ", " <", " >"}; 100 static const std::string replacement[] = { "", "" , ", ", " ", "<" , ">"}; 101 102 full_name = unit_test::utils::replace_all_occurrences_of( 103 full_name, 104 to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]), 105 replacement, replacement + sizeof(replacement)/sizeof(replacement[0])); 106 107 typedef typename boost::remove_reference<TestType>::type TestTypewoRef; 108 if( boost::is_const<TestTypewoRef>::value ) 109 full_name += "_const"; 110 if( boost::is_volatile<TestTypewoRef>::value ) 111 full_name += "_volatile"; 112 if( boost::is_rvalue_reference<TestType>::value ) 113 full_name += "_refref"; 114 else if( boost::is_lvalue_reference<TestType>::value ) 115 full_name += "_ref"; 116 117 full_name += '>'; 118 119 m_holder.m_test_cases.push_back( new test_case( ut_detail::normalize_test_case_name( full_name ), 120 m_test_case_file, 121 m_test_case_line, 122 test_case_template_invoker<TestCaseTemplate,TestType>() ) ); 123 } 124 125 private: 126 // Data members 127 const_string m_test_case_name; 128 const_string m_test_case_file; 129 std::size_t m_test_case_line; 130 Generator& m_holder; 131 }; 132 133 // ************************************************************************** // 134 // ************** test_case_template ************** // 135 // ************************************************************************** // 136 137 class template_test_case_gen_base : public test_unit_generator { 138 public: next() const139 test_unit* next() const BOOST_OVERRIDE 140 { 141 if( m_test_cases.empty() ) 142 return 0; 143 144 test_unit* res = m_test_cases.front(); 145 m_test_cases.pop_front(); 146 147 return res; 148 } 149 150 // Data members 151 mutable std::list<test_unit*> m_test_cases; 152 }; 153 154 template<typename TestCaseTemplate,typename TestTypesList, typename enabler = void> 155 class template_test_case_gen : public template_test_case_gen_base { 156 public: 157 // Constructor template_test_case_gen(const_string tc_name,const_string tc_file,std::size_t tc_line)158 template_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line ) 159 { 160 typedef generate_test_case_4_type<template_test_case_gen<TestCaseTemplate,TestTypesList>,TestCaseTemplate> single_test_gen; 161 162 mpl::for_each<TestTypesList,mpl::make_identity<mpl::_> >( single_test_gen( tc_name, tc_file, tc_line, *this ) ); 163 } 164 }; 165 166 // Describing template test cases with tuples 167 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ 168 !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && \ 169 !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) 170 171 template<typename TestCaseTemplate, 172 template <class ...> class C, 173 typename... parameter_pack> 174 class template_test_case_gen< 175 TestCaseTemplate, 176 C<parameter_pack...>, 177 typename std::enable_if<!boost::mpl::is_sequence<C<parameter_pack...>>::value>::type > 178 : public template_test_case_gen_base { 179 180 template<typename F> for_each(F & f)181 void for_each(F &f) 182 { 183 auto l = { (f(mpl::identity<parameter_pack>()), 0)... }; 184 (void)l; // silence warning 185 } 186 187 public: 188 // Constructor template_test_case_gen(const_string tc_name,const_string tc_file,std::size_t tc_line)189 template_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line ) 190 { 191 using this_type = template_test_case_gen< 192 TestCaseTemplate, 193 C<parameter_pack...>, 194 typename std::enable_if<!boost::mpl::is_sequence<C<parameter_pack...>>::value>::type>; 195 using single_test_gen = generate_test_case_4_type<this_type, TestCaseTemplate>; 196 197 single_test_gen op( tc_name, tc_file, tc_line, *this ); 198 199 this->for_each(op); 200 } 201 }; 202 203 #endif /* C++11 variadic, type alias */ 204 205 } // namespace ut_detail 206 } // unit_test 207 } // namespace boost 208 209 #include <boost/test/detail/enable_warnings.hpp> 210 211 #endif // BOOST_TEST_TREE_TEST_CASE_TEMPLATE_HPP_091911GER 212