321 lines
13 KiB
C++
321 lines
13 KiB
C++
|
// (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 <boost/test/data/config.hpp>
|
||
|
#include <boost/test/data/dataset.hpp>
|
||
|
#include <boost/test/data/for_each_sample.hpp>
|
||
|
|
||
|
// Boost
|
||
|
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||
|
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||
|
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||
|
|
||
|
#include <boost/preprocessor/variadic/to_seq.hpp>
|
||
|
#include <boost/preprocessor/variadic/size.hpp>
|
||
|
#include <boost/preprocessor/cat.hpp>
|
||
|
#include <boost/preprocessor/seq/for_each_i.hpp>
|
||
|
#include <boost/preprocessor/seq/for_each.hpp>
|
||
|
#include <boost/preprocessor/seq/enum.hpp>
|
||
|
#include <boost/preprocessor/control/iif.hpp>
|
||
|
#include <boost/preprocessor/comparison/equal.hpp>
|
||
|
|
||
|
#include <boost/bind.hpp>
|
||
|
|
||
|
#include <boost/type_traits/is_copy_constructible.hpp>
|
||
|
|
||
|
#include <boost/test/detail/suppress_warnings.hpp>
|
||
|
#include <boost/test/tools/detail/print_helper.hpp>
|
||
|
#include <boost/test/utils/string_cast.hpp>
|
||
|
|
||
|
#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 DataSet>
|
||
|
typename data::result_of::make<DataSet>::type
|
||
|
operator->*( DataSet&& ds ) const
|
||
|
{
|
||
|
return data::make( std::forward<DataSet>( 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 <class T>
|
||
|
struct parameter_holder {
|
||
|
std::shared_ptr<T> value;
|
||
|
|
||
|
parameter_holder(T && value_)
|
||
|
: value(std::make_shared<T>(std::move(value_)))
|
||
|
{}
|
||
|
|
||
|
operator T const&() const {
|
||
|
return *value;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <class T>
|
||
|
parameter_holder<typename std::remove_reference<T>::type>
|
||
|
boost_bind_rvalue_holder_helper_impl(T&& value, boost::false_type /* is copy constructible */) {
|
||
|
return parameter_holder<typename std::remove_reference<T>::type>(std::forward<T>(value));
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
T&& boost_bind_rvalue_holder_helper_impl(T&& value, boost::true_type /* is copy constructible */) {
|
||
|
return std::forward<T>(value);
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
auto boost_bind_rvalue_holder_helper(T&& value)
|
||
|
-> decltype(boost_bind_rvalue_holder_helper_impl(
|
||
|
std::forward<T>(value),
|
||
|
typename boost::is_copy_constructible<typename std::remove_reference<T>::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<T>(value),
|
||
|
typename boost::is_copy_constructible<typename std::remove_reference<T>::type>::type());
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// ************************************************************************** //
|
||
|
// ************** test_case_gen ************** //
|
||
|
// ************************************************************************** //
|
||
|
|
||
|
template<typename TestCase,typename DataSet>
|
||
|
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_tc_name( ut_detail::normalize_test_case_name( tc_name ) )
|
||
|
, m_tc_file( tc_file )
|
||
|
, m_tc_line( tc_line )
|
||
|
, m_tc_index( 0 )
|
||
|
{
|
||
|
data::for_each_sample( std::forward<DataSet>( ds ), *this );
|
||
|
}
|
||
|
test_case_gen( test_case_gen&& gen )
|
||
|
: 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_tc_name( ut_detail::normalize_test_case_name( tc_name ) )
|
||
|
, m_tc_file( tc_file )
|
||
|
, m_tc_line( tc_line )
|
||
|
, m_tc_index( 0 )
|
||
|
{
|
||
|
data::for_each_sample( ds, *this );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
virtual test_unit* next() const
|
||
|
{
|
||
|
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
|
||
|
#define TC_MAKE(z,arity,_) \
|
||
|
template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
|
||
|
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_ENUM_PARAMS(arity, arg) ) ) ); \
|
||
|
} \
|
||
|
|
||
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_TEST_DATASET_MAX_ARITY, TC_MAKE, _)
|
||
|
#else
|
||
|
template<typename ...Arg>
|
||
|
void operator()(Arg&& ... arg) const
|
||
|
{
|
||
|
m_test_cases.push_back(
|
||
|
new test_case( genTestCaseName(),
|
||
|
m_tc_file,
|
||
|
m_tc_line,
|
||
|
boost::bind( &TestCase::template test_method<Arg...>,
|
||
|
boost_bind_rvalue_holder_helper(std::forward<Arg>(arg))...)));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
std::string genTestCaseName() const
|
||
|
{
|
||
|
return "_" + utils::string_cast(m_tc_index++);
|
||
|
}
|
||
|
|
||
|
// Data members
|
||
|
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<test_unit*> m_test_cases;
|
||
|
};
|
||
|
|
||
|
//____________________________________________________________________________//
|
||
|
|
||
|
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||
|
template<typename TestCase,typename DataSet>
|
||
|
test_case_gen<TestCase,DataSet>
|
||
|
make_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet&& ds )
|
||
|
{
|
||
|
return test_case_gen<TestCase,DataSet>( tc_name, tc_file, tc_line, std::forward<DataSet>(ds) );
|
||
|
}
|
||
|
#else
|
||
|
template<typename TestCase,typename DataSet>
|
||
|
test_case_gen<TestCase,DataSet>
|
||
|
make_test_case_gen( const_string tc_name, const_string tc_file, std::size_t tc_line, DataSet const& ds )
|
||
|
{
|
||
|
return test_case_gen<TestCase,DataSet>( 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<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
|
||
|
static void test_method( BOOST_DATA_TEST_CASE_PARAMS( params ) ) \
|
||
|
{ \
|
||
|
BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture entry.");\
|
||
|
BOOST_PP_CAT(test_name, case) t; \
|
||
|
BOOST_TEST_CHECKPOINT('"' << #test_name << "\" entry."); \
|
||
|
BOOST_TEST_CONTEXT( "" \
|
||
|
BOOST_PP_SEQ_FOR_EACH(BOOST_DATA_TEST_CONTEXT, _, params)) \
|
||
|
t._impl(BOOST_PP_SEQ_ENUM(params)); \
|
||
|
BOOST_TEST_CHECKPOINT('"' << #test_name << "\" exit."); \
|
||
|
} \
|
||
|
private: \
|
||
|
template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
|
||
|
void _impl(BOOST_DATA_TEST_CASE_PARAMS( params )); \
|
||
|
}; \
|
||
|
\
|
||
|
BOOST_AUTO_TEST_SUITE( test_name ) \
|
||
|
\
|
||
|
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::instance() ); \
|
||
|
\
|
||
|
BOOST_AUTO_TEST_SUITE_END() \
|
||
|
\
|
||
|
template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
|
||
|
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 <boost/test/detail/enable_warnings.hpp>
|
||
|
|
||
|
#endif // BOOST_TEST_DATA_TEST_CASE_HPP_102211GER
|
||
|
|