boost/test/data/test_case.hpp
// (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>
#include <boost/test/tree/test_unit.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/tools/detail/print_helper.hpp>
#include <boost/test/utils/string_cast.hpp>
#include <list>
#include <string>
#include <boost/test/detail/suppress_warnings.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
// there is also a limit on boost::bind
#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,
std::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