// what: unit tests for variant type boost::any // who: contributed by Kevlin Henney // when: July 2001, 2013, 2014 // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95 #include #include #include #include #include #include "test.hpp" namespace any_tests { typedef test test_case; typedef const test_case * test_case_iterator; extern const test_case_iterator begin, end; } int main() { using namespace any_tests; tester test_suite(begin, end); return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE; } namespace any_tests // test suite { void test_default_ctor(); void test_converting_ctor(); void test_copy_ctor(); void test_copy_assign(); void test_converting_assign(); void test_bad_cast(); void test_swap(); void test_null_copying(); void test_cast_to_reference(); void test_with_array(); void test_with_func(); void test_clear(); void test_vectors(); void test_addressof(); const test_case test_cases[] = { { "default construction", test_default_ctor }, { "single argument construction", test_converting_ctor }, { "copy construction", test_copy_ctor }, { "copy assignment operator", test_copy_assign }, { "converting assignment operator", test_converting_assign }, { "failed custom keyword cast", test_bad_cast }, { "swap member function", test_swap }, { "copying operations on a null", test_null_copying }, { "cast to reference types", test_cast_to_reference }, { "storing an array inside", test_with_array }, { "implicit cast of returned value",test_with_func }, { "clear() methods", test_clear }, { "testing with vectors", test_vectors }, { "class with operator&()", test_addressof } }; const test_case_iterator begin = test_cases; const test_case_iterator end = test_cases + (sizeof test_cases / sizeof *test_cases); struct copy_counter { public: copy_counter() {} copy_counter(const copy_counter&) { ++count; } copy_counter& operator=(const copy_counter&) { ++count; return *this; } static int get_count() { return count; } private: static int count; }; int copy_counter::count = 0; } namespace any_tests // test definitions { using namespace boost; void test_default_ctor() { const any value; check_true(value.empty(), "empty"); check_null(any_cast(&value), "any_cast"); check_equal(value.type(), boost::typeindex::type_id(), "type"); } void test_converting_ctor() { std::string text = "test message"; any value = text; check_false(value.empty(), "empty"); check_equal(value.type(), boost::typeindex::type_id(), "type"); check_null(any_cast(&value), "any_cast"); check_non_null(any_cast(&value), "any_cast"); check_equal( any_cast(value), text, "comparing cast copy against original text"); check_unequal( any_cast(&value), &text, "comparing address in copy against original text"); } void test_copy_ctor() { std::string text = "test message"; any original = text, copy = original; check_false(copy.empty(), "empty"); check_equal(boost::typeindex::type_index(original.type()), copy.type(), "type"); check_equal( any_cast(original), any_cast(copy), "comparing cast copy against original"); check_equal( text, any_cast(copy), "comparing cast copy against original text"); check_unequal( any_cast(&original), any_cast(©), "comparing address in copy against original"); } void test_copy_assign() { std::string text = "test message"; any original = text, copy; any * assign_result = &(copy = original); check_false(copy.empty(), "empty"); check_equal(boost::typeindex::type_index(original.type()), copy.type(), "type"); check_equal( any_cast(original), any_cast(copy), "comparing cast copy against cast original"); check_equal( text, any_cast(copy), "comparing cast copy against original text"); check_unequal( any_cast(&original), any_cast(©), "comparing address in copy against original"); check_equal(assign_result, ©, "address of assignment result"); } void test_converting_assign() { std::string text = "test message"; any value; any * assign_result = &(value = text); check_false(value.empty(), "type"); check_equal(value.type(), boost::typeindex::type_id(), "type"); check_null(any_cast(&value), "any_cast"); check_non_null(any_cast(&value), "any_cast"); check_equal( any_cast(value), text, "comparing cast copy against original text"); check_unequal( any_cast(&value), &text, "comparing address in copy against original text"); check_equal(assign_result, &value, "address of assignment result"); } void test_bad_cast() { std::string text = "test message"; any value = text; TEST_CHECK_THROW( any_cast(value), bad_any_cast, "any_cast to incorrect type"); } void test_swap() { std::string text = "test message"; any original = text, swapped; std::string * original_ptr = any_cast(&original); any * swap_result = &original.swap(swapped); check_true(original.empty(), "empty on original"); check_false(swapped.empty(), "empty on swapped"); check_equal(swapped.type(), boost::typeindex::type_id(), "type"); check_equal( text, any_cast(swapped), "comparing swapped copy against original text"); check_non_null(original_ptr, "address in pre-swapped original"); check_equal( original_ptr, any_cast(&swapped), "comparing address in swapped against original"); check_equal(swap_result, &original, "address of swap result"); any copy1 = copy_counter(); any copy2 = copy_counter(); int count = copy_counter::get_count(); swap(copy1, copy2); check_equal(count, copy_counter::get_count(), "checking that free swap doesn't make any copies."); } void test_null_copying() { const any null; any copied = null, assigned; assigned = null; check_true(null.empty(), "empty on null"); check_true(copied.empty(), "empty on copied"); check_true(assigned.empty(), "empty on copied"); } void test_cast_to_reference() { any a(137); const any b(a); int & ra = any_cast(a); int const & ra_c = any_cast(a); int volatile & ra_v = any_cast(a); int const volatile & ra_cv = any_cast(a); check_true( &ra == &ra_c && &ra == &ra_v && &ra == &ra_cv, "cv references to same obj"); int const & rb_c = any_cast(b); int const volatile & rb_cv = any_cast(b); check_true(&rb_c == &rb_cv, "cv references to copied const obj"); check_true(&ra != &rb_c, "copies hold different objects"); ++ra; int incremented = any_cast(a); check_true(incremented == 138, "increment by reference changes value"); TEST_CHECK_THROW( any_cast(a), bad_any_cast, "any_cast to incorrect reference type"); TEST_CHECK_THROW( any_cast(b), bad_any_cast, "any_cast to incorrect const reference type"); } void test_with_array() { any value1("Char array"); any value2; value2 = "Char array"; check_false(value1.empty(), "type"); check_false(value2.empty(), "type"); check_equal(value1.type(), boost::typeindex::type_id(), "type"); check_equal(value2.type(), boost::typeindex::type_id(), "type"); check_non_null(any_cast(&value1), "any_cast"); check_non_null(any_cast(&value2), "any_cast"); } const std::string& returning_string1() { static const std::string ret("foo"); return ret; } std::string returning_string2() { static const std::string ret("foo"); return ret; } void test_with_func() { std::string s; s = any_cast(returning_string1()); s = any_cast(returning_string1()); s = any_cast(returning_string2()); s = any_cast(returning_string2()); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #if !defined(__INTEL_COMPILER) && !defined(__ICL) && (!defined(_MSC_VER) || _MSC_VER != 1600) // Intel compiler thinks that it must choose the `any_cast(const any&)` function // instead of the `any_cast(const any&&)`. // Bug was not reported because of missing premier support account + annoying // registrations requirements. // MSVC-10 had a bug: // // any.hpp(291) : error C2440: 'return' : cannot convert. // Conversion loses qualifiers // any_test.cpp(304) : see reference to function template instantiation // // This issue was fixed in MSVC-11. s = any_cast(returning_string1()); #endif s = any_cast(returning_string2()); #endif } void test_clear() { std::string text = "test message"; any value = text; check_false(value.empty(), "empty"); value.clear(); check_true(value.empty(), "non-empty after clear"); value.clear(); check_true(value.empty(), "non-empty after second clear"); value = text; check_false(value.empty(), "empty"); value.clear(); check_true(value.empty(), "non-empty after clear"); } // Following tests cover the case from #9462 // https://svn.boost.org/trac/boost/ticket/9462 boost::any makeVec() { return std::vector(100 /*size*/, 7 /*value*/); } void test_vectors() { const std::vector& vec = boost::any_cast >(makeVec()); check_equal(vec.size(), 100u, "size of vector extracted from boost::any"); check_equal(vec.back(), 7, "back value of vector extracted from boost::any"); check_equal(vec.front(), 7, "front value of vector extracted from boost::any"); std::vector vec1 = boost::any_cast >(makeVec()); check_equal(vec1.size(), 100u, "size of second vector extracted from boost::any"); check_equal(vec1.back(), 7, "back value of second vector extracted from boost::any"); check_equal(vec1.front(), 7, "front value of second vector extracted from boost::any"); } template class class_with_address_op { public: class_with_address_op(const T* p) : ptr(p) {} const T** operator &() { return &ptr; } const T* get() const { return ptr; } private: const T* ptr; }; void test_addressof() { int val = 10; const int* ptr = &val; class_with_address_op obj(ptr); boost::any test_val(obj); class_with_address_op returned_obj = boost::any_cast >(test_val); check_equal(&val, returned_obj.get(), "any_cast incorrectly works with type that has operator&(): addresses differ"); check_true(!!boost::any_cast >(&test_val), "any_cast incorrectly works with type that has operator&()"); check_equal(boost::unsafe_any_cast >(&test_val)->get(), ptr, "unsafe_any_cast incorrectly works with type that has operator&()"); } } // Copyright Kevlin Henney, 2000, 2001. All rights reserved. // Copyright Antony Polukhin, 2013-2019. // // 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) //