diff options
Diffstat (limited to 'boost/test')
27 files changed, 496 insertions, 103 deletions
diff --git a/boost/test/data/config.hpp b/boost/test/data/config.hpp index 7a9d03be98..e1d15b5013 100644 --- a/boost/test/data/config.hpp +++ b/boost/test/data/config.hpp @@ -37,6 +37,11 @@ #endif +//! Defined when the initializer_list implementation is buggy, such as for VS2013 +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define BOOST_TEST_ERRONEOUS_INIT_LIST +#endif + //____________________________________________________________________________// #define BOOST_TEST_DS_ERROR( msg ) BOOST_TEST_I_THROW( std::logic_error( msg ) ) diff --git a/boost/test/data/for_each_sample.hpp b/boost/test/data/for_each_sample.hpp index 4785b038cc..6cb40bd33c 100644 --- a/boost/test/data/for_each_sample.hpp +++ b/boost/test/data/for_each_sample.hpp @@ -77,7 +77,7 @@ invoke_action( Action const& action, T&& args, std::true_type /* is_tuple */ ) template<typename DataSet, typename Action> inline typename std::enable_if<monomorphic::is_dataset<DataSet>::value,void>::type -for_each_sample( DataSet && samples, +for_each_sample( DataSet const & samples, Action const& act, data::size_t number_of_samples = BOOST_TEST_DS_INFINITE_SIZE ) { diff --git a/boost/test/data/generators.hpp b/boost/test/data/generators.hpp deleted file mode 100644 index e9bd4c17b5..0000000000 --- a/boost/test/data/generators.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// (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 specific generators -// *************************************************************************** - -#ifndef BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_HPP_112011GER -#define BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_HPP_112011GER - -// Boost.Test -#include <boost/test/data/monomorphic/generators/xrange.hpp> - -#endif // BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_HPP_112011GER - diff --git a/boost/test/data/index_sequence.hpp b/boost/test/data/index_sequence.hpp index 21af7e504c..05b48f7f97 100644 --- a/boost/test/data/index_sequence.hpp +++ b/boost/test/data/index_sequence.hpp @@ -49,6 +49,11 @@ struct make_index_sequence<B,E,typename std::enable_if<E==B+1,void>::type> { typedef index_sequence<B> type; }; +template <> +struct make_index_sequence<0, 0> { + typedef index_sequence<> type; +}; + template <typename... T> using index_sequence_for = typename make_index_sequence<0, sizeof...(T)>::type; diff --git a/boost/test/data/monomorphic.hpp b/boost/test/data/monomorphic.hpp index 31d7b01b32..e5f2d3ad21 100644 --- a/boost/test/data/monomorphic.hpp +++ b/boost/test/data/monomorphic.hpp @@ -22,6 +22,7 @@ #include <boost/test/data/monomorphic/join.hpp> #include <boost/test/data/monomorphic/singleton.hpp> #include <boost/test/data/monomorphic/zip.hpp> +#include <boost/test/data/monomorphic/delayed.hpp> #endif // BOOST_TEST_DATA_MONOMORPHIC_HPP_102211GER diff --git a/boost/test/data/monomorphic/delayed.hpp b/boost/test/data/monomorphic/delayed.hpp new file mode 100644 index 0000000000..eecf117a8d --- /dev/null +++ b/boost/test/data/monomorphic/delayed.hpp @@ -0,0 +1,122 @@ +// (C) Copyright Raffi Enficiaud 2018. +// 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 +/// Defines a lazy/delayed dataset store +// *************************************************************************** + +#ifndef BOOST_TEST_DATA_MONOMORPHIC_DELAYED_HPP_062018GER +#define BOOST_TEST_DATA_MONOMORPHIC_DELAYED_HPP_062018GER + +// Boost.Test +#include <boost/test/data/config.hpp> +#include <boost/test/data/monomorphic/fwd.hpp> +#include <boost/test/data/index_sequence.hpp> + +#include <boost/core/ref.hpp> + +#include <algorithm> + +#include <boost/test/detail/suppress_warnings.hpp> + +//____________________________________________________________________________// + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_HDR_TUPLE) + +namespace boost { +namespace unit_test { +namespace data { +namespace monomorphic { + +// ************************************************************************** // +// ************** delayed_dataset ************** // +// ************************************************************************** // + + +/// Delayed dataset +/// +/// This dataset holds another dataset that is instanciated on demand. It is +/// constructed with the @c data::make_delayed<dataset_t>(arg1,....) instead of the +/// @c data::make. +template <class dataset_t, class ...Args> +class delayed_dataset +{ +public: + enum { arity = dataset_t::arity }; + using iterator = decltype(std::declval<dataset_t>().begin()); + using sample = typename dataset_t::sample; + + delayed_dataset(Args... args) + : m_args(std::make_tuple(std::forward<Args>(args)...)) + {} + + // Mostly for VS2013 + delayed_dataset(delayed_dataset&& b) + : m_args(std::move(b.m_args)) + , m_dataset(std::move(b.m_dataset)) + {} + + boost::unit_test::data::size_t size() const { + return this->get().size(); + } + + // iterator + iterator begin() const { + return this->get().begin(); + } + +private: + + dataset_t& get() const { + if(!m_dataset) { + m_dataset = create(boost::unit_test::data::index_sequence_for<Args...>()); + } + return *m_dataset; + } + + template<std::size_t... I> + std::unique_ptr<dataset_t> + create(boost::unit_test::data::index_sequence<I...>) const + { + return std::unique_ptr<dataset_t>{new dataset_t(std::get<I>(m_args)...)}; + } + + std::tuple<typename std::decay<Args>::type...> m_args; + mutable std::unique_ptr<dataset_t> m_dataset; +}; + +//____________________________________________________________________________// + +//! A lazy/delayed dataset is a dataset. +template <class dataset_t, class ...Args> +struct is_dataset< delayed_dataset<dataset_t, Args...> > : boost::mpl::true_ {}; + +//____________________________________________________________________________// + +} // namespace monomorphic + +template<class dataset_t, class ...Args> +inline typename std::enable_if< + monomorphic::is_dataset< dataset_t >::value, + monomorphic::delayed_dataset<dataset_t, Args...> +>::type +make_delayed(Args... args) +{ + return monomorphic::delayed_dataset<dataset_t, Args...>( std::forward<Args>(args)... ); +} + + +} // namespace data +} // namespace unit_test +} // namespace boost + +#endif + +#include <boost/test/detail/enable_warnings.hpp> + +#endif // BOOST_TEST_DATA_MONOMORPHIC_DELAYED_HPP_062018GER diff --git a/boost/test/data/monomorphic/fwd.hpp b/boost/test/data/monomorphic/fwd.hpp index dcd1b84165..82d3ff354d 100644 --- a/boost/test/data/monomorphic/fwd.hpp +++ b/boost/test/data/monomorphic/fwd.hpp @@ -43,9 +43,6 @@ namespace monomorphic { #if !defined(BOOST_TEST_DOXYGEN_DOC__) -template<typename T, typename Specific> -class dataset; - template<typename T> class singleton; @@ -58,6 +55,12 @@ class array; template<typename T> class init_list; +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_HDR_TUPLE) +template<class dataset_t, class ...Args> +class delayed_dataset; +#endif + #endif // ************************************************************************** // @@ -73,6 +76,8 @@ struct is_dataset : mpl::false_ {}; //! A reference to a dataset is a dataset template<typename DataSet> struct is_dataset<DataSet&> : is_dataset<DataSet> {}; +template<typename DataSet> +struct is_dataset<DataSet&&> : is_dataset<DataSet> {}; //____________________________________________________________________________// @@ -80,6 +85,18 @@ struct is_dataset<DataSet&> : is_dataset<DataSet> {}; template<typename DataSet> struct is_dataset<DataSet const> : is_dataset<DataSet> {}; +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +//! Helper to check if a list of types contains a dataset +template<class DataSet, class...> +struct has_dataset : is_dataset<DataSet> {}; + +template<class DataSet0, class DataSet1, class... DataSetTT> +struct has_dataset<DataSet0, DataSet1, DataSetTT...> + : std::integral_constant<bool, is_dataset<DataSet0>::value || has_dataset<DataSet1, DataSetTT...>::value> +{}; +#endif + } // namespace monomorphic // ************************************************************************** // @@ -160,6 +177,31 @@ make( std::initializer_list<T>&& ); //____________________________________________________________________________// +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_TEST_ERRONEOUS_INIT_LIST) +//! @overload boost::unit_test::data::make() +template<class T, class ...Args> +inline typename std::enable_if< + !monomorphic::has_dataset<T, Args...>::value, + monomorphic::init_list<T> +>::type +make( T&& arg0, Args&&... args ); +#endif + +//____________________________________________________________________________// + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_HDR_TUPLE) +template<class dataset_t, class ...Args> +inline typename std::enable_if< + monomorphic::is_dataset< dataset_t >::value, + monomorphic::delayed_dataset<dataset_t, Args...> +>::type +make_delayed(Args... args); +#endif + +//____________________________________________________________________________// + namespace result_of { //! Result of the make call. diff --git a/boost/test/data/monomorphic/grid.hpp b/boost/test/data/monomorphic/grid.hpp index 2cf66189a0..ee138df15d 100644 --- a/boost/test/data/monomorphic/grid.hpp +++ b/boost/test/data/monomorphic/grid.hpp @@ -104,7 +104,10 @@ public: {} // dataset interface - data::size_t size() const { return m_ds1.size() * m_ds2.size(); } + data::size_t size() const { + BOOST_TEST_DS_ASSERT( !m_ds1.size().is_inf() && !m_ds2.size().is_inf(), "Grid axes can't have infinite size" ); + return m_ds1.size() * m_ds2.size(); + } iterator begin() const { return iterator( m_ds1.begin(), m_ds2 ); } private: @@ -140,8 +143,6 @@ inline typename boost::lazy_enable_if_c<is_dataset<DataSet1>::value && is_datase >::type operator*( DataSet1&& ds1, DataSet2&& ds2 ) { - BOOST_TEST_DS_ASSERT( !ds1.size().is_inf() && !ds2.size().is_inf(), "Grid axes can't have infinite size" ); - return grid<DataSet1,DataSet2>( std::forward<DataSet1>( ds1 ), std::forward<DataSet2>( ds2 ) ); } diff --git a/boost/test/data/monomorphic/initializer_list.hpp b/boost/test/data/monomorphic/initializer_list.hpp index 3221597396..3f4a4df045 100644 --- a/boost/test/data/monomorphic/initializer_list.hpp +++ b/boost/test/data/monomorphic/initializer_list.hpp @@ -16,6 +16,7 @@ #include <boost/test/data/config.hpp> #include <boost/test/data/monomorphic/fwd.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/test/detail/suppress_warnings.hpp> //____________________________________________________________________________// @@ -26,10 +27,14 @@ namespace data { namespace monomorphic { // ************************************************************************** // -// ************** array ************** // +// ************** initializer_list ************** // // ************************************************************************** // -/// Dataset view of a C array +/// Dataset view from an initializer_list or variadic template arguments +/// +/// The data should be stored in the dataset, and since the elements +/// are passed by an @c std::initializer_list , it implies a copy of +/// the elements. template<typename T> class init_list { public: @@ -37,12 +42,22 @@ public: enum { arity = 1 }; - typedef T const* iterator; + typedef typename std::vector<T>::const_iterator iterator; - //! Constructor swallows initializer_list - init_list( std::initializer_list<T>&& il ) - : m_data( std::forward<std::initializer_list<T>>( il ) ) + //! Constructor copies content of initializer_list + init_list( std::initializer_list<T> il ) + : m_data( il ) {} + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_TEST_ERRONEOUS_INIT_LIST) + //! Variadic template initialization + template <class ...Args> + init_list( Args&& ... args ) { + int dummy[] = { 0, (m_data.emplace_back(std::forward<Args&&>(args)), 0)... }; + boost::ignore_unused(dummy); + } +#endif //! dataset interface data::size_t size() const { return m_data.size(); } @@ -50,7 +65,39 @@ public: private: // Data members - std::initializer_list<T> m_data; + std::vector<T> m_data; +}; + +//! Specialization of init_list for type bool +template <> +class init_list<bool> { +public: + typedef bool sample; + + enum { arity = 1 }; + + typedef std::vector<bool>::const_iterator iterator; + + //! Constructor copies content of initializer_list + init_list( std::initializer_list<bool>&& il ) + : m_data( std::forward<std::initializer_list<bool>>( il ) ) + {} + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_TEST_ERRONEOUS_INIT_LIST) + //! Variadic template initialization + template <class ...Args> + init_list( Args&& ... args ) : m_data{ args... } + { } +#endif + + //! dataset interface + data::size_t size() const { return m_data.size(); } + iterator begin() const { return m_data.begin(); } + +private: + // Data members + std::vector<bool> m_data; }; //____________________________________________________________________________// @@ -71,6 +118,20 @@ make( std::initializer_list<T>&& il ) return monomorphic::init_list<T>( std::forward<std::initializer_list<T>>( il ) ); } +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_TEST_ERRONEOUS_INIT_LIST) +template<class T, class ...Args> +inline typename std::enable_if< + !monomorphic::has_dataset<T, Args...>::value, + monomorphic::init_list<T> +>::type +make( T&& arg0, Args&&... args ) +{ + return monomorphic::init_list<T>( std::forward<T>(arg0), std::forward<Args>( args )... ); +} +#endif + + } // namespace data } // namespace unit_test } // namespace boost diff --git a/boost/test/data/monomorphic/zip.hpp b/boost/test/data/monomorphic/zip.hpp index 5fc65d0e20..04e390e9ac 100644 --- a/boost/test/data/monomorphic/zip.hpp +++ b/boost/test/data/monomorphic/zip.hpp @@ -75,28 +75,47 @@ public: //! Constructor //! //! The datasets are moved and not copied. - zip( DataSet1&& ds1, DataSet2&& ds2, data::size_t size ) + zip( DataSet1&& ds1, DataSet2&& ds2/*, data::size_t size*/ ) : m_ds1( std::forward<DataSet1>( ds1 ) ) , m_ds2( std::forward<DataSet2>( ds2 ) ) - , m_size( size ) + //, m_size( size ) {} //! Move constructor zip( zip&& j ) : m_ds1( std::forward<DataSet1>( j.m_ds1 ) ) , m_ds2( std::forward<DataSet2>( j.m_ds2 ) ) - , m_size( j.m_size ) + //, m_size( j.m_size ) {} // dataset interface - data::size_t size() const { return m_size; } + data::size_t size() const { return zip_size(); } iterator begin() const { return iterator( m_ds1.begin(), m_ds2.begin() ); } private: // Data members DataSet1 m_ds1; DataSet2 m_ds2; - data::size_t m_size; + //data::size_t m_size; + + + //! Handles the sise of the resulting zipped dataset. + data::size_t zip_size() const + { + data::size_t ds1_size = m_ds1.size(); + data::size_t ds2_size = m_ds2.size(); + + if( ds1_size == ds2_size ) + return ds1_size; + + if( ds1_size == 1 || ds1_size.is_inf() ) + return ds2_size; + + if( ds2_size == 1 || ds2_size.is_inf() ) + return ds1_size; + + BOOST_TEST_DS_ERROR( "Can't zip datasets of different sizes" ); + } }; //____________________________________________________________________________// @@ -107,32 +126,6 @@ struct is_dataset<zip<DataSet1,DataSet2>> : mpl::true_ {}; //____________________________________________________________________________// -namespace ds_detail { - -//! Handles the sise of the resulting zipped dataset. -template<typename DataSet1, typename DataSet2> -inline data::size_t -zip_size( DataSet1&& ds1, DataSet2&& ds2 ) -{ - data::size_t ds1_size = ds1.size(); - data::size_t ds2_size = ds2.size(); - - if( ds1_size == ds2_size ) - return ds1_size; - - if( ds1_size == 1 || ds1_size.is_inf() ) - return ds2_size; - - if( ds2_size == 1 || ds2_size.is_inf() ) - return ds1_size; - - BOOST_TEST_DS_ERROR( "Can't zip datasets of different sizes" ); -} - -} // namespace ds_detail - -//____________________________________________________________________________// - namespace result_of { //! Result type of the zip operator. @@ -153,8 +146,8 @@ inline typename boost::lazy_enable_if_c<is_dataset<DataSet1>::value && is_datase operator^( DataSet1&& ds1, DataSet2&& ds2 ) { return zip<DataSet1,DataSet2>( std::forward<DataSet1>( ds1 ), - std::forward<DataSet2>( ds2 ), - ds_detail::zip_size( ds1, ds2 ) ); + std::forward<DataSet2>( ds2 )/*, + ds_detail::zip_size( ds1, ds2 )*/ ); } //____________________________________________________________________________// diff --git a/boost/test/data/test_case.hpp b/boost/test/data/test_case.hpp index 01dc91b06a..eecbee9065 100644 --- a/boost/test/data/test_case.hpp +++ b/boost/test/data/test_case.hpp @@ -126,15 +126,17 @@ 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_dataset( std::forward<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 ) - { - data::for_each_sample( std::forward<DataSet>( ds ), *this ); - } + {} test_case_gen( test_case_gen&& gen ) - : m_tc_name( gen.m_tc_name ) + : 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 ) @@ -142,17 +144,23 @@ public: {} #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_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 ) - { - data::for_each_sample( ds, *this ); - } + {} #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; @@ -162,6 +170,7 @@ public: 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 @@ -195,6 +204,8 @@ private: } // 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; @@ -206,10 +217,10 @@ private: #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template<typename TestCase,typename DataSet> -test_case_gen<TestCase,DataSet> +boost::shared_ptr<test_unit_generator> //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) ); + return boost::shared_ptr<test_unit_generator>(new test_case_gen<TestCase,DataSet>( tc_name, tc_file, tc_line, std::forward<DataSet>(ds) )); } #else template<typename TestCase,typename DataSet> diff --git a/boost/test/execution_monitor.hpp b/boost/test/execution_monitor.hpp index ed06ef254e..eb3b21c6dc 100644 --- a/boost/test/execution_monitor.hpp +++ b/boost/test/execution_monitor.hpp @@ -515,8 +515,12 @@ enum masks { BOOST_FPE_ALL = MCW_EM, #elif !defined(BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__)/* *** */ + BOOST_FPE_DIVBYZERO = BOOST_FPE_OFF, + BOOST_FPE_INEXACT = BOOST_FPE_OFF, + BOOST_FPE_INVALID = BOOST_FPE_OFF, + BOOST_FPE_OVERFLOW = BOOST_FPE_OFF, + BOOST_FPE_UNDERFLOW = BOOST_FPE_OFF, BOOST_FPE_ALL = BOOST_FPE_OFF, - #else /* *** */ #if defined(FE_DIVBYZERO) diff --git a/boost/test/impl/decorator.ipp b/boost/test/impl/decorator.ipp index 74d42b22a2..0cc562ee2f 100644 --- a/boost/test/impl/decorator.ipp +++ b/boost/test/impl/decorator.ipp @@ -64,6 +64,14 @@ collector::reset() //____________________________________________________________________________// +std::vector<base_ptr> +collector::get_lazy_decorators() const +{ + return m_tu_decorators; +} + +//____________________________________________________________________________// + // ************************************************************************** // // ************** decorator::base ************** // // ************************************************************************** // diff --git a/boost/test/impl/framework.ipp b/boost/test/impl/framework.ipp index 496e7de859..ddb0144d27 100644 --- a/boost/test/impl/framework.ipp +++ b/boost/test/impl/framework.ipp @@ -692,7 +692,10 @@ public: BOOST_TEST_FOREACH( test_observer*, to, m_observers ) to->test_unit_skipped( tu, precondition_res.message() ); - return unit_test_monitor_t::precondition_failure; + // It is not an error to skip the test if any of the parent tests + // have failed. This one should be reported as skipped as if it was + // disabled + return unit_test_monitor_t::test_ok; } // 20. Notify all observers about the start of the test unit @@ -707,7 +710,7 @@ public: break; test_results const& test_rslt = unit_test::results_collector.results( m_curr_test_unit ); if( test_rslt.aborted() ) { - result = unit_test_monitor_t::precondition_failure; + result = unit_test_monitor_t::test_setup_failure; break; } } @@ -1178,6 +1181,13 @@ finalize_setup_phase( test_unit_id master_tu_id ) class apply_decorators : public test_tree_visitor { private: // test_tree_visitor interface + + virtual bool test_suite_start( test_suite const& ts) + { + const_cast<test_suite&>(ts).generate(); + return test_tree_visitor::test_suite_start(ts); + } + virtual bool visit( test_unit const& tu ) { BOOST_TEST_FOREACH( decorator::base_ptr, d, tu.p_decorators.get() ) diff --git a/boost/test/impl/results_collector.ipp b/boost/test/impl/results_collector.ipp index fd74bdb65c..ea5050937b 100644 --- a/boost/test/impl/results_collector.ipp +++ b/boost/test/impl/results_collector.ipp @@ -5,11 +5,9 @@ // See http://www.boost.org/libs/test for the library home page. // -// File : $RCSfile$ -// -// Version : $Revision$ -// -// Description : implements Unit Test results collecting facility. +/// @file +/// Test results collecting facility. +/// // *************************************************************************** #ifndef BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER @@ -52,13 +50,17 @@ test_results::test_results() bool test_results::passed() const { + // if it is skipped, it is not passed. However, if any children is not failed/aborted + // then their skipped status is not taken into account. return !p_skipped && p_test_cases_failed == 0 && p_assertions_failed <= p_expected_failures && - p_test_cases_skipped == 0 && + // p_test_cases_skipped == 0 && !p_aborted; } +//____________________________________________________________________________// + bool test_results::aborted() const { @@ -67,6 +69,14 @@ test_results::aborted() const //____________________________________________________________________________// +bool +test_results::skipped() const +{ + return p_skipped; +} + +//____________________________________________________________________________// + int test_results::result_code() const { diff --git a/boost/test/impl/test_tree.ipp b/boost/test/impl/test_tree.ipp index e0839e3dd1..cb48be4a99 100644 --- a/boost/test/impl/test_tree.ipp +++ b/boost/test/impl/test_tree.ipp @@ -124,7 +124,7 @@ test_unit::check_preconditions() const test_results const& test_rslt = unit_test::results_collector.results( dep_id ); if( !test_rslt.passed() ) { test_tools::assertion_result res(false); - res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has failed"; + res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << (test_rslt.skipped() ? "\" was skipped":"\" has failed"); return res; } @@ -281,10 +281,46 @@ test_suite::add( test_unit_generator const& gen, decorator::collector& decorator decorators.store_in( *tu ); add( tu, 0 ); } + decorators.reset(); +} +void +test_suite::add( boost::shared_ptr<test_unit_generator> gen_ptr, decorator::collector& decorators ) +{ + std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > tmp_p(gen_ptr, decorators.get_lazy_decorators() ); + m_generators.push_back(tmp_p); decorators.reset(); } +void +test_suite::generate( ) +{ + typedef std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > element_t; + + for(std::vector<element_t>::iterator it(m_generators.begin()), ite(m_generators.end()); + it < ite; + ++it) + { + test_unit* tu; + while((tu = it->first->next()) != 0) { + tu->p_decorators.value.insert( tu->p_decorators.value.end(), it->second.begin(), it->second.end() ); + //it->second.store_in( *tu ); + add( tu, 0 ); + } + + } + m_generators.clear(); + + #if 0 + test_unit* tu; + while((tu = gen.next()) != 0) { + decorators.store_in( *tu ); + add( tu, 0 ); + } + #endif +} + + //____________________________________________________________________________// void @@ -457,6 +493,14 @@ auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& t //____________________________________________________________________________// +auto_test_unit_registrar::auto_test_unit_registrar( boost::shared_ptr<test_unit_generator> tc_gen, decorator::collector& decorators ) +{ + framework::current_auto_test_suite().add( tc_gen, decorators ); +} + + +//____________________________________________________________________________// + auto_test_unit_registrar::auto_test_unit_registrar( int ) { framework::current_auto_test_suite( 0, false ); diff --git a/boost/test/impl/unit_test_main.ipp b/boost/test/impl/unit_test_main.ipp index 1780c6b93b..cad3d88ec6 100644 --- a/boost/test/impl/unit_test_main.ipp +++ b/boost/test/impl/unit_test_main.ipp @@ -174,18 +174,34 @@ private: std::set<std::string> m_labels; }; +struct framework_shutdown_helper { + ~framework_shutdown_helper() { + try { + framework::shutdown(); + } + catch(...) { + std::cerr << "Boost.Test shutdown exception caught" << std::endl; + } + } +}; + } // namespace ut_detail // ************************************************************************** // // ************** unit_test_main ************** // // ************************************************************************** // + + int BOOST_TEST_DECL unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) { int result_code = 0; + ut_detail::framework_shutdown_helper shutdown_helper; + BOOST_TEST_I_TRY { + framework::init( init_func, argc, argv ); if( runtime_config::get<bool>( runtime_config::btrt_wait_for_debugger ) ) { @@ -247,14 +263,17 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) result_code = boost::exit_exception_failure; } + BOOST_TEST_I_CATCH( std::logic_error, ex ) { + results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; + + result_code = boost::exit_exception_failure; + } BOOST_TEST_I_CATCHALL() { results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl; result_code = boost::exit_exception_failure; } - framework::shutdown(); - return result_code; } diff --git a/boost/test/impl/unit_test_parameters.ipp b/boost/test/impl/unit_test_parameters.ipp index 428c10116f..fec7bb94ca 100644 --- a/boost/test/impl/unit_test_parameters.ipp +++ b/boost/test/impl/unit_test_parameters.ipp @@ -351,7 +351,7 @@ register_parameters( rt::parameters_store& store ) rt::env_var = "BOOST_TEST_LOG_SINK", rt::value_hint = "<stderr|stdout|file name>", rt::help = "Sets the log sink - the location " - "where Boost.Test writes the logs of the test execution. it allows to easily redirect the " + "where Boost.Test writes the logs of the test execution. It allows to easily redirect the " "test logs to file or standard streams. By default testing log is " "directed to standard output." )); @@ -380,8 +380,7 @@ register_parameters( rt::parameters_store& store ) , #endif rt::help = "Combines an effect of " + btrt_report_format + - " and " + btrt_log_format + " parameters. This parameter has higher priority " - "than either one of them. In other words if this parameter is specified " + " and " + btrt_log_format + " parameters. If this parameter is specified, " "it overrides the value of other two parameters. This parameter does not " "have a default value. The only acceptable values are string names of " "output formats: HRF - human readable format and XML - XML formats for " diff --git a/boost/test/results_collector.hpp b/boost/test/results_collector.hpp index 3acd7b87bc..75a0e551cd 100644 --- a/boost/test/results_collector.hpp +++ b/boost/test/results_collector.hpp @@ -79,6 +79,12 @@ public: /// Returns true if test unit passed bool passed() const; + /// Returns true if test unit skipped + /// + /// For test suites, this indicates if the test suite itself has been marked as + /// skipped, and not if the test suite contains any skipped test. + bool skipped() const; + /// Returns true if the test unit was aborted (hard failure) bool aborted() const; diff --git a/boost/test/tree/auto_registration.hpp b/boost/test/tree/auto_registration.hpp index a3fe32fda7..98bc2924fd 100644 --- a/boost/test/tree/auto_registration.hpp +++ b/boost/test/tree/auto_registration.hpp @@ -40,6 +40,7 @@ struct BOOST_TEST_DECL auto_test_unit_registrar { auto_test_unit_registrar( test_case* tc, decorator::collector& decorators, counter_t exp_fail = 0 ); explicit auto_test_unit_registrar( const_string ts_name, const_string ts_file, std::size_t ts_line, decorator::collector& decorators ); explicit auto_test_unit_registrar( test_unit_generator const& tc_gen, decorator::collector& decorators ); + explicit auto_test_unit_registrar( boost::shared_ptr<test_unit_generator> tc_gen, decorator::collector& decorators ); explicit auto_test_unit_registrar( int ); }; diff --git a/boost/test/tree/decorator.hpp b/boost/test/tree/decorator.hpp index 27c46682a0..f891a27765 100644 --- a/boost/test/tree/decorator.hpp +++ b/boost/test/tree/decorator.hpp @@ -59,6 +59,8 @@ public: void store_in( test_unit& tu ); void reset(); + + std::vector<base_ptr> get_lazy_decorators() const; private: BOOST_TEST_SINGLETON_CONS( collector ) diff --git a/boost/test/tree/test_case_template.hpp b/boost/test/tree/test_case_template.hpp index 83a13f00f5..f588e12e9f 100644 --- a/boost/test/tree/test_case_template.hpp +++ b/boost/test/tree/test_case_template.hpp @@ -141,10 +141,11 @@ public: } }; -// adding support for tuple +// Describing template test cases with tuples #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ - !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) + !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && \ + !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) template<typename TestCaseTemplate, typename... tuple_parameter_pack> class template_test_case_gen<TestCaseTemplate, std::tuple<tuple_parameter_pack...> > : public template_test_case_gen_base { @@ -179,7 +180,7 @@ public: } }; -#endif /* C++11 variadic and tuples */ +#endif /* C++11 variadic, tuples and type alias */ } // namespace ut_detail } // unit_test diff --git a/boost/test/tree/test_unit.hpp b/boost/test/tree/test_unit.hpp index 273fa14ff3..1441bdc7dd 100644 --- a/boost/test/tree/test_unit.hpp +++ b/boost/test/tree/test_unit.hpp @@ -43,6 +43,7 @@ namespace unit_test { namespace framework { class state; +BOOST_TEST_DECL master_test_suite_t& master_test_suite(); } // ************************************************************************** // @@ -176,9 +177,15 @@ public: /// @overload void add( test_unit_generator const& gen, decorator::collector& decorators ); + + /// @overload + void add( boost::shared_ptr<test_unit_generator> gen_ptr, decorator::collector& decorators ); //! Removes a test from the test suite. void remove( test_unit_id id ); + + //! Generates all the delayed test_units from the generators + void generate( ); // access methods @@ -199,6 +206,8 @@ protected: test_unit_id_list m_children; children_per_rank m_ranked_children; ///< maps child sibling rank to list of children with that rank + + std::vector< std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > > m_generators; /// lazy evaluation }; // ************************************************************************** // @@ -206,12 +215,17 @@ protected: // ************************************************************************** // class BOOST_TEST_DECL master_test_suite_t : public test_suite { -public: +private: master_test_suite_t(); - + master_test_suite_t(const master_test_suite_t&); // undefined + master_test_suite_t& operator=(master_test_suite_t const &); // undefined + +public: // Data members int argc; char** argv; + + friend master_test_suite_t& boost::unit_test::framework::master_test_suite(); }; // ************************************************************************** // diff --git a/boost/test/unit_test_monitor.hpp b/boost/test/unit_test_monitor.hpp index 1f937fa674..4402b79e73 100644 --- a/boost/test/unit_test_monitor.hpp +++ b/boost/test/unit_test_monitor.hpp @@ -34,7 +34,9 @@ class BOOST_TEST_DECL unit_test_monitor_t : public singleton<unit_test_monitor_t public: enum error_level { test_ok = 0, - precondition_failure = -1, + /// Indicates a failure to prepare the unit test (eg. fixture). Does not + /// account for tests skipped because of parent tests failed/skipped. + test_setup_failure = -1, unexpected_exception = -2, os_exception = -3, os_timeout = -4, diff --git a/boost/test/unit_test_parameters.hpp b/boost/test/unit_test_parameters.hpp index e01bbd7aed..e7e60d344f 100644 --- a/boost/test/unit_test_parameters.hpp +++ b/boost/test/unit_test_parameters.hpp @@ -112,11 +112,21 @@ public: if( stream_name == "stderr" ) { m_stream = &std::cerr; - m_cleaner.reset(); + if(cleaner_callback) { + m_cleaner = boost::make_shared<callback_cleaner>(cleaner_callback); + } + else { + m_cleaner.reset(); + } } else if( stream_name == "stdout" ) { m_stream = &std::cout; - m_cleaner.reset(); + if (cleaner_callback) { + m_cleaner = boost::make_shared<callback_cleaner>(cleaner_callback); + } + else { + m_cleaner.reset(); + } } else { m_cleaner = boost::make_shared<callback_cleaner>(cleaner_callback); diff --git a/boost/test/utils/basic_cstring/compare.hpp b/boost/test/utils/basic_cstring/compare.hpp index 2a256fc6be..b6dc15ab77 100644 --- a/boost/test/utils/basic_cstring/compare.hpp +++ b/boost/test/utils/basic_cstring/compare.hpp @@ -82,7 +82,7 @@ public: typedef bool result_type; typedef basic_cstring<CharT> first_argument_type; typedef basic_cstring<CharT> second_argument_type; - + bool operator()( basic_cstring<CharT> x, basic_cstring<CharT> y ) const { return x.size() != y.size() diff --git a/boost/test/utils/runtime/cla/parser.hpp b/boost/test/utils/runtime/cla/parser.hpp index a57091b474..de8943884b 100644 --- a/boost/test/utils/runtime/cla/parser.hpp +++ b/boost/test/utils/runtime/cla/parser.hpp @@ -211,10 +211,15 @@ public: curr_token.trim_left( name.size() ); + bool should_go_to_next = true; cstring value; + // Skip validations if parameter has optional value and we are at the end of token if( !value_separator.is_empty() || !found_param->p_has_optional_value ) { + + // we are given a separator or there is no optional value + // Validate and skip value separator in the input BOOST_TEST_I_ASSRT( found_id.m_value_separator == value_separator, format_error( found_param->p_name ) @@ -237,6 +242,40 @@ public: << found_param->p_name << " in the argument " << tr.current_token() ); } + else if( (value_separator.is_empty() && found_id.m_value_separator.empty()) ) { + // Deduce value source + value = curr_token; + if( value.is_empty() ) { + tr.next_token(); // tokenization broke the value, we check the next one + + if(!found_param->p_has_optional_value) { + // there is no separator and there is no optional value + // we look for the value on the next token + // example "-t XXXX" (no default) + // and we commit this value as being the passed value + value = tr.current_token(); + } + else { + // there is no separator and the value is optional + // we check the next token + // example "-c" (defaults to true) + // and commit this as the value if this is not a token + cstring value_check = tr.current_token(); + + cstring prefix_test, name_test, value_separator_test; + bool negative_form_test; + if( validate_token_format( value_check, prefix_test, name_test, value_separator_test, negative_form_test ) + && m_param_trie[prefix_test]) { + // this is a token, we consume what we have + should_go_to_next = false; + } + else { + // this is a value, we commit it + value = value_check; + } + } + } + } // Validate against argument duplication BOOST_TEST_I_ASSRT( !res.has( found_param->p_name ) || found_param->p_repeatable, @@ -248,7 +287,9 @@ public: // Produce argument value found_param->produce_argument( value, negative_form, res ); - tr.next_token(); + if(should_go_to_next) { + tr.next_token(); + } } // generate the remainder and return it's size |