diff options
Diffstat (limited to 'libs/variant/test')
-rw-r--r-- | libs/variant/test/Jamfile.v2 | 3 | ||||
-rw-r--r-- | libs/variant/test/auto_visitors.cpp | 321 | ||||
-rw-r--r-- | libs/variant/test/recursive_variant_test.cpp | 67 | ||||
-rw-r--r-- | libs/variant/test/rvalue_test.cpp | 17 | ||||
-rw-r--r-- | libs/variant/test/test8.cpp | 8 | ||||
-rw-r--r-- | libs/variant/test/variant_comparison_test.cpp | 35 | ||||
-rw-r--r-- | libs/variant/test/variant_get_test.cpp | 323 | ||||
-rw-r--r-- | libs/variant/test/variant_multivisit_test.cpp | 49 | ||||
-rw-r--r-- | libs/variant/test/variant_nonempty_check.cpp | 474 | ||||
-rw-r--r-- | libs/variant/test/variant_polymorphic_get_test.cpp | 29 |
10 files changed, 1309 insertions, 17 deletions
diff --git a/libs/variant/test/Jamfile.v2 b/libs/variant/test/Jamfile.v2 index 91b30595e..c861ac94f 100644 --- a/libs/variant/test/Jamfile.v2 +++ b/libs/variant/test/Jamfile.v2 @@ -28,10 +28,12 @@ test-suite variant [ run variant_reference_test.cpp ] [ run variant_comparison_test.cpp ] [ run variant_visit_test.cpp ] + [ run variant_get_test.cpp ] [ run variant_polymorphic_get_test.cpp ] [ run variant_multivisit_test.cpp ] [ run hash_variant_test.cpp ] [ run rvalue_test.cpp ] + [ run variant_nonempty_check.cpp ] [ run recursive_variant_test.cpp : : : <define>BOOST_NO_EXCEPTIONS <toolset>gcc-4.3:<cxxflags>-fno-exceptions <toolset>gcc-4.4:<cxxflags>-fno-exceptions @@ -44,6 +46,7 @@ test-suite variant ] [ run recursive_variant_test.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : variant_no_rtti_test ] [ run variant_swap_test.cpp ] + [ run auto_visitors.cpp ] ; diff --git a/libs/variant/test/auto_visitors.cpp b/libs/variant/test/auto_visitors.cpp new file mode 100644 index 000000000..84c91c9d2 --- /dev/null +++ b/libs/variant/test/auto_visitors.cpp @@ -0,0 +1,321 @@ +//----------------------------------------------------------------------------- +// boost-libs variant/test/auto_visitors.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2014-2015 Antony Polukhin +// +// 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) + +#include "boost/config.hpp" + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" +#include "boost/variant/multivisitors.hpp" +#include "boost/lexical_cast.hpp" + +struct lex_streamer_explicit: boost::static_visitor<std::string> { + template <class T> + const char* operator()(const T& ) { + return "10"; + } + + template <class T1, class T2> + const char* operator()(const T1& , const T2& ) { + return "100"; + } +}; + + +void run_explicit() +{ + typedef boost::variant<int, std::string, double> variant_type; + variant_type v2("10"), v1("100"); + + lex_streamer_explicit visitor_ref; + + // Must return instance of std::string + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2).c_str() == std::string("10")); + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1).c_str() == std::string("100")); +} + + +// Most part of tests from this file require decltype(auto) + +#ifdef BOOST_NO_CXX14_DECLTYPE_AUTO + +void run() +{ + BOOST_CHECK(true); +} + +void run2() +{ + BOOST_CHECK(true); +} + + +void run3() +{ + BOOST_CHECK(true); +} + +#else + +#include <iostream> + +struct lex_streamer { + template <class T> + std::string operator()(const T& val) const { + return boost::lexical_cast<std::string>(val); + } +}; + +struct lex_streamer_void { + template <class T> + void operator()(const T& val) const { + std::cout << val << std::endl; + } + + + template <class T1, class T2> + void operator()(const T1& val, const T2& val2) const { + std::cout << val << '+' << val2 << std::endl; + } + + + template <class T1, class T2, class T3> + void operator()(const T1& val, const T2& val2, const T3& val3) const { + std::cout << val << '+' << val2 << '+' << val3 << std::endl; + } +}; + + +struct lex_streamer2 { + std::string res; + + template <class T> + const char* operator()(const T& val) const { + return "fail"; + } + + template <class T1, class T2> + const char* operator()(const T1& v1, const T2& v2) const { + return "fail2"; + } + + + template <class T1, class T2, class T3> + const char* operator()(const T1& v1, const T2& v2, const T3& v3) const { + return "fail3"; + } + + template <class T> + std::string& operator()(const T& val) { + res = boost::lexical_cast<std::string>(val); + return res; + } + + + template <class T1, class T2> + std::string& operator()(const T1& v1, const T2& v2) { + res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2); + return res; + } + + + template <class T1, class T2, class T3> + std::string& operator()(const T1& v1, const T2& v2, const T3& v3) { + res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2) + + "+" + boost::lexical_cast<std::string>(v3); + return res; + } +}; + +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES +# define BOOST_CHECK_IF_HAS_VARIADIC(x) BOOST_CHECK(x) +#else +# define BOOST_CHECK_IF_HAS_VARIADIC(x) /**/ +#endif + +void run() +{ + typedef boost::variant<int, std::string, double> variant_type; + variant_type v1(1), v2("10"), v3(100.0); + lex_streamer lex_streamer_visitor; + + BOOST_CHECK(boost::apply_visitor(lex_streamer(), v1) == "1"); + BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v1) == "1"); + BOOST_CHECK(boost::apply_visitor(lex_streamer(), v2) == "10"); + BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v2) == "10"); + + #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS + BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v1) == "1"); + BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v2) == "10"); + + // Retun type must be the same in all instances, so this code does not compile + //boost::variant<int, short, unsigned> v_diff_types(1); + //BOOST_CHECK(boost::apply_visitor([](auto v) { return v; }, v_diff_types) == 1); + + boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v1); + boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v2); + #endif + + lex_streamer2 visitor_ref; + BOOST_CHECK(boost::apply_visitor(visitor_ref, v1) == "1"); + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2) == "10"); +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES + std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1); + BOOST_CHECK(ref_to_string == "1"); +#endif + lex_streamer_void lex_streamer_void_visitor; + boost::apply_visitor(lex_streamer_void(), v1); + boost::apply_visitor(lex_streamer_void(), v2); +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES + boost::apply_visitor(lex_streamer_void_visitor)(v2); +#endif +} + + +struct lex_combine { + template <class T1, class T2> + std::string operator()(const T1& v1, const T2& v2) const { + return boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2); + } + + + template <class T1, class T2, class T3> + std::string operator()(const T1& v1, const T2& v2, const T3& v3) const { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2) + '+' + + boost::lexical_cast<std::string>(v3); + } +}; + +void run2() +{ + typedef boost::variant<int, std::string, double> variant_type; + variant_type v1(1), v2("10"), v3(100.0); + lex_combine lex_combine_visitor; + + BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2) == "1+10"); + BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1) == "10+1"); + BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_combine_visitor)(v2, v1) == "10+1"); + + + #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2); + } + , v1 + , v2 + ) == "1+10" + ); + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2); + } + , v2 + , v1 + ) == "10+1" + ); + + boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v1, v2); + boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v2, v1); + #endif + + + lex_streamer2 visitor_ref; + BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1) == "10+1"); +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES + std::string& ref_to_string = boost::apply_visitor(visitor_ref)(v1, v2); + BOOST_CHECK(ref_to_string == "1+10"); +#endif + + boost::apply_visitor(lex_streamer_void(), v1, v2); + boost::apply_visitor(lex_streamer_void(), v2, v1); +} + +#undef BOOST_CHECK_IF_HAS_VARIADIC + +void run3() +{ +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + typedef boost::variant<int, std::string, double> variant_type; + variant_type v1(1), v2("10"), v3(100); + lex_combine lex_combine_visitor; + + BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2, v3) == "1+10+100"); + BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1, v3) == "10+1+100"); + BOOST_CHECK(boost::apply_visitor(lex_combine_visitor)(v2, v1, v3) == "10+1+100"); + + + #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2) + "+" + + boost::lexical_cast<std::string>(v3); + } + , v1 + , v2 + , v3 + ) == "1+10+100" + ); + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2) + "+" + + boost::lexical_cast<std::string>(v3); + } + , v3 + , v1 + , v3 + ) == "100+1+100" + ); + + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; }, + v1, v2, v3 + ); + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; }, + v2, v1, v3 + ); + #endif + + + lex_streamer2 visitor_ref; + BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); + BOOST_CHECK(boost::apply_visitor(visitor_ref)(v2, v1) == "10+1"); + std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1, v2); + BOOST_CHECK(ref_to_string == "1+10"); + + lex_streamer_void lex_streamer_void_visitor; + boost::apply_visitor(lex_streamer_void(), v1, v2, v1); + boost::apply_visitor(lex_streamer_void(), v2, v1, v1); + boost::apply_visitor(lex_streamer_void_visitor)(v2, v1, v1); +#endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) +} +#endif + + +int test_main(int , char* []) +{ + run_explicit(); + run(); + run2(); + run3(); + + return 0; +} diff --git a/libs/variant/test/recursive_variant_test.cpp b/libs/variant/test/recursive_variant_test.cpp index 8b6434801..fc9eaf2a5 100644 --- a/libs/variant/test/recursive_variant_test.cpp +++ b/libs/variant/test/recursive_variant_test.cpp @@ -129,6 +129,43 @@ void test_recursive_variant() std::cout << "result1: " << result1 << '\n'; BOOST_CHECK(result1 == "( 3 5 ( 3 5 ) 7 ) "); + std::vector<var1_t> vec1_copy = vec1; + vec1_copy.erase(vec1_copy.begin() + 2); + vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy); + var1 = vec1_copy; + result1 = printer()(var1); + std::cout << "result1+: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + // Uses move construction on compilers with rvalue references support + result1 = printer()( + var1_t( + std::vector<var1_t>(vec1_copy) + ) + ); + std::cout << "result1++: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + + var1_t vec1_another_copy(vec1_copy); + vec1_copy[2].swap(vec1_another_copy); + result1 = printer()( + var1_t(vec1_copy) + ); + std::cout << "result1+++1: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); + + result1 = printer()(vec1_another_copy); + std::cout << "result1++2: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 7 ) "); + + vec1_copy[2].swap(vec1_copy[2]); + result1 = printer()( + var1_t(vec1_copy) + ); + std::cout << "result1.2: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); + typedef boost::make_recursive_variant< boost::variant<int, double> , std::vector<boost::recursive_variant_> @@ -231,6 +268,36 @@ void test_recursive_variant_over() std::cout << "result1: " << result1 << '\n'; BOOST_CHECK(result1 == "( 3 5 ( 3 5 ) 7 ) "); + std::vector<var1_t> vec1_copy = vec1; + vec1_copy.erase(vec1_copy.begin() + 2); + vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy); + var1 = vec1_copy; + result1 = printer()(var1); + std::cout << "result1+: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + // Uses move construction on compilers with rvalue references support + result1 = printer()( + var1_t( + std::vector<var1_t>(vec1_copy) + ) + ); + std::cout << "result1++: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + + var1_t vec1_another_copy(vec1_copy); + vec1_copy[2].swap(vec1_another_copy); + result1 = printer()( + var1_t(vec1_copy) + ); + std::cout << "result1+++1: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); + + result1 = printer()(vec1_another_copy); + std::cout << "result1++2: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 7 ) "); + typedef boost::make_recursive_variant_over< boost::mpl::vector< boost::make_variant_over<boost::mpl::vector<int, double> >::type diff --git a/libs/variant/test/rvalue_test.cpp b/libs/variant/test/rvalue_test.cpp index d2d849a55..8ef9d3971 100644 --- a/libs/variant/test/rvalue_test.cpp +++ b/libs/variant/test/rvalue_test.cpp @@ -16,8 +16,22 @@ #include "boost/type_traits/is_nothrow_move_assignable.hpp" #include "boost/mpl/bool.hpp" -// Most part of tests from this file require rvalue references support +#include <boost/blank.hpp> +#include <boost/swap.hpp> + +namespace swap_ambiguouty_test_ns { + struct A {}; + struct B {}; + + void swap_ambiguouty_test() { + // If boost::blank is not used, then it compiles. + typedef boost::variant<boost::blank, A, B> Variant; + Variant v1, v2; + swap(v1, v2); + } +} // namespace swap_ambiguouty_test_ns +// Most part of tests from this file require rvalue references support class move_copy_conting_class { public: @@ -288,6 +302,7 @@ void run_is_container_compilation_test() int test_main(int , char* []) { + swap_ambiguouty_test_ns::swap_ambiguouty_test(); run(); run1(); run_move_only(); diff --git a/libs/variant/test/test8.cpp b/libs/variant/test/test8.cpp index 0e64ba0d7..d228b4c6b 100644 --- a/libs/variant/test/test8.cpp +++ b/libs/variant/test/test8.cpp @@ -58,17 +58,17 @@ T& check_pass(Variant& v, T value) template <typename T, typename Variant> void check_fail(Variant& v) { - BOOST_CHECK(!get<T>(&v)); + BOOST_CHECK(!relaxed_get<T>(&v)); try { - T& r = get<T>(v); + T& r = relaxed_get<T>(v); (void)r; // suppress warning about r not being used BOOST_CHECK(false && &r); // should never reach } - catch(boost::bad_get&) + catch(const boost::bad_get& e) { - // (do nothing here) + BOOST_CHECK(!!e.what()); // make sure that what() is const qualified and returnes something } } diff --git a/libs/variant/test/variant_comparison_test.cpp b/libs/variant/test/variant_comparison_test.cpp index f04d2575c..3f6cc4176 100644 --- a/libs/variant/test/variant_comparison_test.cpp +++ b/libs/variant/test/variant_comparison_test.cpp @@ -3,8 +3,8 @@ // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2003 -// Eric Friedman, Itay Maman +// Copyright (c) 2003 Eric Friedman, Itay Maman +// Copyright (c) 2014 Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -34,6 +34,9 @@ void assert_equality_comparable( BOOST_CHECK( !(&x == &y) || (x == y) ); BOOST_CHECK( !(&x == &z) || (x == z) ); BOOST_CHECK( !(&y == &z) || (y == z) ); + BOOST_CHECK( !(&x == &y) || !(x != y) ); + BOOST_CHECK( !(&x == &z) || !(x != z) ); + BOOST_CHECK( !(&y == &z) || !(y != z) ); // reflexivity check BOOST_CHECK( (x == x) ); @@ -43,12 +46,18 @@ void assert_equality_comparable( // symmetry check BOOST_CHECK( !(x == y) || (y == x) ); BOOST_CHECK( !(y == x) || (x == y) ); + BOOST_CHECK( (x != y) || (y == x) ); + BOOST_CHECK( (y != x) || (x == y) ); BOOST_CHECK( !(x == z) || (z == x) ); BOOST_CHECK( !(z == x) || (x == z) ); + BOOST_CHECK( (x != z) || (z == x) ); + BOOST_CHECK( (z != x) || (x == z) ); BOOST_CHECK( !(y == z) || (z == y) ); BOOST_CHECK( !(z == y) || (y == z) ); + BOOST_CHECK( (y != z) || (z == y) ); + BOOST_CHECK( (z != y) || (y == z) ); // transitivity check BOOST_CHECK( !(x == y && y == z) || (x == z) ); @@ -65,12 +74,34 @@ void assert_less_than_comparable( BOOST_CHECK( !(x < x) ); BOOST_CHECK( !(y < y) ); BOOST_CHECK( !(z < z) ); + BOOST_CHECK( !(x > x) ); + BOOST_CHECK( !(y > y) ); + BOOST_CHECK( !(z > z) ); + + BOOST_CHECK( (x <= x) ); + BOOST_CHECK( (y <= y) ); + BOOST_CHECK( (z <= z) ); + BOOST_CHECK( (x >= x) ); + BOOST_CHECK( (y >= y) ); + BOOST_CHECK( (z >= z) ); // transitivity check BOOST_CHECK( (x < y) ); BOOST_CHECK( (y < z) ); BOOST_CHECK( (x < z) ); + BOOST_CHECK( (x <= y) ); + BOOST_CHECK( (y <= z) ); + BOOST_CHECK( (x <= z) ); + + BOOST_CHECK( (z > y) ); + BOOST_CHECK( (y > x) ); + BOOST_CHECK( (z > x) ); + + BOOST_CHECK( (z >= y) ); + BOOST_CHECK( (y >= x) ); + BOOST_CHECK( (z >= x) ); + // antisymmetry check BOOST_CHECK( !(y < x) ); BOOST_CHECK( !(z < y) ); diff --git a/libs/variant/test/variant_get_test.cpp b/libs/variant/test/variant_get_test.cpp new file mode 100644 index 000000000..69b613729 --- /dev/null +++ b/libs/variant/test/variant_get_test.cpp @@ -0,0 +1,323 @@ +//----------------------------------------------------------------------------- +// boost-libs variant/test/variant_get_test.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2014 Antony Polukhin +// +// 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) + +#include "boost/variant/variant.hpp" +#include "boost/variant/get.hpp" +#include "boost/variant/polymorphic_get.hpp" +#include "boost/variant/recursive_wrapper.hpp" +#include "boost/test/minimal.hpp" + +struct base { + int trash; + + base() : trash(123) {} + base(const base& b) : trash(b.trash) { int i = 100; (void)i; } + const base& operator=(const base& b) { + trash = b.trash; + int i = 100; (void)i; + + return *this; + } + + virtual ~base(){} +}; + +struct derived1 : base{}; +struct derived2 : base{}; + +struct vbase { short trash; virtual ~vbase(){} virtual int foo() const { return 0; } }; +struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } }; +struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } }; +struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } }; + +typedef boost::variant<int, base, derived1, derived2, std::string> var_t; +typedef boost::variant<int, derived1, derived2, std::string> var_t_shortened; +typedef boost::variant<base, derived1, derived2> var_t_no_fallback; +typedef boost::variant<int&, base&, derived1&, derived2&, std::string&> var_ref_t; +typedef boost::variant<const int&, const base&, const derived1&, const derived2&, const std::string&> var_cref_t; + +struct recursive_structure; +typedef boost::variant< + int, base, derived1, derived2, std::string, boost::recursive_wrapper<recursive_structure> +> var_req_t; +struct recursive_structure { var_req_t var; }; + +template <class T, class V, class TestType> +inline void check_polymorphic_get_on_types_impl_single_type(V* v) +{ + if (!!boost::is_same<T, TestType>::value) { + BOOST_CHECK(boost::polymorphic_get<TestType>(v)); + BOOST_CHECK(boost::polymorphic_get<const TestType>(v)); + BOOST_CHECK(boost::polymorphic_strict_get<TestType>(v)); + BOOST_CHECK(boost::polymorphic_strict_get<const TestType>(v)); + BOOST_CHECK(boost::polymorphic_relaxed_get<TestType>(v)); + BOOST_CHECK(boost::polymorphic_relaxed_get<const TestType>(v)); + } else { + BOOST_CHECK(!boost::polymorphic_get<TestType>(v)); + BOOST_CHECK(!boost::polymorphic_get<const TestType>(v)); + BOOST_CHECK(!boost::polymorphic_strict_get<TestType>(v)); + BOOST_CHECK(!boost::polymorphic_strict_get<const TestType>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<TestType>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<const TestType>(v)); + } +} + +template <class T, class V, class TestType> +inline void check_get_on_types_impl_single_type(V* v) +{ + if (!!boost::is_same<T, TestType>::value) { + BOOST_CHECK(boost::get<TestType>(v)); + BOOST_CHECK(boost::get<const TestType>(v)); + BOOST_CHECK(boost::strict_get<TestType>(v)); + BOOST_CHECK(boost::strict_get<const TestType>(v)); + BOOST_CHECK(boost::relaxed_get<TestType>(v)); + BOOST_CHECK(boost::relaxed_get<const TestType>(v)); + } else { + BOOST_CHECK(!boost::get<TestType>(v)); + BOOST_CHECK(!boost::get<const TestType>(v)); + BOOST_CHECK(!boost::strict_get<TestType>(v)); + BOOST_CHECK(!boost::strict_get<const TestType>(v)); + BOOST_CHECK(!boost::relaxed_get<TestType>(v)); + BOOST_CHECK(!boost::relaxed_get<const TestType>(v)); + } +} + +template <class T, class V> +inline void check_get_on_types_impl(V* v) +{ + check_get_on_types_impl_single_type<T, V, int>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, int>(v); + + check_get_on_types_impl_single_type<T, V, base>(v); + + check_get_on_types_impl_single_type<T, V, derived1>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, derived1>(v); + + check_get_on_types_impl_single_type<T, V, derived2>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, derived2>(v); + + check_get_on_types_impl_single_type<T, V, std::string>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, std::string>(v); + + // Never exist in here + BOOST_CHECK(!boost::relaxed_get<short>(v)); + BOOST_CHECK(!boost::relaxed_get<const short>(v)); + BOOST_CHECK(!boost::relaxed_get<char>(v)); + BOOST_CHECK(!boost::relaxed_get<char*>(v)); + BOOST_CHECK(!boost::relaxed_get<bool>(v)); + BOOST_CHECK(!boost::relaxed_get<const bool>(v)); + + BOOST_CHECK(!boost::polymorphic_relaxed_get<short>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<const short>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<char>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<char*>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<bool>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<const bool>(v)); + + boost::get<T>(*v); // Must compile + boost::get<const T>(*v); // Must compile + boost::strict_get<T>(*v); // Must compile + boost::strict_get<const T>(*v); // Must compile + + boost::polymorphic_get<T>(*v); // Must compile + boost::polymorphic_get<const T>(*v); // Must compile + boost::polymorphic_strict_get<T>(*v); // Must compile + boost::polymorphic_strict_get<const T>(*v); // Must compile +} + +template <class T, class V> +inline void check_get_on_types(V* v) +{ + check_get_on_types_impl<T, V>(v); + check_get_on_types_impl<T, const V>(v); +} + +inline void get_test() +{ + var_t v; + check_get_on_types<int>(&v); + + var_t(base()).swap(v); + check_get_on_types<base>(&v); + + var_t(derived1()).swap(v); + check_get_on_types<derived1>(&v); + + var_t(derived2()).swap(v); + check_get_on_types<derived2>(&v); + + var_t(std::string("Hello")).swap(v); + check_get_on_types<std::string>(&v); + + var_t_shortened vs = derived2(); + check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs); + check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs); + // Checking that Base is really determinated + check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs); + + vs = derived1(); + check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs); + check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs); + // Checking that Base is really determinated + check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs); +} + +inline void get_test_no_fallback() +{ + var_t_no_fallback v; + var_t_no_fallback(base()).swap(v); + check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + + var_t_no_fallback(derived1()).swap(v); + check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<derived1, var_t_no_fallback, derived1>(&v); + check_get_on_types_impl_single_type<derived1, const var_t_no_fallback, derived1>(&v); + + var_t_no_fallback(derived2()).swap(v); + check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<derived2, var_t_no_fallback, derived2>(&v); + check_get_on_types_impl_single_type<derived2, const var_t_no_fallback, derived2>(&v); +} + +inline void get_ref_test() +{ + int i = 0; + var_ref_t v(i); + check_get_on_types<int>(&v); + + base b; + var_ref_t v1(b); + check_get_on_types<base>(&v1); + + derived1 d1; + var_ref_t v2(d1); + check_get_on_types<derived1>(&v2); + + derived2 d2; + var_ref_t v3(d2); + check_get_on_types<derived2>(&v3); + + std::string s("Hello"); + var_ref_t v4(s); + check_get_on_types<std::string>(&v4); +} + + +inline void get_cref_test() +{ + int i = 0; + var_cref_t v(i); + BOOST_CHECK(boost::get<const int>(&v)); + BOOST_CHECK(!boost::get<const base>(&v)); + + base b; + var_cref_t v1(b); + BOOST_CHECK(boost::get<const base>(&v1)); + BOOST_CHECK(!boost::get<const derived1>(&v1)); + BOOST_CHECK(!boost::get<const int>(&v1)); + + std::string s("Hello"); + const var_cref_t v4 = s; + BOOST_CHECK(boost::get<const std::string>(&v4)); + BOOST_CHECK(!boost::get<const int>(&v4)); +} + +inline void get_recursive_test() +{ + var_req_t v; + check_get_on_types<int>(&v); + + var_req_t(base()).swap(v); + check_get_on_types<base>(&v); + + var_req_t(derived1()).swap(v); + check_get_on_types<derived1>(&v); + + var_req_t(derived2()).swap(v); + check_get_on_types<derived2>(&v); + + var_req_t(std::string("Hello")).swap(v); + check_get_on_types<std::string>(&v); + + recursive_structure s = { v }; // copying "v" + v = s; + check_get_on_types<recursive_structure>(&v); +} + +template <class T> +inline void check_that_does_not_exist_impl() +{ + using namespace boost::detail::variant; + + BOOST_CHECK((holds_element<T, const int>::value)); + BOOST_CHECK((!holds_element<T, short>::value)); + BOOST_CHECK((!holds_element<T, short>::value)); + BOOST_CHECK((!holds_element<T, const short>::value)); + BOOST_CHECK((!holds_element<T, char*>::value)); + BOOST_CHECK((!holds_element<T, const char*>::value)); + BOOST_CHECK((!holds_element<T, char[5]>::value)); + BOOST_CHECK((!holds_element<T, const char[5]>::value)); + BOOST_CHECK((!holds_element<T, bool>::value)); + BOOST_CHECK((!holds_element<T, const bool>::value)); + + BOOST_CHECK((!holds_element<T, boost::recursive_wrapper<int> >::value)); + BOOST_CHECK((!holds_element<T, boost::recursive_wrapper<short> >::value)); + BOOST_CHECK((!holds_element<T, boost::detail::reference_content<short> >::value)); + + + BOOST_CHECK((holds_element_polymorphic<T, const int>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, short>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, short>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const short>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, char*>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const char*>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, char[5]>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const char[5]>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, bool>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const bool>::value)); + + BOOST_CHECK((!holds_element_polymorphic<T, boost::recursive_wrapper<int> >::value)); + BOOST_CHECK((!holds_element_polymorphic<T, boost::recursive_wrapper<short> >::value)); + BOOST_CHECK((!holds_element_polymorphic<T, boost::detail::reference_content<short> >::value)); +} + +inline void check_that_does_not_exist() +{ + using namespace boost::detail::variant; + + BOOST_CHECK((holds_element<var_t, int>::value)); + BOOST_CHECK((holds_element<var_ref_t, int>::value)); + BOOST_CHECK((!holds_element<var_cref_t, int>::value)); + + check_that_does_not_exist_impl<var_t>(); + check_that_does_not_exist_impl<var_ref_t>(); + check_that_does_not_exist_impl<var_cref_t>(); + check_that_does_not_exist_impl<var_req_t>(); +} + +int test_main(int , char* []) +{ + get_test(); + get_test_no_fallback(); + get_ref_test(); + get_cref_test(); + get_recursive_test(); + check_that_does_not_exist(); + + return boost::exit_success; +} diff --git a/libs/variant/test/variant_multivisit_test.cpp b/libs/variant/test/variant_multivisit_test.cpp index ddcbe02da..8fc3ebe82 100644 --- a/libs/variant/test/variant_multivisit_test.cpp +++ b/libs/variant/test/variant_multivisit_test.cpp @@ -3,37 +3,46 @@ // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2013 -// Antony Polukhin +// Copyright (c) 2013-2015 Antony Polukhin // // 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) #include "boost/config.hpp" +#include "boost/noncopyable.hpp" #define BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS 5 #include "boost/variant/multivisitors.hpp" +#include "boost/variant.hpp" #include "boost/test/minimal.hpp" +struct my_noncopyable : boost::noncopyable { + my_noncopyable(){} + ~my_noncopyable(){} +}; + +typedef boost::variant<my_noncopyable, int> variant_noncopy_t; + + typedef boost::variant<char, unsigned char, signed char, unsigned short, int, unsigned int> variant6_t; struct test_visitor: boost::static_visitor<> { // operators that shall not be called template <class T1, class T2, class T3> - void operator()(T1, T2, T3) const + void operator()(T1&, T2&, T3&) const { BOOST_CHECK(false); } template <class T1, class T2, class T3, class T4> - void operator()(T1, T2, T3, T4) const + void operator()(T1&, T2&, T3&, T4&) const { BOOST_CHECK(false); } template <class T1, class T2, class T3, class T4, class T5> - void operator()(T1, T2, T3, T4, T5) const + void operator()(T1&, T2&, T3&, T4&, T5&) const { BOOST_CHECK(false); } @@ -62,6 +71,21 @@ struct test_visitor: boost::static_visitor<> { BOOST_CHECK(v3 == 3); BOOST_CHECK(v4 == 4); } + + + // Noncopyables + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } }; typedef boost::variant<int, double, bool> bool_like_t; @@ -112,13 +136,24 @@ int test_main(int , char* []) arithmetics_t(true) ); - /* Delayed multi visitation is not implemented +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) if_visitor if_vis; BOOST_CHECK( boost::apply_visitor(if_vis)(v0, v1, v2) == arithmetics_t(true) ); - */ +#endif + + + variant_noncopy_t vnonc[6]; + boost::apply_visitor(v, vnonc[0], vnonc[1], vnonc[2]); + boost::apply_visitor(test_visitor(), vnonc[0], vnonc[1], vnonc[2], vnonc[3]); + +#ifdef BOOST_VARIANT_MULTIVISITORS_TEST_VERY_EXTREME + boost::apply_visitor(v, vnonc[0], vnonc[1], vnonc[2], vnonc[3], vnonc[4]); + boost::apply_visitor(test_visitor(), vnonc[0], vnonc[1], vnonc[2], vnonc[3], vnonc[4], vnonc[5]); +#endif + return boost::exit_success; } diff --git a/libs/variant/test/variant_nonempty_check.cpp b/libs/variant/test/variant_nonempty_check.cpp new file mode 100644 index 000000000..de643b862 --- /dev/null +++ b/libs/variant/test/variant_nonempty_check.cpp @@ -0,0 +1,474 @@ +//----------------------------------------------------------------------------- +// boost-libs variant/test/variant_nonempty_check.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2014 Antony Polukhin +// +// 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) + + +// In this file we are making tests to ensure that variant guarantees nonemptiness. +// +// For that purpose we create a `throwing_class`, that throws exception at a specified +// assignment attempt. If exception was thrown during move/assignemnt operation we make sure +// that data in variant is same as before move/assignemnt operation or that a fallback type is +// stored in variant. +// +// Different nonthrowing_class'es are used to tests different variant internal policies: +// with/without fallback type + throw/nothrow copyable + throw/nothrow movable + + +#include "boost/variant/variant.hpp" +#include "boost/variant/get.hpp" +#include "boost/test/minimal.hpp" +#include <stdexcept> + +struct exception_on_assignment : std::exception {}; +struct exception_on_move_assignment : exception_on_assignment {}; + +void prevent_compiler_noexcept_detection() { + char* p = new char; + *p = '\0'; + delete p; +} + + +struct throwing_class { + int trash; + enum helper_enum { + do_not_throw = 780, + throw_after_5, + throw_after_4, + throw_after_3, + throw_after_2, + throw_after_1 + }; + + bool is_throw() { + if (trash < do_not_throw) { + return true; + } + + if (trash > do_not_throw && trash <= throw_after_1) { + ++ trash; + return false; + } + + return trash != do_not_throw; + } + + throwing_class(int value = 123) BOOST_NOEXCEPT_IF(false) : trash(value) { + prevent_compiler_noexcept_detection(); + } + + throwing_class(const throwing_class& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) { + if (is_throw()) { + throw exception_on_assignment(); + } + } + + const throwing_class& operator=(const throwing_class& b) BOOST_NOEXCEPT_IF(false) { + trash = b.trash; + if (is_throw()) { + throw exception_on_assignment(); + } + + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + throwing_class(throwing_class&& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) { + if (is_throw()) { + throw exception_on_move_assignment(); + } + } + + const throwing_class& operator=(throwing_class&& b) BOOST_NOEXCEPT_IF(false) { + trash = b.trash; + if (is_throw()) { + throw exception_on_move_assignment(); + } + + return *this; + } +#endif + + virtual ~throwing_class() {} +}; + +struct nonthrowing_class { + int trash; + + nonthrowing_class() BOOST_NOEXCEPT_IF(false) : trash(123) { + prevent_compiler_noexcept_detection(); + } + + nonthrowing_class(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class& operator=(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + nonthrowing_class(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class& operator=(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } +#endif +}; + +struct nonthrowing_class2 { + int trash; + + nonthrowing_class2() BOOST_NOEXCEPT_IF(false) : trash(123) { + prevent_compiler_noexcept_detection(); + } +}; + +struct nonthrowing_class3 { + int trash; + + nonthrowing_class3() BOOST_NOEXCEPT_IF(true) : trash(123) {} + + nonthrowing_class3(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class3& operator=(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + nonthrowing_class3(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class3& operator=(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } +#endif +}; + +struct nonthrowing_class4 { + int trash; + + nonthrowing_class4() BOOST_NOEXCEPT_IF(false) : trash(123) { + prevent_compiler_noexcept_detection(); + } + + nonthrowing_class4(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class4& operator=(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + nonthrowing_class4(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) { + } + + const nonthrowing_class4& operator=(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) { + return *this; + } +#endif +}; + + +// Tests ///////////////////////////////////////////////////////////////////////////////////// + + +template <class Nonthrowing> +inline void check_1_impl(int helper) +{ + boost::variant<throwing_class, Nonthrowing> v; + try { + v = throwing_class(helper); + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } + + try { + throwing_class tc(helper); + v = tc; + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } +} + +inline void check_1(int helper = 1) +{ + check_1_impl<nonthrowing_class>(helper); + check_1_impl<nonthrowing_class2>(helper); + check_1_impl<nonthrowing_class3>(helper); + check_1_impl<nonthrowing_class4>(helper); + check_1_impl<boost::blank>(helper); +} + +template <class Nonthrowing> +inline void check_2_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v; + try { + v = throwing_class(helper); + BOOST_CHECK(v.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v)); + } + + try { + throwing_class cl(helper); + v = cl; + BOOST_CHECK(v.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v)); + } +} + +inline void check_2(int helper = 1) +{ + check_2_impl<nonthrowing_class>(helper); + check_2_impl<nonthrowing_class2>(helper); + check_2_impl<nonthrowing_class3>(helper); + check_2_impl<nonthrowing_class4>(helper); + check_2_impl<boost::blank>(helper); +} + +template <class Nonthrowing> +inline void check_3_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v1, v2; + + swap(v1, v2); + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v1)); + } + + + try { + v2 = throwing_class(helper); + BOOST_CHECK(v2.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v2)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v2)); + } + + + if (!v1.which() && !v2.which()) { + swap(v1, v2); // Make sure that two backup holders swap well + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v1)); + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v2)); + + v1 = v2; + } +} + +inline void check_3(int helper = 1) +{ + check_3_impl<nonthrowing_class>(helper); + check_3_impl<nonthrowing_class2>(helper); + check_3_impl<nonthrowing_class3>(helper); + check_3_impl<nonthrowing_class4>(helper); + check_3_impl<boost::blank>(helper); +} + +inline void check_4(int helper = 1) +{ + // This one has a fallback + boost::variant<int, throwing_class> v1, v2; + + swap(v1, v2); + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<int>(&v1)); + } + + + try { + v2 = throwing_class(helper); + BOOST_CHECK(v2.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v2)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<int>(&v2)); + } + + if (!v1.which() && !v2.which()) { + swap(v1, v2); + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<int>(&v1)); + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<int>(&v2)); + + v1 = v2; + } +} + +template <class Nonthrowing> +inline void check_5_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v1, v2; + throwing_class throw_not_now; + throw_not_now.trash = throwing_class::do_not_throw; + v1 = throw_not_now; + v2 = throw_not_now; + + boost::get<throwing_class>(v1).trash = 1; + boost::get<throwing_class>(v2).trash = 1; + + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } + + boost::get<throwing_class>(v1).trash = throwing_class::do_not_throw; + boost::get<throwing_class>(v2).trash = throwing_class::do_not_throw; + v1 = Nonthrowing(); + v2 = Nonthrowing(); + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 0); + BOOST_CHECK(boost::get<Nonthrowing>(&v1)); + } + + int v1_type = v1.which(); + int v2_type = v2.which(); + try { + swap(v1, v2); // Make sure that backup holders swap well + BOOST_CHECK(v1.which() == v2_type); + BOOST_CHECK(v2.which() == v1_type); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == v1_type); + BOOST_CHECK(v2.which() == v2_type); + } +} + + +inline void check_5(int helper = 1) +{ + check_5_impl<nonthrowing_class>(helper); + check_5_impl<nonthrowing_class2>(helper); + check_5_impl<nonthrowing_class3>(helper); + check_5_impl<nonthrowing_class4>(helper); + check_5_impl<boost::blank>(helper); +} + +template <class Nonthrowing> +inline void check_6_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v1, v2; + throwing_class throw_not_now; + throw_not_now.trash = throwing_class::do_not_throw; + v1 = throw_not_now; + v2 = throw_not_now; + + v1 = throw_not_now; + v2 = throw_not_now; + swap(v1, v2); + boost::get<throwing_class>(v1).trash = 1; + boost::get<throwing_class>(v2).trash = 1; + + v1 = throwing_class(throw_not_now); + v2 = v1; + + v1 = Nonthrowing(); + try { + throwing_class tc; + tc.trash = helper; + v1 = tc; + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 0); + } + + v2 = Nonthrowing(); + try { + v2 = 2; + BOOST_CHECK(false); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v2.which() == 0); + } + + // Probably the most significant test: + // unsuccessful swap must preserve old values of vaiant + v1 = throw_not_now; + boost::get<throwing_class>(v1).trash = helper; + try { + swap(v1, v2); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(v2.which() == 0); + BOOST_CHECK(boost::get<throwing_class>(v1).trash == helper); + } +} + + +inline void check_6(int helper = 1) +{ + check_6_impl<nonthrowing_class>(helper); + check_6_impl<nonthrowing_class2>(helper); + check_6_impl<nonthrowing_class3>(helper); + check_6_impl<nonthrowing_class4>(helper); + check_6_impl<boost::blank>(helper); +} + +int test_main(int , char* []) +{ + // throwing_class::throw_after_1 + 1 => throw on first assignment/construction + // throwing_class::throw_after_1 => throw on second assignment/construction + // throwing_class::throw_after_2 => throw on third assignment/construction + // ... + for (int i = throwing_class::throw_after_1 + 1; i != throwing_class::do_not_throw; --i) { + check_1(i); + check_2(i); + check_3(i); + check_4(i); + check_5(i); + check_6(i); + } + + return boost::exit_success; +} diff --git a/libs/variant/test/variant_polymorphic_get_test.cpp b/libs/variant/test/variant_polymorphic_get_test.cpp index d4e6fe4a9..43fc7b6b9 100644 --- a/libs/variant/test/variant_polymorphic_get_test.cpp +++ b/libs/variant/test/variant_polymorphic_get_test.cpp @@ -1,10 +1,10 @@ //----------------------------------------------------------------------------- -// boost-libs variant/test/variant_visit_test.cpp source file +// boost-libs variant/test/variant_plymorphic_get_test.cpp source file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2003 -// Eric Friedman +// Copyright (c) 2003 Eric Friedman +// Copyright (c) 2013-2014 Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -25,24 +25,44 @@ struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } }; struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } }; struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } }; +template <class T, class Variant> +inline void check_throws(Variant& v) { + try { + boost::polymorphic_get<T>(v); + BOOST_CHECK(false); + } catch (const boost::bad_polymorphic_get& e) { + BOOST_CHECK(!!e.what()); + BOOST_CHECK(std::string(e.what()) != boost::bad_get().what()); + } +} + int test_main(int , char* []) { typedef boost::variant<int, base, derived1, derived2> var_t; var_t var1; BOOST_CHECK(!boost::polymorphic_get<base>(&var1)); + check_throws<base>(var1); + BOOST_CHECK(!boost::polymorphic_get<const base>(&var1)); + check_throws<base, const var_t>(var1); var1 = derived1(); BOOST_CHECK(boost::polymorphic_get<base>(&var1)); + BOOST_CHECK(boost::polymorphic_get<const base>(&var1)); derived2 d; d.trash = 777; var_t var2 = d; BOOST_CHECK(boost::polymorphic_get<base>(var2).trash == 777); + BOOST_CHECK(boost::polymorphic_get<const base>(var2).trash == 777); var2 = 777; BOOST_CHECK(!boost::polymorphic_get<base>(&var2)); + check_throws<base>(var2); + BOOST_CHECK(!boost::polymorphic_get<const base>(&var2)); + check_throws<base, const var_t>(var2); BOOST_CHECK(boost::polymorphic_get<int>(var2) == 777); + BOOST_CHECK(boost::polymorphic_get<const int>(var2) == 777); typedef boost::variant<int, vbase, vderived1, vderived2, vderived3> vvar_t; @@ -50,9 +70,12 @@ int test_main(int , char* []) boost::polymorphic_get<vderived3>(v).trash = 777; const vvar_t& cv = v; BOOST_CHECK(boost::polymorphic_get<vbase>(cv).trash == 777); + BOOST_CHECK(boost::polymorphic_get<const vbase>(cv).trash == 777); BOOST_CHECK(boost::polymorphic_get<vbase>(cv).foo() == 3); BOOST_CHECK(boost::polymorphic_get<vbase>(v).foo() == 3); + BOOST_CHECK(boost::polymorphic_get<const vbase>(cv).foo() == 3); + BOOST_CHECK(boost::polymorphic_get<const vbase>(v).foo() == 3); return boost::exit_success; } |