test_case.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. //!@file
  8. //!@brief test case family based on data generator
  9. // ***************************************************************************
  10. #ifndef BOOST_TEST_DATA_TEST_CASE_HPP_102211GER
  11. #define BOOST_TEST_DATA_TEST_CASE_HPP_102211GER
  12. // Boost.Test
  13. #include <boost/test/data/config.hpp>
  14. #include <boost/test/data/dataset.hpp>
  15. #include <boost/test/data/for_each_sample.hpp>
  16. #include <boost/test/tree/test_unit.hpp>
  17. // Boost
  18. #include <boost/preprocessor/repetition/enum_params.hpp>
  19. #include <boost/preprocessor/repetition/enum_binary_params.hpp>
  20. #include <boost/preprocessor/repetition/repeat_from_to.hpp>
  21. #include <boost/preprocessor/variadic/to_seq.hpp>
  22. #include <boost/preprocessor/variadic/size.hpp>
  23. #include <boost/preprocessor/cat.hpp>
  24. #include <boost/preprocessor/seq/for_each_i.hpp>
  25. #include <boost/preprocessor/seq/for_each.hpp>
  26. #include <boost/preprocessor/seq/enum.hpp>
  27. #include <boost/preprocessor/control/iif.hpp>
  28. #include <boost/preprocessor/comparison/equal.hpp>
  29. #include <boost/bind/bind.hpp>
  30. #include <boost/type_traits/is_copy_constructible.hpp>
  31. #include <boost/test/tools/detail/print_helper.hpp>
  32. #include <boost/test/utils/string_cast.hpp>
  33. #include <list>
  34. #include <string>
  35. #include <boost/test/detail/suppress_warnings.hpp>
  36. #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) \
  37. && !defined(BOOST_TEST_DATASET_MAX_ARITY)
  38. # define BOOST_TEST_DATASET_MAX_ARITY 10
  39. #endif
  40. //____________________________________________________________________________//
  41. namespace boost {
  42. namespace unit_test {
  43. namespace data {
  44. namespace ds_detail {
  45. // ************************************************************************** //
  46. // ************** seed ************** //
  47. // ************************************************************************** //
  48. struct seed {
  49. template<typename DataSet>
  50. typename data::result_of::make<DataSet>::type
  51. operator->*( DataSet&& ds ) const
  52. {
  53. return data::make( std::forward<DataSet>( ds ) );
  54. }
  55. };
  56. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
  57. !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
  58. !defined(BOOST_NO_CXX11_DECLTYPE) && \
  59. !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
  60. !defined(BOOST_NO_CXX11_SMART_PTR)
  61. #define BOOST_TEST_DATASET_VARIADIC
  62. template <class T>
  63. struct parameter_holder {
  64. std::shared_ptr<T> value;
  65. parameter_holder(T && value_)
  66. : value(std::make_shared<T>(std::move(value_)))
  67. {}
  68. operator T const&() const {
  69. return *value;
  70. }
  71. };
  72. template <class T>
  73. parameter_holder<typename std::remove_reference<T>::type>
  74. boost_bind_rvalue_holder_helper_impl(T&& value, boost::false_type /* is copy constructible */) {
  75. return parameter_holder<typename std::remove_reference<T>::type>(std::forward<T>(value));
  76. }
  77. template <class T>
  78. T&& boost_bind_rvalue_holder_helper_impl(T&& value, boost::true_type /* is copy constructible */) {
  79. return std::forward<T>(value);
  80. }
  81. template <class T>
  82. auto boost_bind_rvalue_holder_helper(T&& value)
  83. -> decltype(boost_bind_rvalue_holder_helper_impl(
  84. std::forward<T>(value),
  85. typename boost::is_copy_constructible<typename std::remove_reference<T>::type>::type()))
  86. {
  87. // need to use boost::is_copy_constructible because std::is_copy_constructible is broken on MSVC12
  88. return boost_bind_rvalue_holder_helper_impl(
  89. std::forward<T>(value),
  90. typename boost::is_copy_constructible<typename std::remove_reference<T>::type>::type());
  91. }
  92. #endif
  93. // ************************************************************************** //
  94. // ************** test_case_gen ************** //
  95. // ************************************************************************** //
  96. template<typename TestCase,typename DataSet>
  97. class test_case_gen : public test_unit_generator {
  98. public:
  99. // Constructor
  100. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  101. test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet&& ds )
  102. : m_dataset( std::forward<DataSet>( ds ) )
  103. , m_generated( false )
  104. , m_tc_name( ut_detail::normalize_test_case_name( tc_name ) )
  105. , m_tc_file( tc_file )
  106. , m_tc_line( tc_line )
  107. , m_tc_index( 0 )
  108. {}
  109. test_case_gen( test_case_gen&& gen )
  110. : m_dataset( std::move( gen.m_dataset ) )
  111. , m_generated( gen.m_generated )
  112. , m_tc_name( gen.m_tc_name )
  113. , m_tc_file( gen.m_tc_file )
  114. , m_tc_line( gen.m_tc_line )
  115. , m_tc_index( gen.m_tc_index )
  116. , m_test_cases( std::move(gen.m_test_cases) )
  117. {}
  118. #else
  119. test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet const& ds )
  120. : m_dataset( ds )
  121. , m_generated( false )
  122. , m_tc_name( ut_detail::normalize_test_case_name( tc_name ) )
  123. , m_tc_file( tc_file )
  124. , m_tc_line( tc_line )
  125. , m_tc_index( 0 )
  126. {}
  127. #endif
  128. public:
  129. virtual test_unit* next() const
  130. {
  131. if(!m_generated) {
  132. data::for_each_sample( m_dataset, *this );
  133. m_generated = true;
  134. }
  135. if( m_test_cases.empty() )
  136. return 0;
  137. test_unit* res = m_test_cases.front();
  138. m_test_cases.pop_front();
  139. return res;
  140. }
  141. #if !defined(BOOST_TEST_DATASET_VARIADIC)
  142. // see BOOST_TEST_DATASET_MAX_ARITY to increase the default supported arity
  143. // there is also a limit on boost::bind
  144. #define TC_MAKE(z,arity,_) \
  145. template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
  146. void operator()( BOOST_PP_ENUM_BINARY_PARAMS(arity, Arg, const& arg) ) const \
  147. { \
  148. m_test_cases.push_back( new test_case( genTestCaseName(), m_tc_file, m_tc_line, \
  149. boost::bind( &TestCase::template test_method<BOOST_PP_ENUM_PARAMS(arity,Arg)>,\
  150. BOOST_PP_ENUM_PARAMS(arity, arg) ) ) ); \
  151. } \
  152. BOOST_PP_REPEAT_FROM_TO(1, BOOST_TEST_DATASET_MAX_ARITY, TC_MAKE, _)
  153. #else
  154. template<typename ...Arg>
  155. void operator()(Arg&& ... arg) const
  156. {
  157. m_test_cases.push_back(
  158. new test_case( genTestCaseName(),
  159. m_tc_file,
  160. m_tc_line,
  161. std::bind( &TestCase::template test_method<Arg...>,
  162. boost_bind_rvalue_holder_helper(std::forward<Arg>(arg))...)));
  163. }
  164. #endif
  165. private:
  166. std::string genTestCaseName() const
  167. {
  168. return "_" + utils::string_cast(m_tc_index++);
  169. }
  170. // Data members
  171. DataSet m_dataset;
  172. mutable bool m_generated;
  173. std::string m_tc_name;
  174. const_string m_tc_file;
  175. std::size_t m_tc_line;
  176. mutable std::size_t m_tc_index;
  177. mutable std::list<test_unit*> m_test_cases;
  178. };
  179. //____________________________________________________________________________//
  180. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  181. template<typename TestCase,typename DataSet>
  182. boost::shared_ptr<test_unit_generator> //test_case_gen<TestCase,DataSet>
  183. make_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet&& ds )
  184. {
  185. return boost::shared_ptr<test_unit_generator>(new test_case_gen<TestCase,DataSet>( tc_name, tc_file, tc_line, std::forward<DataSet>(ds) ));
  186. }
  187. #else
  188. template<typename TestCase,typename DataSet>
  189. test_case_gen<TestCase,DataSet>
  190. make_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet const& ds )
  191. {
  192. return test_case_gen<TestCase,DataSet>( tc_name, tc_file, tc_line, ds );
  193. }
  194. #endif
  195. //____________________________________________________________________________//
  196. } // namespace ds_detail
  197. // ************************************************************************** //
  198. // ************** BOOST_DATA_TEST_CASE ************** //
  199. // ************************************************************************** //
  200. #define BOOST_DATA_TEST_CASE_PARAM(r, _, i, param) (BOOST_PP_CAT(Arg, i) const& param)
  201. #define BOOST_DATA_TEST_CONTEXT(r, _, param) << BOOST_STRINGIZE(param) << " = " << boost::test_tools::tt_detail::print_helper(param) << "; "
  202. #define BOOST_DATA_TEST_CASE_PARAMS( params ) \
  203. BOOST_PP_SEQ_ENUM( \
  204. BOOST_PP_SEQ_FOR_EACH_I(BOOST_DATA_TEST_CASE_PARAM, _, params)) \
  205. /**/
  206. #define BOOST_DATA_TEST_CASE_IMPL(arity, F, test_name, dataset, params) \
  207. struct BOOST_PP_CAT(test_name, case) : public F { \
  208. template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
  209. static void test_method( BOOST_DATA_TEST_CASE_PARAMS( params ) ) \
  210. { \
  211. BOOST_TEST_CONTEXT( "" \
  212. BOOST_PP_SEQ_FOR_EACH(BOOST_DATA_TEST_CONTEXT, _, params)) \
  213. { \
  214. BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture ctor");\
  215. BOOST_PP_CAT(test_name, case) t; \
  216. BOOST_TEST_CHECKPOINT('"' \
  217. << #test_name << "\" fixture setup"); \
  218. boost::unit_test::setup_conditional(t); \
  219. BOOST_TEST_CHECKPOINT('"' << #test_name << "\" test entry"); \
  220. t._impl(BOOST_PP_SEQ_ENUM(params)); \
  221. BOOST_TEST_CHECKPOINT('"' \
  222. << #test_name << "\" fixture teardown"); \
  223. boost::unit_test::teardown_conditional(t); \
  224. BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture dtor");\
  225. } \
  226. } \
  227. private: \
  228. template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
  229. void _impl(BOOST_DATA_TEST_CASE_PARAMS( params )); \
  230. }; \
  231. \
  232. BOOST_AUTO_TEST_SUITE( test_name, \
  233. *boost::unit_test::decorator::stack_decorator()) \
  234. \
  235. BOOST_AUTO_TU_REGISTRAR( BOOST_PP_CAT(test_name, case) )( \
  236. boost::unit_test::data::ds_detail::make_test_case_gen< \
  237. BOOST_PP_CAT(test_name, case)>( \
  238. BOOST_STRINGIZE( test_name ), \
  239. __FILE__, __LINE__, \
  240. boost::unit_test::data::ds_detail::seed{} ->* dataset ), \
  241. boost::unit_test::decorator::collector_t::instance() ); \
  242. \
  243. BOOST_AUTO_TEST_SUITE_END() \
  244. \
  245. template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
  246. void BOOST_PP_CAT(test_name, case)::_impl( \
  247. BOOST_DATA_TEST_CASE_PARAMS( params ) ) \
  248. /**/
  249. #define BOOST_DATA_TEST_CASE_WITH_PARAMS( F, test_name, dataset, ... ) \
  250. BOOST_DATA_TEST_CASE_IMPL( BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), \
  251. F, test_name, dataset, \
  252. BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) ) \
  253. /**/
  254. #define BOOST_DATA_TEST_CASE_NO_PARAMS( F, test_name, dataset ) \
  255. BOOST_DATA_TEST_CASE_WITH_PARAMS( F, test_name, dataset, sample ) \
  256. /**/
  257. #if BOOST_PP_VARIADICS_MSVC
  258. #define BOOST_DATA_TEST_CASE( ... ) \
  259. BOOST_PP_CAT( \
  260. BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \
  261. BOOST_DATA_TEST_CASE_NO_PARAMS, \
  262. BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \
  263. BOOST_AUTO_TEST_CASE_FIXTURE, __VA_ARGS__), ) \
  264. /**/
  265. #define BOOST_DATA_TEST_CASE_F( F, ... ) \
  266. BOOST_PP_CAT( \
  267. BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \
  268. BOOST_DATA_TEST_CASE_NO_PARAMS, \
  269. BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \
  270. F, __VA_ARGS__), ) \
  271. /**/
  272. #else
  273. #define BOOST_DATA_TEST_CASE( ... ) \
  274. BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \
  275. BOOST_DATA_TEST_CASE_NO_PARAMS, \
  276. BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \
  277. BOOST_AUTO_TEST_CASE_FIXTURE, __VA_ARGS__) \
  278. /**/
  279. #define BOOST_DATA_TEST_CASE_F( F, ... ) \
  280. BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \
  281. BOOST_DATA_TEST_CASE_NO_PARAMS, \
  282. BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \
  283. F, __VA_ARGS__) \
  284. /**/
  285. #endif
  286. } // namespace data
  287. } // namespace unit_test
  288. } // namespace boost
  289. #include <boost/test/detail/enable_warnings.hpp>
  290. #endif // BOOST_TEST_DATA_TEST_CASE_HPP_102211GER