diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 63045c5..4876b41 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,6 +17,7 @@ import testing ; { test-suite optional : [ run optional_test.cpp ] + [ run optional_test_swap.cpp ] [ run optional_test_conversions_from_U.cpp ] [ run optional_test_tie.cpp ] [ run optional_test_ref_assign_portable_minimum.cpp ] diff --git a/test/optional_test.cpp b/test/optional_test.cpp index 1247965..3591867 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -907,337 +907,6 @@ void test_no_implicit_conversions() } - -namespace optional_swap_test -{ - class default_ctor_exception : public std::exception {} ; - class copy_ctor_exception : public std::exception {} ; - class assignment_exception : public std::exception {} ; - - // - // Base class for swap test classes. Its assignment should not be called, when swapping - // optional objects. (The default std::swap would do so.) - // - class base_class_with_forbidden_assignment - { - public: - base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &) - { - BOOST_CHECK(!"The assignment should not be used while swapping!"); - throw assignment_exception(); - } - - virtual ~base_class_with_forbidden_assignment() {} - }; - - // - // Class without default constructor - // - class class_without_default_ctor : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_without_default_ctor(char arg) : data(arg) {} - }; - - // - // Class whose default constructor should not be used by optional::swap! - // - class class_whose_default_ctor_should_not_be_used : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_whose_default_ctor_should_not_be_used(char arg) : data(arg) {} - - class_whose_default_ctor_should_not_be_used() - { - BOOST_CHECK(!"This default constructor should not be used while swapping!"); - throw default_ctor_exception(); - } - }; - - // - // Class whose default constructor should be used by optional::swap. - // Its copy constructor should be avoided! - // - class class_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_whose_default_ctor_should_be_used(char arg) : data(arg) { } - - class_whose_default_ctor_should_be_used() : data('\0') { } - - class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &) - { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); - throw copy_ctor_exception(); - } - }; - - // - // Class template whose default constructor should be used by optional::swap. - // Its copy constructor should be avoided! - // - template - class template_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment - { - public: - T data; - explicit template_whose_default_ctor_should_be_used(T arg) : data(arg) { } - - template_whose_default_ctor_should_be_used() : data('\0') { } - - template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &) - { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); - throw copy_ctor_exception(); - } - }; - - // - // Class whose explicit constructor should be used by optional::swap. - // Its other constructors should be avoided! - // - class class_whose_explicit_ctor_should_be_used : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_whose_explicit_ctor_should_be_used(char arg) : data(arg) { } - - class_whose_explicit_ctor_should_be_used() - { - BOOST_CHECK(!"This default constructor should not be used while swapping!"); - throw default_ctor_exception(); - } - - class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &) - { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); - throw copy_ctor_exception(); - } - }; - - void swap(class_whose_default_ctor_should_not_be_used & lhs, class_whose_default_ctor_should_not_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - void swap(class_whose_default_ctor_should_be_used & lhs, class_whose_default_ctor_should_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - void swap(class_without_default_ctor & lhs, class_without_default_ctor & rhs) - { - std::swap(lhs.data, rhs.data); - } - - void swap(class_whose_explicit_ctor_should_be_used & lhs, class_whose_explicit_ctor_should_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - template - void swap(template_whose_default_ctor_should_be_used & lhs, template_whose_default_ctor_should_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - // - // optional::swap should be customized when neither the copy constructor - // nor the default constructor of T are supposed to be used when swapping, e.g., - // for the following type T = class_whose_explicit_ctor_should_be_used. - // - void swap(boost::optional & x, boost::optional & y) - { - bool hasX(x); - bool hasY(y); - - if ( !hasX && !hasY ) - return; - - if( !hasX ) - x = boost::in_place('\0'); - else if ( !hasY ) - y = boost::in_place('\0'); - - optional_swap_test::swap(*x,*y); - - if( !hasX ) - y = boost::none ; - else if( !hasY ) - x = boost::none ; - } - - -} // End of namespace optional_swap_test. - - -namespace boost { - -// -// Compile time tweaking on whether or not swap should use the default constructor: -// - -template <> struct optional_swap_should_use_default_constructor< - optional_swap_test::class_whose_default_ctor_should_be_used> : mpl::true_ {} ; - -template <> struct optional_swap_should_use_default_constructor< - optional_swap_test::class_whose_default_ctor_should_not_be_used> : mpl::false_ {} ; - -template struct optional_swap_should_use_default_constructor< - optional_swap_test::template_whose_default_ctor_should_be_used > : mpl::true_ {} ; - - -// -// Specialization of boost::swap: -// -template <> -void swap(optional & x, optional & y) -{ - optional_swap_test::swap(x, y); -} - -} // namespace boost - - -namespace std { - -// -// Specializations of std::swap: -// - -template <> -void swap(optional_swap_test::class_whose_default_ctor_should_be_used & x, optional_swap_test::class_whose_default_ctor_should_be_used & y) -{ - optional_swap_test::swap(x, y); -} - -template <> -void swap(optional_swap_test::class_whose_default_ctor_should_not_be_used & x, optional_swap_test::class_whose_default_ctor_should_not_be_used & y) -{ - optional_swap_test::swap(x, y); -} - -template <> -void swap(optional_swap_test::class_without_default_ctor & x, optional_swap_test::class_without_default_ctor & y) -{ - optional_swap_test::swap(x, y); -} - -template <> -void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used & x, optional_swap_test::class_whose_explicit_ctor_should_be_used & y) -{ - optional_swap_test::swap(x, y); -} - -} // namespace std - - -// -// Tests whether the swap function works properly for optional. -// Assumes that T has one data member, of type char. -// Returns true iff the test is passed. -// -template -bool test_swap_function( T const* ) -{ - const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter(); - try - { - optional obj1; - optional obj2('a'); - - // Self-swap should not have any effect. - swap(obj1, obj1); - swap(obj2, obj2); - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - - // Call non-member swap. - swap(obj1, obj2); - - // Test if obj1 and obj2 are really swapped. - BOOST_CHECK(!!obj1 && obj1->data == 'a'); - BOOST_CHECK(!obj2); - - // Call non-member swap one more time. - swap(obj1, obj2); - - // Test if obj1 and obj2 are swapped back. - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - } - catch(const std::exception &) - { - // The swap function should not throw, for our test cases. - return false ; - } - return boost::minimal_test::errors_counter() == counter_before_test ; -} - -// -// Tests whether the optional::swap member function works properly. -// Assumes that T has one data member, of type char. -// Returns true iff the test is passed. -// -template -bool test_swap_member_function( T const* ) -{ - const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter(); - try - { - optional obj1; - optional obj2('a'); - - // Self-swap should not have any effect. - obj1.swap(obj1); - obj2.swap(obj2); - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - - // Call member swap. - obj1.swap(obj2); - - // Test if obj1 and obj2 are really swapped. - BOOST_CHECK(!!obj1 && obj1->data == 'a'); - BOOST_CHECK(!obj2); - - // Call member swap one more time. - obj1.swap(obj2); - - // Test if obj1 and obj2 are swapped back. - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - } - catch(const std::exception &) - { - // The optional::swap member function should not throw, for our test cases. - return false ; - } - return boost::minimal_test::errors_counter() == counter_before_test ; -} - - -// -// Tests compile time tweaking of swap, by means of -// optional_swap_should_use_default_constructor. -// -void test_swap_tweaking() -{ - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); -} - // Test for support for classes with overridden operator& class CustomAddressOfClass { @@ -1272,7 +941,6 @@ int test_main( int, char* [] ) test_with_class_type(); test_with_builtin_types(); test_no_implicit_conversions(); - test_swap_tweaking(); test_custom_addressof_operator(); } catch ( ... ) diff --git a/test/optional_test_swap.cpp b/test/optional_test_swap.cpp new file mode 100644 index 0000000..53eebc2 --- /dev/null +++ b/test/optional_test_swap.cpp @@ -0,0 +1,376 @@ +// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// fernando_cacciola@hotmail.com +// +// Revisions: +// 12 May 2008 (added more swap tests) +// +#include +#include +#include + +#define BOOST_ENABLE_ASSERT_HANDLER + +#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin +#include "boost/mpl/bool.hpp" +#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/none.hpp" + +#include "boost/test/minimal.hpp" + +#include "optional_test_common.cpp" + + + +namespace optional_swap_test +{ + class default_ctor_exception : public std::exception {} ; + class copy_ctor_exception : public std::exception {} ; + class assignment_exception : public std::exception {} ; + + // + // Base class for swap test classes. Its assignment should not be called, when swapping + // optional objects. (The default std::swap would do so.) + // + class base_class_with_forbidden_assignment + { + public: + base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &) + { + BOOST_CHECK(!"The assignment should not be used while swapping!"); + throw assignment_exception(); + } + + virtual ~base_class_with_forbidden_assignment() {} + }; + + // + // Class without default constructor + // + class class_without_default_ctor : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_without_default_ctor(char arg) : data(arg) {} + }; + + // + // Class whose default constructor should not be used by optional::swap! + // + class class_whose_default_ctor_should_not_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_default_ctor_should_not_be_used(char arg) : data(arg) {} + + class_whose_default_ctor_should_not_be_used() + { + BOOST_CHECK(!"This default constructor should not be used while swapping!"); + throw default_ctor_exception(); + } + }; + + // + // Class whose default constructor should be used by optional::swap. + // Its copy constructor should be avoided! + // + class class_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_default_ctor_should_be_used(char arg) : data(arg) { } + + class_whose_default_ctor_should_be_used() : data('\0') { } + + class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + // + // Class template whose default constructor should be used by optional::swap. + // Its copy constructor should be avoided! + // + template + class template_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + T data; + explicit template_whose_default_ctor_should_be_used(T arg) : data(arg) { } + + template_whose_default_ctor_should_be_used() : data('\0') { } + + template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + // + // Class whose explicit constructor should be used by optional::swap. + // Its other constructors should be avoided! + // + class class_whose_explicit_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_explicit_ctor_should_be_used(char arg) : data(arg) { } + + class_whose_explicit_ctor_should_be_used() + { + BOOST_CHECK(!"This default constructor should not be used while swapping!"); + throw default_ctor_exception(); + } + + class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + void swap(class_whose_default_ctor_should_not_be_used & lhs, class_whose_default_ctor_should_not_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_whose_default_ctor_should_be_used & lhs, class_whose_default_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_without_default_ctor & lhs, class_without_default_ctor & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_whose_explicit_ctor_should_be_used & lhs, class_whose_explicit_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + template + void swap(template_whose_default_ctor_should_be_used & lhs, template_whose_default_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + // + // optional::swap should be customized when neither the copy constructor + // nor the default constructor of T are supposed to be used when swapping, e.g., + // for the following type T = class_whose_explicit_ctor_should_be_used. + // + void swap(boost::optional & x, boost::optional & y) + { + bool hasX(x); + bool hasY(y); + + if ( !hasX && !hasY ) + return; + + if( !hasX ) + x = boost::in_place('\0'); + else if ( !hasY ) + y = boost::in_place('\0'); + + optional_swap_test::swap(*x,*y); + + if( !hasX ) + y = boost::none ; + else if( !hasY ) + x = boost::none ; + } + + +} // End of namespace optional_swap_test. + + +namespace boost { + +// +// Compile time tweaking on whether or not swap should use the default constructor: +// + +template <> struct optional_swap_should_use_default_constructor< + optional_swap_test::class_whose_default_ctor_should_be_used> : mpl::true_ {} ; + +template <> struct optional_swap_should_use_default_constructor< + optional_swap_test::class_whose_default_ctor_should_not_be_used> : mpl::false_ {} ; + +template struct optional_swap_should_use_default_constructor< + optional_swap_test::template_whose_default_ctor_should_be_used > : mpl::true_ {} ; + + +// +// Specialization of boost::swap: +// +template <> +void swap(optional & x, optional & y) +{ + optional_swap_test::swap(x, y); +} + +} // namespace boost + + +namespace std { + +// +// Specializations of std::swap: +// + +template <> +void swap(optional_swap_test::class_whose_default_ctor_should_be_used & x, optional_swap_test::class_whose_default_ctor_should_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_whose_default_ctor_should_not_be_used & x, optional_swap_test::class_whose_default_ctor_should_not_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_without_default_ctor & x, optional_swap_test::class_without_default_ctor & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used & x, optional_swap_test::class_whose_explicit_ctor_should_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +} // namespace std + + +// +// Tests whether the swap function works properly for optional. +// Assumes that T has one data member, of type char. +// Returns true iff the test is passed. +// +template +void test_swap_function( T const* ) +{ + try + { + optional obj1; + optional obj2('a'); + + // Self-swap should not have any effect. + swap(obj1, obj1); + swap(obj2, obj2); + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + + // Call non-member swap. + swap(obj1, obj2); + + // Test if obj1 and obj2 are really swapped. + BOOST_CHECK(!!obj1 && obj1->data == 'a'); + BOOST_CHECK(!obj2); + + // Call non-member swap one more time. + swap(obj1, obj2); + + // Test if obj1 and obj2 are swapped back. + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + } + catch(const std::exception &) + { + // The swap function should not throw, for our test cases. + BOOST_CHECK(!"throw in swap"); + } +} + +// +// Tests whether the optional::swap member function works properly. +// Assumes that T has one data member, of type char. +// Returns true iff the test is passed. +// +template +void test_swap_member_function( T const* ) +{ + try + { + optional obj1; + optional obj2('a'); + + // Self-swap should not have any effect. + obj1.swap(obj1); + obj2.swap(obj2); + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + + // Call member swap. + obj1.swap(obj2); + + // Test if obj1 and obj2 are really swapped. + BOOST_CHECK(!!obj1 && obj1->data == 'a'); + BOOST_CHECK(!obj2); + + // Call member swap one more time. + obj1.swap(obj2); + + // Test if obj1 and obj2 are swapped back. + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + } + catch(const std::exception &) + { + BOOST_CHECK(!"throw in swap"); + } +} + + +// +// Tests compile time tweaking of swap, by means of +// optional_swap_should_use_default_constructor. +// +void test_swap_tweaking() +{ + ( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) ); + ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); + ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); + ( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); + ( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); +} + +int test_main( int, char* [] ) +{ + try + { + test_swap_tweaking(); + } + catch ( ... ) + { + BOOST_ERROR("Unexpected Exception caught!"); + } + + return 0; +}