// (C) Copyright Gennadiy Rozental 2001. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/test for the library home page. // //!@file //!@brief test case family based on data generator // *************************************************************************** #ifndef BOOST_TEST_DATA_TEST_CASE_HPP_102211GER #define BOOST_TEST_DATA_TEST_CASE_HPP_102211GER // Boost.Test #include #include #include #include // Boost #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) \ && !defined(BOOST_TEST_DATASET_MAX_ARITY) # define BOOST_TEST_DATASET_MAX_ARITY 10 #endif //____________________________________________________________________________// namespace boost { namespace unit_test { namespace data { namespace ds_detail { // ************************************************************************** // // ************** seed ************** // // ************************************************************************** // struct seed { template typename data::result_of::make::type operator->*( DataSet&& ds ) const { return data::make( std::forward( ds ) ); } }; #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ !defined(BOOST_NO_CXX11_DECLTYPE) && \ !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \ !defined(BOOST_NO_CXX11_SMART_PTR) #define BOOST_TEST_DATASET_VARIADIC template struct parameter_holder { std::shared_ptr value; parameter_holder(T && value_) : value(std::make_shared(std::move(value_))) {} operator T const&() const { return *value; } }; template parameter_holder::type> boost_bind_rvalue_holder_helper_impl(T&& value, boost::false_type /* is copy constructible */) { return parameter_holder::type>(std::forward(value)); } template T&& boost_bind_rvalue_holder_helper_impl(T&& value, boost::true_type /* is copy constructible */) { return std::forward(value); } template auto boost_bind_rvalue_holder_helper(T&& value) -> decltype(boost_bind_rvalue_holder_helper_impl( std::forward(value), typename boost::is_copy_constructible::type>::type())) { // need to use boost::is_copy_constructible because std::is_copy_constructible is broken on MSVC12 return boost_bind_rvalue_holder_helper_impl( std::forward(value), typename boost::is_copy_constructible::type>::type()); } #endif // ************************************************************************** // // ************** test_case_gen ************** // // ************************************************************************** // template class test_case_gen : public test_unit_generator { public: // Constructor #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet&& ds ) : m_dataset( std::forward( ds ) ) , m_generated( false ) , m_tc_name( ut_detail::normalize_test_case_name( tc_name ) ) , m_tc_file( tc_file ) , m_tc_line( tc_line ) , m_tc_index( 0 ) {} test_case_gen( test_case_gen&& gen ) : m_dataset( std::move( gen.m_dataset ) ) , m_generated( gen.m_generated ) , m_tc_name( gen.m_tc_name ) , m_tc_file( gen.m_tc_file ) , m_tc_line( gen.m_tc_line ) , m_tc_index( gen.m_tc_index ) , m_test_cases( std::move(gen.m_test_cases) ) {} #else test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet const& ds ) : m_dataset( ds ) , m_generated( false ) , m_tc_name( ut_detail::normalize_test_case_name( tc_name ) ) , m_tc_file( tc_file ) , m_tc_line( tc_line ) , m_tc_index( 0 ) {} #endif public: virtual test_unit* next() const { if(!m_generated) { data::for_each_sample( m_dataset, *this ); m_generated = true; } if( m_test_cases.empty() ) return 0; test_unit* res = m_test_cases.front(); m_test_cases.pop_front(); return res; } #if !defined(BOOST_TEST_DATASET_VARIADIC) // see BOOST_TEST_DATASET_MAX_ARITY to increase the default supported arity // there is also a limit on boost::bind #define TC_MAKE(z,arity,_) \ template \ void operator()( BOOST_PP_ENUM_BINARY_PARAMS(arity, Arg, const& arg) ) const \ { \ m_test_cases.push_back( new test_case( genTestCaseName(), m_tc_file, m_tc_line, \ boost::bind( &TestCase::template test_method,\ BOOST_PP_ENUM_PARAMS(arity, arg) ) ) ); \ } \ BOOST_PP_REPEAT_FROM_TO(1, BOOST_TEST_DATASET_MAX_ARITY, TC_MAKE, _) #else template void operator()(Arg&& ... arg) const { m_test_cases.push_back( new test_case( genTestCaseName(), m_tc_file, m_tc_line, std::bind( &TestCase::template test_method, boost_bind_rvalue_holder_helper(std::forward(arg))...))); } #endif private: std::string genTestCaseName() const { return "_" + utils::string_cast(m_tc_index++); } // Data members DataSet m_dataset; mutable bool m_generated; std::string m_tc_name; const_string m_tc_file; std::size_t m_tc_line; mutable std::size_t m_tc_index; mutable std::list m_test_cases; }; //____________________________________________________________________________// #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template boost::shared_ptr //test_case_gen make_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet&& ds ) { return boost::shared_ptr(new test_case_gen( tc_name, tc_file, tc_line, std::forward(ds) )); } #else template test_case_gen make_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet const& ds ) { return test_case_gen( tc_name, tc_file, tc_line, ds ); } #endif //____________________________________________________________________________// } // namespace ds_detail // ************************************************************************** // // ************** BOOST_DATA_TEST_CASE ************** // // ************************************************************************** // #define BOOST_DATA_TEST_CASE_PARAM(r, _, i, param) (BOOST_PP_CAT(Arg, i) const& param) #define BOOST_DATA_TEST_CONTEXT(r, _, param) << BOOST_STRINGIZE(param) << " = " << boost::test_tools::tt_detail::print_helper(param) << "; " #define BOOST_DATA_TEST_CASE_PARAMS( params ) \ BOOST_PP_SEQ_ENUM( \ BOOST_PP_SEQ_FOR_EACH_I(BOOST_DATA_TEST_CASE_PARAM, _, params)) \ /**/ #define BOOST_DATA_TEST_CASE_IMPL(arity, F, test_name, dataset, params) \ struct BOOST_PP_CAT(test_name, case) : public F { \ template \ static void test_method( BOOST_DATA_TEST_CASE_PARAMS( params ) ) \ { \ BOOST_TEST_CONTEXT( "" \ BOOST_PP_SEQ_FOR_EACH(BOOST_DATA_TEST_CONTEXT, _, params)) \ { \ BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture ctor");\ BOOST_PP_CAT(test_name, case) t; \ BOOST_TEST_CHECKPOINT('"' \ << #test_name << "\" fixture setup"); \ boost::unit_test::setup_conditional(t); \ BOOST_TEST_CHECKPOINT('"' << #test_name << "\" test entry"); \ t._impl(BOOST_PP_SEQ_ENUM(params)); \ BOOST_TEST_CHECKPOINT('"' \ << #test_name << "\" fixture teardown"); \ boost::unit_test::teardown_conditional(t); \ BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture dtor");\ } \ } \ private: \ template \ void _impl(BOOST_DATA_TEST_CASE_PARAMS( params )); \ }; \ \ BOOST_AUTO_TEST_SUITE( test_name, \ *boost::unit_test::decorator::stack_decorator()) \ \ BOOST_AUTO_TU_REGISTRAR( BOOST_PP_CAT(test_name, case) )( \ boost::unit_test::data::ds_detail::make_test_case_gen< \ BOOST_PP_CAT(test_name, case)>( \ BOOST_STRINGIZE( test_name ), \ __FILE__, __LINE__, \ boost::unit_test::data::ds_detail::seed{} ->* dataset ), \ boost::unit_test::decorator::collector_t::instance() ); \ \ BOOST_AUTO_TEST_SUITE_END() \ \ template \ void BOOST_PP_CAT(test_name, case)::_impl( \ BOOST_DATA_TEST_CASE_PARAMS( params ) ) \ /**/ #define BOOST_DATA_TEST_CASE_WITH_PARAMS( F, test_name, dataset, ... ) \ BOOST_DATA_TEST_CASE_IMPL( BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), \ F, test_name, dataset, \ BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) ) \ /**/ #define BOOST_DATA_TEST_CASE_NO_PARAMS( F, test_name, dataset ) \ BOOST_DATA_TEST_CASE_WITH_PARAMS( F, test_name, dataset, sample ) \ /**/ #if BOOST_PP_VARIADICS_MSVC #define BOOST_DATA_TEST_CASE( ... ) \ BOOST_PP_CAT( \ BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \ BOOST_DATA_TEST_CASE_NO_PARAMS, \ BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \ BOOST_AUTO_TEST_CASE_FIXTURE, __VA_ARGS__), ) \ /**/ #define BOOST_DATA_TEST_CASE_F( F, ... ) \ BOOST_PP_CAT( \ BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \ BOOST_DATA_TEST_CASE_NO_PARAMS, \ BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \ F, __VA_ARGS__), ) \ /**/ #else #define BOOST_DATA_TEST_CASE( ... ) \ BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \ BOOST_DATA_TEST_CASE_NO_PARAMS, \ BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \ BOOST_AUTO_TEST_CASE_FIXTURE, __VA_ARGS__) \ /**/ #define BOOST_DATA_TEST_CASE_F( F, ... ) \ BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \ BOOST_DATA_TEST_CASE_NO_PARAMS, \ BOOST_DATA_TEST_CASE_WITH_PARAMS) ( \ F, __VA_ARGS__) \ /**/ #endif } // namespace data } // namespace unit_test } // namespace boost #include #endif // BOOST_TEST_DATA_TEST_CASE_HPP_102211GER