From 8214c43060e960561827709b1f9fafbb60cbea8f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 5 Nov 2005 17:24:20 +0000 Subject: [PATCH] Unit tests for unordered containers. [SVN r2731] --- test/Jamfile.v2 | 63 ++++ test/assign_tests.cpp | 86 ++++++ test/basic_tests.cpp | 207 +++++++++++++ test/check_return_type.hpp | 36 +++ test/clear_tests.cpp | 32 ++ test/concept_test.cpp | 32 ++ test/const_iterator_fail_test.cpp | 16 + test/const_local_iterator_fail_test.cpp | 18 ++ test/construct_tests.cpp | 273 +++++++++++++++++ test/container_tests.cpp | 228 ++++++++++++++ test/containers.hpp | 76 +++++ test/copy_construct_tests.cpp | 119 ++++++++ test/count_tests.cpp | 65 ++++ test/equal_range_tests.cpp | 100 +++++++ test/equivalent.hpp | 112 +++++++ test/erase_tests.cpp | 190 ++++++++++++ test/find_tests.cpp | 78 +++++ test/helpers/accessors.hpp | 12 + test/helpers/allocator.cpp | 209 +++++++++++++ test/helpers/allocator.hpp | 376 ++++++++++++++++++++++++ test/helpers/base.cpp | 31 ++ test/helpers/base.hpp | 15 + test/helpers/config.hpp | 18 ++ test/helpers/constructors.hpp | 69 +++++ test/helpers/equivalent.hpp | 45 +++ test/helpers/exception.cpp | 85 ++++++ test/helpers/exception.hpp | 60 ++++ test/helpers/exception_test.cpp | 108 +++++++ test/helpers/exception_test.hpp | 33 +++ test/helpers/exception_trigger.hpp | 49 +++ test/helpers/functional.cpp | 140 +++++++++ test/helpers/functional.hpp | 80 +++++ test/helpers/generators.cpp | 43 +++ test/helpers/generators.hpp | 41 +++ test/helpers/input_iterator_adaptor.hpp | 35 +++ test/helpers/invariant_checker.cpp | 54 ++++ test/helpers/invariant_checker.hpp | 78 +++++ test/helpers/less.hpp | 37 +++ test/helpers/member.cpp | 79 +++++ test/helpers/member.hpp | 40 +++ test/helpers/metafunctions.hpp | 100 +++++++ test/helpers/random_values.hpp | 203 +++++++++++++ test/helpers/strong.cpp | 32 ++ test/helpers/strong.hpp | 78 +++++ test/helpers/unit_test.hpp | 77 +++++ test/insert_tests.cpp | 193 ++++++++++++ test/invariant.hpp | 128 ++++++++ test/iterator_tests.cpp | 141 +++++++++ test/map_operator_tests.cpp | 69 +++++ test/max_load_factor_test.cpp | 170 +++++++++++ test/next_prime_tests.cpp | 18 ++ test/set_assign_fail_test.cpp | 14 + test/strong.hpp | 102 +++++++ test/swap_tests.hpp | 120 ++++++++ test/swap_tests.ipp | 102 +++++++ test/swap_tests1.cpp | 7 + test/swap_tests2.cpp | 7 + test/swap_tests3.cpp | 7 + test/type_tests.cpp | 206 +++++++++++++ 59 files changed, 5242 insertions(+) create mode 100644 test/Jamfile.v2 create mode 100644 test/assign_tests.cpp create mode 100644 test/basic_tests.cpp create mode 100644 test/check_return_type.hpp create mode 100644 test/clear_tests.cpp create mode 100644 test/concept_test.cpp create mode 100644 test/const_iterator_fail_test.cpp create mode 100644 test/const_local_iterator_fail_test.cpp create mode 100644 test/construct_tests.cpp create mode 100644 test/container_tests.cpp create mode 100644 test/containers.hpp create mode 100644 test/copy_construct_tests.cpp create mode 100644 test/count_tests.cpp create mode 100644 test/equal_range_tests.cpp create mode 100644 test/equivalent.hpp create mode 100644 test/erase_tests.cpp create mode 100644 test/find_tests.cpp create mode 100644 test/helpers/accessors.hpp create mode 100644 test/helpers/allocator.cpp create mode 100644 test/helpers/allocator.hpp create mode 100644 test/helpers/base.cpp create mode 100644 test/helpers/base.hpp create mode 100644 test/helpers/config.hpp create mode 100644 test/helpers/constructors.hpp create mode 100644 test/helpers/equivalent.hpp create mode 100644 test/helpers/exception.cpp create mode 100644 test/helpers/exception.hpp create mode 100644 test/helpers/exception_test.cpp create mode 100644 test/helpers/exception_test.hpp create mode 100644 test/helpers/exception_trigger.hpp create mode 100644 test/helpers/functional.cpp create mode 100644 test/helpers/functional.hpp create mode 100644 test/helpers/generators.cpp create mode 100644 test/helpers/generators.hpp create mode 100644 test/helpers/input_iterator_adaptor.hpp create mode 100644 test/helpers/invariant_checker.cpp create mode 100644 test/helpers/invariant_checker.hpp create mode 100644 test/helpers/less.hpp create mode 100644 test/helpers/member.cpp create mode 100644 test/helpers/member.hpp create mode 100644 test/helpers/metafunctions.hpp create mode 100644 test/helpers/random_values.hpp create mode 100644 test/helpers/strong.cpp create mode 100644 test/helpers/strong.hpp create mode 100644 test/helpers/unit_test.hpp create mode 100644 test/insert_tests.cpp create mode 100644 test/invariant.hpp create mode 100644 test/iterator_tests.cpp create mode 100644 test/map_operator_tests.cpp create mode 100644 test/max_load_factor_test.cpp create mode 100644 test/next_prime_tests.cpp create mode 100644 test/set_assign_fail_test.cpp create mode 100644 test/strong.hpp create mode 100644 test/swap_tests.hpp create mode 100644 test/swap_tests.ipp create mode 100644 test/swap_tests1.cpp create mode 100644 test/swap_tests2.cpp create mode 100644 test/swap_tests3.cpp create mode 100644 test/type_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 00000000..7704f38c --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,63 @@ + +# Copyright Daniel James 2005. Use, modification, and distribution are +# 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) + +import testing ; + +project unordered-test + : requirements + intel-linux:"-strict_ansi -cxxlib-icc" + # off + # TODO: Make this an option: + REDUCED_TESTS + ; + +lib helpers + : + [ glob helpers/*.cpp ] + ; + +framework = helpers/static /boost/test//boost_unit_test_framework ; + +test-suite helpers-test + : + [ run-fail helpers-test/simple_test.cpp $(framework) ] + [ run-fail helpers-test/allocator_test.cpp $(framework) ] + [ run helpers-test/exception_test.cpp $(framework) ] + ; + +test-suite compile-tests + : + [ compile-fail const_local_iterator_fail_test.cpp ] + [ compile-fail const_iterator_fail_test.cpp ] + [ compile-fail set_assign_fail_test.cpp ] + [ compile type_tests.cpp ] + [ run concept_test.cpp ] + ; + +test-suite basic-tests + : + [ run container_tests.cpp $(framework) ] + [ run iterator_tests.cpp $(framework) ] + [ run next_prime_tests.cpp $(framework) ] + [ run max_load_factor_test.cpp $(framework) ] + ; + +test-suite less-base-tests + : + [ run construct_tests.cpp $(framework) ] + [ run find_tests.cpp $(framework) ] + [ run count_tests.cpp $(framework) ] + [ run equal_range_tests.cpp $(framework) ] + [ run copy_construct_tests.cpp $(framework) ] + [ run swap_tests1.cpp $(framework) ] + [ run swap_tests2.cpp $(framework) ] + [ run swap_tests3.cpp $(framework) ] + [ run assign_tests.cpp $(framework) ] + [ run clear_tests.cpp $(framework) ] + [ run erase_tests.cpp $(framework) ] + [ run insert_tests.cpp $(framework) ] + [ run map_operator_tests.cpp $(framework) ] + ; + diff --git a/test/assign_tests.cpp b/test/assign_tests.cpp new file mode 100644 index 00000000..8d3e45ae --- /dev/null +++ b/test/assign_tests.cpp @@ -0,0 +1,86 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/constructors.hpp" +#include "./helpers/constructors.hpp" +#include "./helpers/equivalent.hpp" +#include "./invariant.hpp" + +const int num_values = 50; + +META_FUNC_TEST_CASE(assign_test1, Container) +{ + test::constructors constructor; + + test::random_values values(num_values); + Container x(values.begin(), values.end(), 0, + constructor.hasher(55), constructor.key_equal(55), + constructor.allocator(10)); + x.max_load_factor(0.1); + + EXCEPTION_TEST(10000) + { + DEACTIVATE_EXCEPTIONS; + Container y; + INVARIANT_CHECK(y); + ACTIVATE_EXCEPTIONS; + + BOOST_CHECKPOINT("y = x"); + y = x; + + { + DEACTIVATE_EXCEPTIONS; + BOOST_CHECK_EQUAL(y.size(), x.size()); + BOOST_CHECK(test::equivalent(y.hash_function(), x.hash_function())); + BOOST_CHECK(test::equivalent(y.key_eq(), x.key_eq())); + BOOST_CHECK_EQUAL(y.max_load_factor(), x.max_load_factor()); + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator())); + BOOST_CHECK(y.load_factor() <= y.max_load_factor()); + test::check_invariants(); + } + + BOOST_CHECKPOINT("y = y"); + y = y; + + { + DEACTIVATE_EXCEPTIONS; + BOOST_CHECK_EQUAL(y.size(), x.size()); + BOOST_CHECK(test::equivalent(y.hash_function(), x.hash_function())); + BOOST_CHECK(test::equivalent(y.key_eq(), x.key_eq())); + BOOST_CHECK_EQUAL(y.max_load_factor(), x.max_load_factor()); + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator())); + BOOST_CHECK(y.load_factor() <= y.max_load_factor()); + test::check_invariants(); + } + + BOOST_CHECKPOINT("y = Container(values.begin(), values.end())"); + y = Container(values.begin(), values.end()); + + { + DEACTIVATE_EXCEPTIONS; + BOOST_CHECK_EQUAL(y.size(), x.size()); + BOOST_CHECK(test::equivalent(y.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(y.key_eq(), constructor.key_equal())); + BOOST_CHECK_EQUAL(y.max_load_factor(), 1.0); + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator())); + BOOST_CHECK(y.load_factor() <= 1.0); + test::check_invariants(); + } + } + EXCEPTION_TEST_END +} + +AUTO_META_TESTS( + (assign_test1), + CONTAINER_SEQ +) diff --git a/test/basic_tests.cpp b/test/basic_tests.cpp new file mode 100644 index 00000000..177edbcb --- /dev/null +++ b/test/basic_tests.cpp @@ -0,0 +1,207 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include +#include +#include +#include +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/random_values.hpp" + +typedef double comparison_type; + +template +struct check_return_type +{ + template + static void equals(T2) + { + BOOST_MPL_ASSERT((boost::is_same)); + } + + template + static void equals_ref(T2&) + { + BOOST_MPL_ASSERT((boost::is_same)); + } + + template + static void convertible(T2) + { + BOOST_MPL_ASSERT((boost::is_convertible)); + } +}; + +// 23.1.5 +template +void container_tests(X*, T*) +{ + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::difference_type difference_type; + typedef typename X::size_type size_type; + + BOOST_MPL_ASSERT((boost::is_same)); + // TODO: Actually 'lvalue of T' + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + + // TODO: Iterator checks. + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT_NOT((boost::is_same, std::output_iterator_tag>)); + BOOST_MPL_ASSERT((boost::is_convertible)); + + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT_NOT((boost::is_same, std::output_iterator_tag>)); + + BOOST_MPL_ASSERT((boost::mpl::bool_::is_signed>)); + BOOST_MPL_ASSERT((boost::mpl::bool_::is_integer>)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + + BOOST_MPL_ASSERT_NOT((boost::mpl::bool_::is_signed>)); + BOOST_MPL_ASSERT((boost::mpl::bool_::is_integer>)); + BOOST_CHECK((comparison_type)(std::numeric_limits::max)() + > (comparison_type)(std::numeric_limits::max)()); + + { + X u; + BOOST_CHECK(u.size() == 0); + } +} + +template +void container_tests2(X& a) +{ + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::difference_type difference_type; + typedef typename X::size_type size_type; + + { + X u(a); + // BOOST_CHECK_EQUAL(a, u); + } + + { + X u = a; + // BOOST_CHECK_EQUAL(a, u); + } + + // Test that destructor destructs all elements + + { + X const a_const = a; + + check_return_type::equals(a.begin()); + check_return_type::equals(a_const.begin()); + check_return_type::equals(a.end()); + check_return_type::equals(a_const.end()); + } + + // No tests for ==, != since they're not required for unordered containers. + + { + X b; + a.swap(b); + a.swap(b); + } + + { + X u; + X& r = u; + + check_return_type::equals_ref(r = a); + } + + { + check_return_type::equals(a.size()); + BOOST_CHECK_EQUAL(a.size(), (size_type) std::distance(a.begin(), a.end())); + } + + { + check_return_type::equals(a.max_size()); + } + + { + check_return_type::convertible(a.empty()); + BOOST_CHECK_EQUAL(a.empty(), a.size() == 0); + } + + // TODO: member function size return number of elements. + // Semantics determined by constructors/inserts/erases. + // ie. will be tested in their tests. + + // begin() returns first element. + // end() return past the end iterator. + // Can't really test this for unordered containers. + + { + if(a.empty()) + BOOST_CHECK(a.begin() == a.end()); + } + + // TODO: test that const_iterator can replace iterator in comparisons. + + // TODO: test allocators + + // No need to test reversible. + + // Exceptions: + // No copy constructor or assignment operator of a returned iterator throws an exception. + + // No swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped. + // Unless otherwise specified, iterators are not invalidated, and the values of objects aren't changed. +} + +BOOST_AUTO_UNIT_TEST(basic_tests) +{ + // I don't use the normal template mechanism here, as I want to specify the + // member type explicitly. + container_tests((boost::unordered_set*) 0, (int*) 0); + container_tests((boost::unordered_map*) 0, (std::pair*) 0); + container_tests((boost::unordered_multiset*) 0, (std::string*) 0); + container_tests((boost::unordered_multimap*) 0, + (std::pair*) 0); +} + +struct test_structure { int* x; }; + +META_FUNC_TEST_CASE(basic_tests_2, Container) +{ + + Container a; + container_tests2(a); + + { + test::random_values values1((std::min)(10u, a.max_size())); + Container b(values1.begin(), values1.end()); + container_tests2(b); + } + + { + test::random_values values2((std::min)(1000u, a.max_size())); + Container c(values2.begin(), values2.end()); + container_tests2(c); + } + + { + test::random_values values3((std::min)(100000u, a.max_size())); + Container d(values3.begin(), values3.end()); + container_tests2(d); + } +} + +AUTO_META_TESTS( + (basic_tests_2), + CONTAINER_SEQ +) diff --git a/test/check_return_type.hpp b/test/check_return_type.hpp new file mode 100644 index 00000000..a201e75d --- /dev/null +++ b/test/check_return_type.hpp @@ -0,0 +1,36 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TESTS_CHECK_RETURN_TYPE_HEADER) +#define BOOST_UNORDERED_TESTS_CHECK_RETURN_TYPE_HEADER + +#include + +template +struct check_return_type +{ + template + static int equals(T2) + { + BOOST_MPL_ASSERT((boost::is_same)); + return 0; + } + + template + static int equals_ref(T2&) + { + BOOST_MPL_ASSERT((boost::is_same)); + return 0; + } + + template + static int convertible(T2) + { + BOOST_MPL_ASSERT((boost::is_convertible)); + return 0; + } +}; + +#endif diff --git a/test/clear_tests.cpp b/test/clear_tests.cpp new file mode 100644 index 00000000..558ed539 --- /dev/null +++ b/test/clear_tests.cpp @@ -0,0 +1,32 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/constructors.hpp" +#include "./invariant.hpp" + +META_FUNC_TEST_CASE(clear_test, Container) +{ + test::constructors constructor; + test::random_values values(100); + Container x(values.begin(), values.end(), 0, + constructor.hasher(55), constructor.key_equal(55), + constructor.allocator(10)); + + x.clear(); + BOOST_CHECK(x.empty()); + test::invariant_check(x); +} + +AUTO_META_TESTS( + (clear_test), + CONTAINER_SEQ +) diff --git a/test/concept_test.cpp b/test/concept_test.cpp new file mode 100644 index 00000000..ddd98845 --- /dev/null +++ b/test/concept_test.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include + +int main() +{ + using namespace boost; + + typedef boost::unordered_set UnorderedSet; + typedef boost::unordered_multiset UnorderedMultiSet; + typedef boost::unordered_map UnorderedMap; + typedef boost::unordered_multimap UnorderedMultiMap; + + function_requires< UnorderedAssociativeContainerConcept >(); + function_requires< SimpleAssociativeContainerConcept >(); + function_requires< UniqueAssociativeContainerConcept >(); + + function_requires< UnorderedAssociativeContainerConcept >(); + function_requires< SimpleAssociativeContainerConcept >(); + function_requires< MultipleAssociativeContainerConcept >(); + + function_requires< UnorderedAssociativeContainerConcept >(); + function_requires< UniqueAssociativeContainerConcept >(); + function_requires< PairAssociativeContainerConcept >(); + + function_requires< UnorderedAssociativeContainerConcept >(); + function_requires< MultipleAssociativeContainerConcept >(); + function_requires< PairAssociativeContainerConcept >(); + + return 0; +} diff --git a/test/const_iterator_fail_test.cpp b/test/const_iterator_fail_test.cpp new file mode 100644 index 00000000..fcd7b82a --- /dev/null +++ b/test/const_iterator_fail_test.cpp @@ -0,0 +1,16 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include + +void func() +{ + typedef boost::unordered_map map; + typedef map::iterator iterator; + typedef map::const_iterator const_iterator; + + const_iterator x; + iterator y(x); +} diff --git a/test/const_local_iterator_fail_test.cpp b/test/const_local_iterator_fail_test.cpp new file mode 100644 index 00000000..348c9b5b --- /dev/null +++ b/test/const_local_iterator_fail_test.cpp @@ -0,0 +1,18 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include + +void func() +{ + // This is only required to fail for unordered maps & multimaps as for sets + // and multisets both iterator and const_iterator are const. + typedef boost::unordered_map map; + typedef map::local_iterator local_iterator; + typedef map::const_local_iterator const_local_iterator; + + const_local_iterator x; + local_iterator y(x); +} diff --git a/test/construct_tests.cpp b/test/construct_tests.cpp new file mode 100644 index 00000000..2c9cfb99 --- /dev/null +++ b/test/construct_tests.cpp @@ -0,0 +1,273 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/input_iterator_adaptor.hpp" +#include "./helpers/constructors.hpp" +#include "./helpers/equivalent.hpp" +#include "./invariant.hpp" + +META_FUNC_TEST_CASE(empty_construct_test1, Container) +{ + test::constructors constructor; + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 4 + Container x(100, constructor.hasher(55), constructor.key_equal(55)); + BOOST_CHECK(x.bucket_count() >= 100); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(55))); + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(empty_construct_test2, Container) +{ + test::constructors constructor; + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 5 + + // I can only use the default hasher here - as it'll match the default + // key_equal. + Container x(100, constructor.hasher()); + BOOST_CHECK(x.empty()); + BOOST_CHECK(x.bucket_count() >= 100); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal())); + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(empty_construct_test3, Container) +{ + test::constructors constructor; + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 6 + + Container x(200); + BOOST_CHECK(x.empty()); + BOOST_CHECK(x.bucket_count() >= 200); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal())); + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(empty_construct_test4, Container) +{ + test::constructors constructor; + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 7 + + Container x; + BOOST_CHECK(x.empty()); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal())); + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(empty_construct_test5, Container) +{ + test::constructors constructor; + + EXCEPTION_TEST(1000) + { + // TODO: Where? + Container x(100, constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + BOOST_CHECK(x.empty()); + BOOST_CHECK(x.bucket_count() >= 100); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(55))); + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(10))); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(range_construct_test1, Container) +{ + test::constructors constructor; + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 8 + + Container x(values.begin(), values.end(), 100, + constructor.hasher(55), constructor.key_equal(55)); + BOOST_CHECK(x.bucket_count() >= 100); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(55))); + // TODO: Check that values are in container. + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(range_construct_test2, Container) +{ + test::constructors constructor; + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 9 + + Container x(values.begin(), values.end(), 100, constructor.hasher()); + BOOST_CHECK(x.bucket_count() >= 100); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal())); + // TODO: Check that values are in container. + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(range_construct_test3, Container) +{ + test::constructors constructor; + test::random_values values(20); + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 10 + + Container x(values.begin(), values.end(), 10); + BOOST_CHECK(x.bucket_count() >= 10); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal())); + // TODO: Check that values are in container. + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(range_construct_test4, Container) +{ + test::constructors constructor; + test::random_values values(20); + + EXCEPTION_TEST(1000) + { + // TR1 6.3.1/9 row 11 + + Container x(values.begin(), values.end()); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher())); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal())); + // TODO: Check that values are in container. + + // TODO: Where? + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator())); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(range_construct_test5, Container) +{ + test::constructors constructor; + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + // TODO: Where? + Container x(values.begin(), values.end(), 10, + constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + BOOST_CHECK(x.bucket_count() >= 10); + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(55))); + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(10))); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END +} + +// TODO: I should probably just make all the tests run from an input iterator. +META_FUNC_TEST_CASE(input_iterator_construct_test1, Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + Container x( + test::make_input_iterator(values.begin()), + test::make_input_iterator(values.end()) + ); + BOOST_CHECK_EQUAL(x.max_load_factor(), 1.0); + + test::invariant_check(x); + } + EXCEPTION_TEST_END + +} + +AUTO_META_TESTS( + (empty_construct_test1)(empty_construct_test2)(empty_construct_test3) + (empty_construct_test4)(empty_construct_test5) + (range_construct_test1)(range_construct_test2)(range_construct_test3) + (range_construct_test4)(range_construct_test5) + (input_iterator_construct_test1), + CONTAINER_SEQ +) diff --git a/test/container_tests.cpp b/test/container_tests.cpp new file mode 100644 index 00000000..48aa47fb --- /dev/null +++ b/test/container_tests.cpp @@ -0,0 +1,228 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include +#include +#include +#include +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/random_values.hpp" +#include "./equivalent.hpp" +#include "./check_return_type.hpp" + +typedef double comparison_type; + +// 23.1/5 +template +void container_tests(X*, T*) +{ + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::difference_type difference_type; + typedef typename X::size_type size_type; + + BOOST_MPL_ASSERT((boost::is_same)); + // TODO: Actually 'lvalue of T'/'const lvalue of T' + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + + // TODO: Iterator checks. + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT_NOT((boost::is_same, std::output_iterator_tag>)); + BOOST_MPL_ASSERT((boost::is_convertible)); + + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT_NOT((boost::is_same, std::output_iterator_tag>)); + + BOOST_MPL_ASSERT((boost::mpl::bool_::is_signed>)); + BOOST_MPL_ASSERT((boost::mpl::bool_::is_integer>)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + + BOOST_MPL_ASSERT_NOT((boost::mpl::bool_::is_signed>)); + BOOST_MPL_ASSERT((boost::mpl::bool_::is_integer>)); + BOOST_CHECK((comparison_type)(std::numeric_limits::max)() + > (comparison_type)(std::numeric_limits::max)()); + + { + X u; + BOOST_CHECK(u.size() == 0); + BOOST_CHECK(X().size() == 0); + } +} + +template +void container_tests2(X& a) +{ + // 23.1/5 continued + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::difference_type difference_type; + typedef typename X::size_type size_type; + + test::unordered_equivalence_tester equivalent(a); + + { + X u(a); + equivalent.test(u); + } + + { + X u = a; + equivalent.test(u); + } + + // Test that destructor destructs all elements (already done by test::allocator/test::member?). + + { + X const& a_const = a; + + check_return_type::equals(a.begin()); + check_return_type::equals(a_const.begin()); + check_return_type::equals(a.end()); + check_return_type::equals(a_const.end()); + } + + // No tests for ==, != since they're not required for unordered containers. + + { + X b; + a.swap(b); + BOOST_CHECK(a.empty()); + equivalent.test(b); + a.swap(b); + equivalent.test(a); + BOOST_CHECK(b.empty()); + } + + { + X u; + X& r = u; + + check_return_type::equals_ref(r = a); + equivalent.test(r); + } + + { + check_return_type::equals(a.size()); + BOOST_CHECK_EQUAL(a.size(), (size_type) std::distance(a.begin(), a.end())); + } + + { + check_return_type::equals(a.max_size()); + // TODO: Check that a.max_size() == size of the largest possible container + // How do I do that? test::allocator checks that allocations don't exceed + // that allocator's maximum size. Could check that max_size() works, and + // that max_size() + 1 doesn't. Only practicle for small max_size though - + // and it might be possible to implement unordered containers such that + // max_size() > alloc.max_size(). Or is it? + } + + { + check_return_type::convertible(a.empty()); + BOOST_CHECK_EQUAL(a.empty(), a.size() == 0); + } + + // 23.1/7 + { + if(a.empty()) + BOOST_CHECK(a.begin() == a.end()); + } + + // 23.1/8 + { + iterator i = a.begin(), j = a.end(); + const_iterator ci = a.begin(), cj = a.end(); + + if(a.empty()) { + BOOST_CHECK(i == j); + BOOST_CHECK(i == cj); + BOOST_CHECK(ci == j); + BOOST_CHECK(ci == cj); + + BOOST_CHECK(!(i != j)); + BOOST_CHECK(!(i != cj)); + BOOST_CHECK(!(ci != j)); + BOOST_CHECK(!(ci != cj)); + } + else { + BOOST_CHECK(!(i == j)); + BOOST_CHECK(!(i == cj)); + BOOST_CHECK(!(ci == j)); + BOOST_CHECK(!(ci == cj)); + + BOOST_CHECK(i != j); + BOOST_CHECK(i != cj); + BOOST_CHECK(ci != j); + BOOST_CHECK(ci != cj); + } + } + + // TODO: 23.1/9 - Make sure this is checked for all constructors. + { + check_return_type::equals(a.get_allocator()); + } + + // TODO: 23.1/11 - Exception safety: + // No erase function throws an exception. + // No copy constructor or assignment operator of a returned iterator throws an exception. + + // No swap() function throws an exception unless that exception is thrown by the copy constructor of assignment operator of the container's Compare object. + // No swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped. + // + // TODO: 21.1/12 + // + // Unless otherwise specified - iterators not invalidated, values not changed. +} + +BOOST_AUTO_UNIT_TEST(basic_tests) +{ + // I don't use the normal template mechanism here, as I want to specify the + // member type explicitly. + container_tests((boost::unordered_set*) 0, (int*) 0); + container_tests((boost::unordered_map*) 0, (std::pair*) 0); + container_tests((boost::unordered_multiset*) 0, (std::string*) 0); + container_tests((boost::unordered_multimap*) 0, + (std::pair*) 0); +} + +struct test_structure { int* x; }; + +META_FUNC_TEST_CASE(basic_tests_2, Container) +{ + + Container a; + container_tests2(a); + + { + test::random_values values1((std::min)(10u, a.max_size())); + Container b(values1.begin(), values1.end()); + container_tests2(b); + } + + { + test::random_values values2((std::min)(1000u, a.max_size())); + Container c(values2.begin(), values2.end()); + container_tests2(c); + } + + { + test::random_values values3((std::min)(100000u, a.max_size())); + Container d(values3.begin(), values3.end()); + container_tests2(d); + } +} + +AUTO_META_TESTS( + (basic_tests_2), + CONTAINER_SEQ +) diff --git a/test/containers.hpp b/test/containers.hpp new file mode 100644 index 00000000..674fe743 --- /dev/null +++ b/test/containers.hpp @@ -0,0 +1,76 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TESTS_CONTAINERS_HEADER) +#define BOOST_UNORDERED_TESTS_CONTAINERS_HEADER + +#include +#include +#include +#include +#include "./helpers/allocator.hpp" +#include "./helpers/functional.hpp" +#include "./helpers/member.hpp" + +typedef boost::unordered_set< + test::member + > test_set; +typedef boost::unordered_multiset< + test::member, test::hash, test::equals, + test::allocator + > test_multiset; +typedef boost::unordered_map< + test::member, test::member, test::hash, test::equals, + test::allocator > + > test_map; +typedef boost::unordered_multimap< + test::member, test::member, test::hash, test::equals, + test::minimal_allocator > + > test_multimap; + +typedef boost::unordered_set< + int, test::hash, test::equals, + test::allocator + > set_int; +typedef boost::unordered_multiset< + std::string, test::hash, test::equals, + test::allocator + > multiset_string; +typedef boost::unordered_map< + test::member, std::string, test::hash, test::equals, + test::allocator > + > map_member_string; +typedef boost::unordered_multimap< + int, test::member, test::hash, test::equals, + test::allocator > + > multimap_int_member; +typedef boost::unordered_map< + char, test::member, test::hash, test::equals, + test::allocator > + > map_char_member; +typedef boost::unordered_multiset< + char, test::hash, test::equals, + test::allocator + > multiset_char; + +typedef std::pair pair1; +typedef std::pair pair2; +typedef std::pair pair3; +BOOST_TT_BROKEN_COMPILER_SPEC(std::string) +BOOST_TT_BROKEN_COMPILER_SPEC(pair1) +BOOST_TT_BROKEN_COMPILER_SPEC(pair2) +BOOST_TT_BROKEN_COMPILER_SPEC(pair3) +BOOST_TT_BROKEN_COMPILER_SPEC(test::member) + +#ifdef REDUCED_TESTS +#define CONTAINER_SEQ \ + (test_set)(test_multiset)(test_map)(test_multimap) +#else +#define CONTAINER_SEQ \ + (set_int)(multiset_string)(map_member_string) \ + (multimap_int_member)(map_char_member)(multiset_char) +#endif + +#endif diff --git a/test/copy_construct_tests.cpp b/test/copy_construct_tests.cpp new file mode 100644 index 00000000..2bedd4e8 --- /dev/null +++ b/test/copy_construct_tests.cpp @@ -0,0 +1,119 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/constructors.hpp" +#include "./equivalent.hpp" +#include "./invariant.hpp" + +// 23.1/5 + TR1 6.3.1/9 row 12 +META_FUNC_TEST_CASE(empty_copy_test1, X) +{ + X x; + test::unordered_equivalence_tester equivalent(x); + + EXCEPTION_TEST(1000) + { + X y(x); + equivalent.test(y); + test::invariant_check(y); + } + EXCEPTION_TEST_END + + test::invariant_check(x); +} + +META_FUNC_TEST_CASE(empty_copy_test2, X) +{ + test::constructors constructor; + X x(100, constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + x.max_load_factor(4.0); + test::unordered_equivalence_tester equivalent(x); + + EXCEPTION_TEST(1000) + { + X y(x); + equivalent.test(y); + test::invariant_check(y); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(range_copy_construct,X) +{ + test::constructors constructor; + test::random_values values(10); + + X x(values.begin(), values.end(), 100, + constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + x.max_load_factor(4.0); + test::unordered_equivalence_tester equivalent(x); + + EXCEPTION_TEST(1000) + { + X y(x); + equivalent.test(y); + test::invariant_check(y); + } + EXCEPTION_TEST_END +} + +template +void check_container(X const& x, test::unordered_equivalence_tester const& equivalent) +{ + equivalent.test(x); + test::invariant_check(x); +} + +META_FUNC_TEST_CASE(anon_copy_construct, X) +{ + test::constructors constructor; + test::random_values values(10); + + X x(values.begin(), values.end(), 100, + constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + x.max_load_factor(4.0); + test::unordered_equivalence_tester equivalent(x); + + EXCEPTION_TEST(1000) + { + check_container(X(x), equivalent); + } + EXCEPTION_TEST_END +} + +template +X return_container(X const& x) +{ + return x; +} + +META_FUNC_TEST_CASE(copy_from_return,X) +{ + test::random_values values(10); + X x(values.begin(), values.end()); + test::unordered_equivalence_tester equivalent(x); + + EXCEPTION_TEST(1000) + { + X y(return_container(x)); + equivalent.test(y); + test::invariant_check(y); + } + EXCEPTION_TEST_END +} + +AUTO_META_TESTS( + (empty_copy_test1)(empty_copy_test2)(range_copy_construct) + (anon_copy_construct)(copy_from_return), + CONTAINER_SEQ +) diff --git a/test/count_tests.cpp b/test/count_tests.cpp new file mode 100644 index 00000000..b900556c --- /dev/null +++ b/test/count_tests.cpp @@ -0,0 +1,65 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/random_values.hpp" + +META_FUNC_TEST_CASE(count_const_test, Container) +{ + test::random_values values(500); + typedef typename test::random_values::iterator iterator; + + Container const x(values.begin(), values.end()); + + for(iterator it = values.begin(); it != values.end(); ++it) + { + BOOST_CHECK_EQUAL(x.count(values.get_key(*it)), values.key_count(*it)); + } + + typedef typename test::random_values::value_type value_type; + test::generator generator; + + for(int i = 0; i < 500; ++i) + { + value_type value = generator(); + BOOST_CHECK_EQUAL(x.count(values.get_key(value)), values.key_count(value)); + } +} + +META_FUNC_TEST_CASE(count_nonconst_test, Container) +{ + test::random_values values(500); + typedef typename test::random_values::iterator iterator; + + Container x(values.begin(), values.end()); + + for(iterator it = values.begin(); it != values.end(); ++it) + { + BOOST_CHECK_EQUAL(x.count(values.get_key(*it)), values.key_count(*it)); + } +} + +META_FUNC_TEST_CASE(empty_test, Container) +{ + typedef test::random_values random_values; + typedef typename random_values::value_type value_type; + test::generator generator; + Container x; + + for(int i = 0; i < 500; ++i) + { + BOOST_CHECK_EQUAL(x.count(random_values::get_key(generator())), 0u); + } +} + +AUTO_META_TESTS( + (count_const_test)(count_nonconst_test)(empty_test), + CONTAINER_SEQ +) diff --git a/test/equal_range_tests.cpp b/test/equal_range_tests.cpp new file mode 100644 index 00000000..0f1fedbf --- /dev/null +++ b/test/equal_range_tests.cpp @@ -0,0 +1,100 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/random_values.hpp" + +template +OutputIt copy_if(InputIt begin, InputIt end, OutputIt out, Condition cond) +{ + for(;begin != end; ++begin) + { + if(cond(*begin)) { + *out = *begin; + ++out; + } + } + + return out; +} + +template +void compare(std::pair const& range, + RandomValues const& values, Value const& v) +{ + typedef typename RandomValues::value_type value_type; + typedef std::vector value_container; + value_container range_values(range.first, range.second); + value_container orig_values; + copy_if(values.begin(), values.end(), std::back_inserter(orig_values), + values.key_match(v)); + + if(values.is_unique()) { + if(orig_values.empty()) { + BOOST_CHECK_EQUAL(range_values.size(), 0u); + } + else { + BOOST_CHECK_EQUAL(range_values.size(), 1u); + BOOST_CHECK(orig_values.front() == *range_values.begin()); + } + } + else { + std::sort(range_values.begin(), range_values.end()); + std::sort(orig_values.begin(), orig_values.end()); + BOOST_CHECK_EQUAL(range_values.size(), orig_values.size()); + if(range_values.size() == orig_values.size()) + BOOST_CHECK(std::equal(range_values.begin(), range_values.end(), + orig_values.begin())); + } +} + +META_FUNC_TEST_CASE(const_test, Container) +{ + test::random_values values(500); + typedef test::random_values random_values; + typedef typename random_values::iterator iterator; + + Container const x(values.begin(), values.end()); + + for(iterator it = values.begin(); it != values.end(); ++it) + { + compare(x.equal_range(values.get_key(*it)), + values, values.get_key(*it)); + } + + typedef typename random_values::value_type value_type; + test::generator generator; + + for(int i = 0; i < 500; ++i) + { + value_type v = generator(); + compare(x.equal_range(values.get_key(v)), + values, values.get_key(v)); + } +} + +META_FUNC_TEST_CASE(nonconst_test, Container) +{ + test::random_values values(500); + typedef typename test::random_values::iterator iterator; + + Container const x(values.begin(), values.end()); + + for(iterator it = values.begin(); it != values.end(); ++it) + { + compare(x.equal_range(values.get_key(*it)), + values, values.get_key(*it)); + } +} + +AUTO_META_TESTS( + (const_test)(nonconst_test), + CONTAINER_SEQ +) diff --git a/test/equivalent.hpp b/test/equivalent.hpp new file mode 100644 index 00000000..ce8808a3 --- /dev/null +++ b/test/equivalent.hpp @@ -0,0 +1,112 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER) +#define BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER + +#include "./helpers/strong.hpp" +#include "./helpers/equivalent.hpp" +#include "./helpers/metafunctions.hpp" +#include "./helpers/less.hpp" +#include +#include +#include +#include + +namespace test +{ + struct equals2_t + { + template + bool operator()(X const& x, Y const& y) + { + return x == y; + } + + template + bool operator()(std::pair const& x, std::pair const& y) + { + return x.first == y.first && x.second == y.second; + } + } equals2; + + template + class unordered_equivalence_tester + { + typename Container::size_type size_; + typename Container::hasher hasher_; + typename Container::key_equal key_equal_; + float max_load_factor_; + std::vector::type> values_; + public: + unordered_equivalence_tester(Container const &x) + : size_(x.size()), + hasher_(x.hash_function()), key_equal_(x.key_eq()), + max_load_factor_(x.max_load_factor()), + values_(x.begin(), x.end()) + { + std::sort(values_.begin(), values_.end(), + test::compare()); + } + + void test(Container const& x) const + { + BOOST_CHECK(size_ == x.size()); + BOOST_CHECK(test::equivalent(hasher_, x.hash_function())); + BOOST_CHECK(test::equivalent(key_equal_, x.key_eq())); + BOOST_CHECK(max_load_factor_ == x.max_load_factor()); + BOOST_CHECK(values_.size() == x.size()); + if(values_.size() == x.size()) { + std::vector::type> + copy(x.begin(), x.end()); + std::sort(copy.begin(), copy.end(), test::compare()); + BOOST_CHECK( + std::equal(values_.begin(), values_.end(), copy.begin(), + equals2)); + } + } + private: + unordered_equivalence_tester(); + }; +} + +#if 0 +namespace boost +{ + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_set const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_set >(x)); + } + + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_multiset const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_multiset >(x)); + } + + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_map const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_map >(x)); + } + + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_multimap const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_multimap >(x)); + } +} +#endif + +#endif diff --git a/test/erase_tests.cpp b/test/erase_tests.cpp new file mode 100644 index 00000000..306ef5e9 --- /dev/null +++ b/test/erase_tests.cpp @@ -0,0 +1,190 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/constructors.hpp" +#include "./invariant.hpp" + +META_FUNC_TEST_CASE(range_erase_test,Container) +{ + test::constructors constructor; + + test::random_values values(100); + typedef typename Container::iterator iterator; + + { + Container x(values.begin(), values.end(), 0, + constructor.hasher(55), + constructor.key_equal(55), + constructor.allocator(10)); + const std::size_t size = x.size(); + INVARIANT_CHECK(x); + iterator pos; + + // Should be no throw. + ACTIVATE_EXCEPTIONS; + + BOOST_CHECKPOINT("Erase nothing from the beginning"); + BOOST_CHECK(x.begin() == x.erase(x.begin(), x.begin())); + BOOST_CHECK_EQUAL(x.size(), size); + test::check_invariants(); + + BOOST_CHECKPOINT("Erase nothing from the end"); + BOOST_CHECK(x.end() == x.erase(x.end(), x.end())); + BOOST_CHECK_EQUAL(x.size(), size); + test::check_invariants(); + + BOOST_CHECKPOINT("Erase nothing from the middle"); + BOOST_CHECK(boost::next(x.begin(), 4) == x.erase( + boost::next(x.begin(), 4), + boost::next(x.begin(), 4))); + BOOST_CHECK_EQUAL(x.size(), size); + test::check_invariants(); + + BOOST_CHECKPOINT("Erase 3 from the middle"); + pos = x.erase(boost::next(x.begin(), 1), boost::next(x.begin(), 4)); + BOOST_CHECK(boost::next(x.begin(), 1) == pos); + BOOST_CHECK_EQUAL(x.size(), size - 3); + test::check_invariants(); + + BOOST_CHECKPOINT("Erase all but the first 1"); + pos = x.erase(boost::next(x.begin(), 1), x.end()); + BOOST_CHECK(x.end() == pos); + BOOST_CHECK_EQUAL(x.size(), 1u); + test::check_invariants(); + } + + { + Container x(values.begin(), values.end()); + const std::size_t size = x.size(); + INVARIANT_CHECK(x); + iterator pos; + + // Should be no throw. + ACTIVATE_EXCEPTIONS; + + BOOST_CHECKPOINT("Erase first 2"); + pos = x.erase(x.begin(), boost::next(x.begin(), 2)); + BOOST_CHECK(x.begin() == pos); + BOOST_CHECK_EQUAL(x.size(), size - 2); + test::check_invariants(); + } + + { + Container x(values.begin(), values.end()); + INVARIANT_CHECK(x); + iterator pos; + + // Should be no throw. + ACTIVATE_EXCEPTIONS; + + BOOST_CHECKPOINT("Erase all"); + pos = x.erase(x.begin(), x.end()); + BOOST_CHECK(x.begin() == pos && x.end() == pos); + BOOST_CHECK(x.empty()); + test::check_invariants(); + } +} + +META_FUNC_TEST_CASE(erase_by_key_test,Container) +{ + test::constructors constructor; + test::sorted_random_values values(10); + + // Exceptions only from the hash function. + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x(values.begin(), values.end(), 0, + constructor.hasher(55), + constructor.key_equal(55), + constructor.allocator(10)); + INVARIANT_CHECK(x); + + for(int i = 0; i < 10; i += values.count(values[i])) { + std::size_t key_count = values.key_count(values[i]); + { + ACTIVATE_EXCEPTIONS; + BOOST_CHECK_EQUAL(key_count, + x.erase(values.get_key(values[i]))); + } + BOOST_CHECK(x.find(values.get_key(values[i])) == x.end()); + BOOST_CHECK_EQUAL(0u, x.erase(values.get_key(values[i]))); + } + + BOOST_CHECK(x.empty()); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(erase_subrange_test,Container) +{ + test::random_values values(100); + Container x(values.begin(), values.end()); + + // Should be no throw. + ACTIVATE_EXCEPTIONS; + + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + std::size_t length = x.size(); + std::size_t begin_index = length / 2; + std::size_t end_index = (length + begin_index) / 2; + std::size_t sub_begin_index = (end_index - begin_index) / 4; + std::size_t sub_end_index = sub_begin_index * 3; + + const_iterator begin = boost::next(x.begin(), begin_index); + const_iterator end = boost::next(x.begin(), end_index); + + iterator pos = x.erase(boost::next(begin, sub_begin_index), + boost::next(begin, sub_end_index)); + + BOOST_CHECK(pos == boost::next(x.begin(), begin_index + sub_begin_index)); + BOOST_CHECK(pos == boost::next(begin, sub_begin_index)); + BOOST_CHECK_EQUAL( + (end_index - begin_index) - (sub_end_index - sub_begin_index), + static_cast(std::distance(begin, end))); + + test::invariant_check(x); +} + +META_FUNC_TEST_CASE(erase_by_iterator_test,Container) +{ + test::random_values values(100); + Container x(values.begin(), values.end()); + INVARIANT_CHECK(x); + std::size_t size = x.size(); + + typedef typename Container::iterator iterator; + + // Should be no throw. + ACTIVATE_EXCEPTIONS; + + while(!x.empty()) { + using namespace std; + int index = rand() % x.size(); + iterator pos = x.erase(boost::next(x.begin(), index)); + --size; + BOOST_CHECK_EQUAL(size, x.size()); + + BOOST_CHECK(boost::next(x.begin(), index) == pos); + test::check_invariants(); + } +} + +AUTO_META_TESTS( + (range_erase_test)(erase_by_key_test)(erase_subrange_test) + (erase_by_iterator_test), + CONTAINER_SEQ +) diff --git a/test/find_tests.cpp b/test/find_tests.cpp new file mode 100644 index 00000000..cab61bd9 --- /dev/null +++ b/test/find_tests.cpp @@ -0,0 +1,78 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include "./helpers/unit_test.hpp" +#include "./helpers/random_values.hpp" + +META_FUNC_TEST_CASE(find_const_test,Container) +{ + test::random_values values(500); + typedef typename test::random_values::iterator iterator; + + Container const x(values.begin(), values.end()); + + for(iterator it = values.begin(); it != values.end(); ++it) + { + typename Container::const_iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end()); + BOOST_CHECK(values.get_key(*pos) == values.get_key(*it)); + } +} + +META_FUNC_TEST_CASE(find_nonconst_test,Container) +{ + test::random_values values(500); + typedef typename test::random_values::iterator iterator; + + Container x(values.begin(), values.end()); + + for(iterator it = values.begin(); it != values.end(); ++it) + { + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end()); + BOOST_CHECK(values.get_key(*pos) == values.get_key(*it)); + } +} + +META_FUNC_TEST_CASE(missing_test,Container) +{ + test::random_values values(10); + Container x(values.begin(), values.end()); + + typedef typename test::random_values::value_type value_type; + test::generator generator; + + for(int i = 0; i < 500; ++i) + { + value_type const value = generator(); + bool const present_in_values = values.find(value) != values.end(); + bool const present_in_container = x.find(values.get_key(value)) + != x.end(); + BOOST_CHECK(present_in_values == present_in_container); + } +} + +META_FUNC_TEST_CASE(empty_test,Container) +{ + typedef test::random_values random_values; + typedef typename random_values::value_type value_type; + test::generator generator; + Container x; + + for(int i = 0; i < 500; ++i) + { + BOOST_CHECK(x.find(random_values::get_key(generator())) == x.end()); + } +} + +AUTO_META_TESTS( + (find_const_test)(find_nonconst_test)(missing_test)(empty_test), + CONTAINER_SEQ +) diff --git a/test/helpers/accessors.hpp b/test/helpers/accessors.hpp new file mode 100644 index 00000000..f5abfefd --- /dev/null +++ b/test/helpers/accessors.hpp @@ -0,0 +1,12 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_ACCESSORS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_ACCESSORS_HEADER + +namespace test +{ + +} diff --git a/test/helpers/allocator.cpp b/test/helpers/allocator.cpp new file mode 100644 index 00000000..830dd7bb --- /dev/null +++ b/test/helpers/allocator.cpp @@ -0,0 +1,209 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./config.hpp" +#include "./allocator.hpp" +#include "./exception_trigger.hpp" +#include "./exception.hpp" +#include +#include + +#if !defined(BOOST_OLD_IOSTREAMS) +# include +#else +# include +#endif + +namespace test +{ + namespace + { + const unsigned int max_track = 1000; + + struct allocate_details + { + int tag; + std::size_t length; + + allocate_details() + : tag(0), length(0) {} + + allocate_details(int t, int l) + : tag(t), length(l) {} + }; + + std::map allocate_map; + unsigned int reference_count = 0; + unsigned int alloc_count = 0; + + static void ref() + { + ++reference_count; + } + + static void unref() + { + if(--reference_count == 0) { + BOOST_CHECK_MESSAGE(alloc_count == 0 && allocate_map.empty(), + "Memory leak found"); + allocate_map.clear(); + } + } + } + + allocator_base::allocator_base(int x) + : tag(x) + { + ref(); + } + + allocator_base::allocator_base(allocator_base const& x) + : tag(x.tag) + { + ref(); + } + + allocator_base::~allocator_base() + { + unref(); + } + + allocator_base::size_type allocator_base::max_size() const + { + return (std::numeric_limits::max)(); + } + + void* allocator_base::allocate(size_type n, void const*, size_type size) + { + BOOST_CHECK(n <= max_size()); + + exception_trigger((allocator_exception*) 0); + + // TODO: This is not exception safe. + void* ptr = ::operator new(n * size); + ++alloc_count; + if(allocate_map.size() < max_track) + allocate_map[ptr] = allocate_details(tag, n); + + return ptr; + } + + void allocator_base::construct(void* ptr) + { + exception_trigger((allocator_exception*) 0); + } + + void allocator_base::destroy(void* ptr) + { + } + + void allocator_base::deallocate(void* ptr, size_type n) + { + BOOST_CHECK(n <= max_size()); + if(allocate_map.find(ptr) == allocate_map.end()) { + if(alloc_count <= allocate_map.size()) + BOOST_ERROR("Deallocating unknown pointer."); + } else { + // TODO: This is not exception safe. + BOOST_CHECK_EQUAL(allocate_map[ptr].tag, tag); + BOOST_CHECK_EQUAL(allocate_map[ptr].length, n); + allocate_map.erase(ptr); + ::operator delete(ptr); + } + --alloc_count; + } + + void allocator_base::swap(allocator_base& x) + { + std::swap(tag, x. tag); + } + + std::ostream& operator<<(std::ostream& out, allocator_base const& x) + { + out<<"Test Allocator("<::max)() / 4; + } + + void* minimal_allocator_base::allocate(size_type n, void const*, size_type size) + { + BOOST_CHECK(n <= max_size()); + + exception_trigger((allocator_exception*) 0); + + // TODO: This is not exception safe. + void* ptr = ::operator new(n * size); + allocate_map[ptr] = allocate_details(tag, n); + + return ptr; + } + + void minimal_allocator_base::construct(void* ptr) + { + exception_trigger((allocator_exception*) 0); + } + + void minimal_allocator_base::destroy(void* ptr) + { + } + + void minimal_allocator_base::deallocate(void* ptr, size_type n) + { + BOOST_CHECK(n <= max_size()); + if(allocate_map.find(ptr) == allocate_map.end()) { + BOOST_ERROR("Deallocating unknown pointer."); + } else { + // TODO: This is not exception safe. + BOOST_CHECK_EQUAL(allocate_map[ptr].tag, tag); + BOOST_CHECK_EQUAL(allocate_map[ptr].length, n); + allocate_map.erase(ptr); + ::operator delete(ptr); + } + } + + void minimal_allocator_base::swap(minimal_allocator_base& x) + { + std::swap(tag, x. tag); + } + + std::ostream& operator<<(std::ostream& out, minimal_allocator_base const& x) + { + out<<"Minimal Allocator("< +#include +#include + +namespace test +{ + struct allocator_base + { + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + int tag; + + allocator_base(int x); + allocator_base(allocator_base const&); + ~allocator_base(); + + size_type max_size() const; + + void* allocate(size_type, void const*, size_type); + void construct(void*); + void destroy(void*); + void deallocate(void*, size_type); + void swap(allocator_base&); + private: + allocator_base& operator=(allocator_base const&); + }; + + std::ostream& operator<<(std::ostream&, allocator_base const&); + bool allocator_equals(allocator_base const& x, allocator_base const& y); + + template + struct allocator : allocator_base + { + typedef T* pointer; + typedef T const* const_pointer; + typedef T& reference; + typedef T const& const_reference; + typedef T value_type; + + template + struct rebind + { + typedef allocator other; + }; + + pointer address(reference x) const + { + return &x; + } + + const_pointer address(const_reference x) const + { + return &x; + } + + allocator(int x = 1) : allocator_base(x) {} + template + allocator(allocator const& x) : allocator_base(x) {} + allocator(allocator const& x) : allocator_base(x) {} + ~allocator() {} + + pointer allocate(size_type n, T const* hint = 0) + { + return static_cast( + allocator_base::allocate(n, hint, sizeof(T))); + } + + void construct(pointer ptr, T const& x) + { + allocator_base::construct(ptr); + new((void*)ptr)T(x); + } + + void destroy(pointer ptr) + { + allocator_base::destroy(ptr); + ptr->~T(); + } + + void deallocate(pointer ptr, size_type n) + { + allocator_base::deallocate(ptr, n); + } + }; + + template + inline bool operator==(allocator const& x, allocator const& y) + { + return test::allocator_equals(x, y); + } + + template + inline bool operator!=(allocator const& x, allocator const& y) + { + return !test::allocator_equals(x, y); + } + + template + void swap(allocator& x, allocator& y) + { + x.swap(y); + } + + template + allocator create_allocator(allocator*) + { + return allocator(); + } + + template + allocator create_allocator(allocator*, int x) + { + return allocator(x); + } + + template struct minimal_allocator; + typedef unsigned short minimal_size_type; + + template + class minimal_pointer_base + { + protected: + typedef minimal_pointer_base pointer_base; + minimal_pointer_base() : ptr_(0) {} + explicit minimal_pointer_base(T* ptr) : ptr_(ptr) {} + ~minimal_pointer_base() {} + Ptr& get() { return *static_cast(this); } + T* ptr_; + public: + typedef void (minimal_pointer_base::*bool_type)() const; + void this_type_does_not_support_comparisons() const {} + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + Ptr& operator++() { ++ptr_; return get(); } + Ptr operator++(int) { Ptr tmp(get()); ++ptr_; return tmp; } + + Ptr operator+(minimal_size_type s) const + { + return Ptr(ptr_ + s); + } + + T& operator[](minimal_size_type s) const + { + return ptr_[s]; + } + + operator bool_type() const + { + return ptr_ ? + &minimal_pointer_base::this_type_does_not_support_comparisons + : 0; + } + + bool operator!() const { return !ptr_; } + bool operator==(Ptr const& x) const { return ptr_ == x.ptr_; } + bool operator!=(Ptr const& x) const { return ptr_ != x.ptr_; } + bool operator<(Ptr const& x) const { return ptr_ < x.ptr_; } + bool operator>(Ptr const& x) const { return ptr_ > x.ptr_; } + bool operator<=(Ptr const& x) const { return ptr_ <= x.ptr_; } + bool operator>=(Ptr const& x) const { return ptr_ >= x.ptr_; } + + friend std::ostream& operator<<(std::ostream& out, minimal_pointer_base const& x) + { + out< class minimal_pointer; + template class minimal_const_pointer; + + template + class minimal_pointer + : public minimal_pointer_base, T> + { + friend struct minimal_allocator; + friend class minimal_pointer_base, T>; + friend class minimal_const_pointer; + typedef typename minimal_pointer::pointer_base base; + minimal_pointer(T* ptr) : base(ptr) {} + + typedef minimal_const_pointer const_pointer; + typedef minimal_pointer pointer; + public: + minimal_pointer() : base() {} + + bool operator==(pointer const& x) const { return base::operator==(x); } + bool operator!=(pointer const& x) const { return base::operator!=(x); } + bool operator<(pointer const& x) const { return base::operator<(x);} + bool operator>(pointer const& x) const { return base::operator>(x);} + bool operator<=(pointer const& x) const { return base::operator<=(x);} + bool operator>=(pointer const& x) const { return base::operator<=(x);} + + bool operator==(const_pointer const& x) const { return x == *this; } + bool operator!=(const_pointer const& x) const { return x != *this; } + bool operator<(const_pointer const& x) const { return x > *this; } + bool operator>(const_pointer const& x) const { return x < *this; } + bool operator<=(const_pointer const& x) const { return x >= *this; } + bool operator>=(const_pointer const& x) const { return x <= *this; } + }; + + template + class minimal_const_pointer + : public minimal_pointer_base, T const> + { + friend struct minimal_allocator; + friend class minimal_pointer_base, T const>; + typedef typename minimal_const_pointer::pointer_base base; + minimal_const_pointer(T* ptr) : base(ptr) {} + + typedef minimal_const_pointer const_pointer; + typedef minimal_pointer pointer; + public: + minimal_const_pointer() : base() {} + minimal_const_pointer(minimal_pointer const& x) : base(x.ptr_) {} + + bool operator==(const_pointer const& x) const { return base::operator==(x); } + bool operator!=(const_pointer const& x) const { return base::operator!=(x); } + bool operator<(const_pointer const& x) const { return base::operator<(x);} + bool operator>(const_pointer const& x) const { return base::operator>(x);} + bool operator<=(const_pointer const& x) const { return base::operator<=(x);} + bool operator>=(const_pointer const& x) const { return base::operator<=(x);} + + bool operator==(pointer const& x) const { return operator==(const_pointer(x)); } + bool operator!=(pointer const& x) const { return operator!=(const_pointer(x)); } + bool operator<(pointer const& x) const { return operator<(const_pointer(x));} + bool operator>(pointer const& x) const { return operator>(const_pointer(x));} + bool operator<=(pointer const& x) const { return operator<=(const_pointer(x));} + bool operator>=(pointer const& x) const { return operator<=(const_pointer(x));} + }; + + struct minimal_allocator_base + { + typedef minimal_size_type size_type; + typedef std::ptrdiff_t difference_type; + + int tag; + + minimal_allocator_base(int x); + minimal_allocator_base(minimal_allocator_base const&); + ~minimal_allocator_base(); + + size_type max_size() const; + + void* allocate(size_type, void const*, size_type); + void construct(void*); + void destroy(void*); + void deallocate(void*, size_type); + void swap(minimal_allocator_base&); + private: + minimal_allocator_base& operator=(minimal_allocator_base const&); + }; + + std::ostream& operator<<(std::ostream&, minimal_allocator_base const&); + bool allocator_equals(minimal_allocator_base const&, minimal_allocator_base const&); + + template + struct minimal_allocator : minimal_allocator_base + { + typedef minimal_pointer pointer; + typedef minimal_const_pointer const_pointer; + typedef T& reference; + typedef T const& const_reference; + typedef T value_type; + + template + struct rebind + { + typedef minimal_allocator other; + }; + + pointer address(reference r) + { + return pointer(&r); + } + + const_pointer address(const_reference r) + { + return const_pointer(&r); + } + + pointer allocate(size_type n) + { + return pointer(static_cast( + minimal_allocator_base::allocate(n, 0, sizeof(T)))); + } + + pointer allocate(size_type n, const_pointer u) + { + return pointer(static_cast( + minimal_allocator_base::allocate(n, u.ptr_, sizeof(T)))); + } + + void deallocate(pointer p, size_type n) + { + minimal_allocator_base::deallocate(p.ptr_, n); + } + + minimal_allocator() + : minimal_allocator_base(0) + { + } + + explicit minimal_allocator(int tag) + : minimal_allocator_base(tag) + { + } + + template + minimal_allocator(minimal_allocator const& x) + : minimal_allocator_base(x) + { + } + + minimal_allocator(minimal_allocator const& x) + : minimal_allocator_base(x) + { + } + + void construct(pointer p, T const& t) + { + minimal_allocator_base::construct(p.ptr_); + new((void*)p.ptr_) T(t); + } + + void destroy(pointer p) + { + minimal_allocator_base::destroy(p.ptr_); + ((T*)p.ptr_)->~T(); + } + private: + minimal_allocator& operator=(minimal_allocator const&); + }; + + template + inline bool operator==(minimal_allocator const& x, minimal_allocator const& y) + { + return test::allocator_equals(x, y); + } + + template + inline bool operator!=(minimal_allocator const& x, minimal_allocator const& y) + { + return !test::allocator_equals(x, y); + } + + template + void swap(minimal_allocator& x, minimal_allocator& y) + { + x.swap(y); + } + + template + minimal_allocator create_allocator(minimal_allocator*) + { + return minimal_allocator(); + } + + template + minimal_allocator create_allocator(minimal_allocator*, int x) + { + return minimal_allocator(x); + } +} + +#endif diff --git a/test/helpers/base.cpp b/test/helpers/base.cpp new file mode 100644 index 00000000..d351b08e --- /dev/null +++ b/test/helpers/base.cpp @@ -0,0 +1,31 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./base.hpp" +#include +#include + +namespace test +{ + namespace + { + std::vector end_checks; + } + + void register_end_check(void(*check)()) + { + end_checks.push_back(check); + } + + void call_check(void(*check)()) + { + check(); + } + + void end() + { + std::for_each(end_checks.begin(), end_checks.end(), call_check); + } +} diff --git a/test/helpers/base.hpp b/test/helpers/base.hpp new file mode 100644 index 00000000..5cc58b1a --- /dev/null +++ b/test/helpers/base.hpp @@ -0,0 +1,15 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_BASE_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_BASE_HEADER + +namespace test +{ + void register_end_check(void(*)()); + void end(); +} + +#endif diff --git a/test/helpers/config.hpp b/test/helpers/config.hpp new file mode 100644 index 00000000..5ac1a11e --- /dev/null +++ b/test/helpers/config.hpp @@ -0,0 +1,18 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_CONFIG_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_CONFIG_HEADER + +#include + +// From Boost.Dynamic Bitset: + +// support for pre 3.0 libstdc++ - thanks Phil Edwards! +#if defined (__STL_CONFIG_H) && !defined (__STL_USE_NEW_IOSTREAMS) +# define BOOST_OLD_IOSTREAMS +#endif + +#endif diff --git a/test/helpers/constructors.hpp b/test/helpers/constructors.hpp new file mode 100644 index 00000000..51925509 --- /dev/null +++ b/test/helpers/constructors.hpp @@ -0,0 +1,69 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_CONSTRUCTORS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_CONSTRUCTORS_HEADER + +namespace test +{ + template + Allocator create_allocator(Allocator*, int = 0) + { + return Allocator(); + } + + template + Hasher create_hasher(Hasher*, int = 0) + { + return Hasher(); + } + + template + KeyEqual create_key_equal(KeyEqual*, int = 0) + { + return KeyEqual(); + } + + template + class constructors + { + public: + typedef typename Container::allocator_type allocator_type; + typedef typename Container::hasher hasher_type; + typedef typename Container::key_equal key_equal_type; + + allocator_type allocator() const + { + return create_allocator((allocator_type*) 0); + } + + allocator_type allocator(int x) const + { + return create_allocator((allocator_type*) 0, x); + } + + hasher_type hasher() const + { + return create_hasher((hasher_type*) 0); + } + + hasher_type hasher(int x) const + { + return create_hasher((hasher_type*) 0, x); + } + + key_equal_type key_equal() const + { + return create_key_equal((key_equal_type*) 0); + } + + key_equal_type key_equal(int x) const + { + return create_key_equal((key_equal_type*) 0, x); + } + }; +} + +#endif diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp new file mode 100644 index 00000000..3416a838 --- /dev/null +++ b/test/helpers/equivalent.hpp @@ -0,0 +1,45 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_EQUIVALENT_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_EQUIVALENT_HEADER + +#include +#include + +namespace test +{ + template + bool equivalent_impl(std::equal_to, std::equal_to, int) + { + return true; + } + + template + bool equivalent_impl(boost::hash, boost::hash, int) + { + return true; + } + + template + bool equivalent_impl(T const& x, T const& y, float) + { + return x == y; + } + + template + bool equivalent(T const& x, T const& y) + { + return equivalent_impl(x, y, 0); + } + + template + bool equivalent(std::pair const& x, std::pair const& y) + { + return equivalent(x.first, y.first) && equivalent(x.second, y.second); + } +} + +#endif diff --git a/test/helpers/exception.cpp b/test/helpers/exception.cpp new file mode 100644 index 00000000..b50638cd --- /dev/null +++ b/test/helpers/exception.cpp @@ -0,0 +1,85 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./exception.hpp" + +namespace test +{ + exception::exception() + : message_("Triggered test exception") + { + } + + exception::exception(char const* message) + : message_(message) + { + } + + char const* exception::what() const throw() + { + return message_; + } + + hash_exception::hash_exception() + : exception("Triggered hash exception") + { + } + + hash_exception::hash_exception(char const* message) + : exception(message) + { + } + + hash_copy_exception::hash_copy_exception() + : hash_exception("Triggered hash copy exception") + { + } + + hash_copy_exception::hash_copy_exception(char const* message) + : hash_exception(message) + { + } + + pred_exception::pred_exception() + : exception("Triggered pred exception") + { + } + + pred_exception::pred_exception(char const* message) + : exception(message) + { + } + + pred_copy_exception::pred_copy_exception() + : pred_exception("Triggered pred copy exception") + { + } + + pred_copy_exception::pred_copy_exception(char const* message) + : pred_exception(message) + { + } + + allocator_exception::allocator_exception() + : exception("Triggered pred exception") + { + } + + allocator_exception::allocator_exception(char const* message) + : exception(message) + { + } + + allocator_copy_exception::allocator_copy_exception() + : allocator_exception("Triggered pred copy exception") + { + } + + allocator_copy_exception::allocator_copy_exception(char const* message) + : allocator_exception(message) + { + } +} + diff --git a/test/helpers/exception.hpp b/test/helpers/exception.hpp new file mode 100644 index 00000000..692ceaf2 --- /dev/null +++ b/test/helpers/exception.hpp @@ -0,0 +1,60 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_EXCEPTION_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_EXCEPTION_HEADER + +#include + +namespace test +{ + // Exception Handling + + struct exception : std::exception + { + char const* message_; + exception(); + exception(char const*); + char const* what() const throw(); + }; + + struct hash_exception : exception + { + hash_exception(); + hash_exception(char const*); + }; + + struct hash_copy_exception : hash_exception + { + hash_copy_exception(); + hash_copy_exception(char const*); + }; + + struct pred_exception : exception + { + pred_exception(); + pred_exception(char const*); + }; + + struct pred_copy_exception : pred_exception + { + pred_copy_exception(); + pred_copy_exception(char const*); + }; + + struct allocator_exception : exception + { + allocator_exception(); + allocator_exception(char const*); + }; + + struct allocator_copy_exception : allocator_exception + { + allocator_copy_exception(); + allocator_copy_exception(char const*); + }; +} + +#endif diff --git a/test/helpers/exception_test.cpp b/test/helpers/exception_test.cpp new file mode 100644 index 00000000..a8ec3e12 --- /dev/null +++ b/test/helpers/exception_test.cpp @@ -0,0 +1,108 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./exception_test.hpp" +#include +#include +#include + +namespace test +{ + // TODO: (Writing this here instead of the headers to avoid recompiling + // the world) + // + // There are some major design flaws with the exception testing code, + // apart from global variables that is. + + namespace + { + int num_iterations = 0; + int current_iteration = 0; + int trigger_count = 0; + int max_trigger_count = 0; + bool failed = false; + bool exception_testing = false; + bool exceptions_active = false; + } + + void exception_start(int n) + { + num_iterations = n; + current_iteration = 0; + max_trigger_count = 0; + trigger_count = 0; + failed = false; + exception_testing = true; + exceptions_active = true; + } + + void exception_loop() + { + BOOST_CHECK(exceptions_active); + + ++current_iteration; + max_trigger_count = trigger_count; + exception_testing = failed; + exceptions_active = failed; + trigger_count = 0; + failed = false; + } + + bool exception_loop_test() + { + if(exception_testing && current_iteration == num_iterations) { + BOOST_ERROR("Too many iterations"); + return false; + } + else { + return exception_testing; + } + } + + void exception_failure() + { + failed = true; + } + + bool true_once() + { + ++trigger_count; + return !exception_testing || trigger_count > max_trigger_count; + } + + bool exception_trigger_test() + { + ++trigger_count; + return exception_testing && exceptions_active + && trigger_count > max_trigger_count; + } + + void exception_trigger() + { + if(exception_trigger_test()) throw exception(); + } + + void exception_trigger(char const* message) + { + if(exception_trigger_test()) throw exception(message); + } + + bool exceptions_activate(bool value) + { + bool old = exceptions_active; + exceptions_active = value; + return old; + } + + exception_control::exception_control(bool value) + : old_value(exceptions_activate(value)) + { + } + + exception_control::~exception_control() + { + exceptions_activate(old_value); + } +} diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp new file mode 100644 index 00000000..80fb3db1 --- /dev/null +++ b/test/helpers/exception_test.hpp @@ -0,0 +1,33 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_EXCEPTION_TEST_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_EXCEPTION_TEST_HEADER + +#include +#include +#include "./exception.hpp" +#include "./exception_trigger.hpp" +#include "./base.hpp" + +namespace test +{ + void exception_start(int); + bool exception_loop_test(); + void exception_loop(); + void exception_failure(); + + bool true_once(); +} + +#define EXCEPTION_TEST(count) \ + for(::test::exception_start(count); ::test::exception_loop_test(); \ + ::test::exception_loop()) \ + try + +#define EXCEPTION_TEST_END \ + catch(::test::exception const&) { ::test::exception_failure(); } + +#endif diff --git a/test/helpers/exception_trigger.hpp b/test/helpers/exception_trigger.hpp new file mode 100644 index 00000000..358ea7f6 --- /dev/null +++ b/test/helpers/exception_trigger.hpp @@ -0,0 +1,49 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_EXCEPTION_TRIGGER_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_EXCEPTION_TRIGGER_HEADER + +#include + +namespace test +{ + // Exception Handling + + bool exception_trigger_test(); + void exception_trigger(); + void exception_trigger(char const*); + + template + void exception_trigger(T*) + { + if(exception_trigger_test()) throw T(); + } + + template + void exception_trigger(T*, char const* msg) + { + if(exception_trigger_test()) throw T(msg); + } + + struct exception_control + { + bool old_value; + + exception_control(bool); + ~exception_control(); + }; + +} + +#define ACTIVATE_EXCEPTIONS \ + ::test::exception_control BOOST_PP_CAT(ACTIVATE_EXCEPTIONS_, __LINE__) \ + (true) +#define DEACTIVATE_EXCEPTIONS \ + ::test::exception_control BOOST_PP_CAT(ACTIVATE_EXCEPTIONS_, __LINE__) \ + (false) + +#endif + diff --git a/test/helpers/functional.cpp b/test/helpers/functional.cpp new file mode 100644 index 00000000..03458b41 --- /dev/null +++ b/test/helpers/functional.cpp @@ -0,0 +1,140 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./config.hpp" +#include "./functional.hpp" +#include "./exception.hpp" +#include "./exception_trigger.hpp" +#include +#include + +#if !defined(BOOST_OLD_IOSTREAMS) +# include +#else +# include +#endif + +namespace test +{ + // Hash + + hash::hash(int x) + : offset(x) {} + + hash::hash(hash const& x) + : offset(x.offset) + { + exception_trigger((hash_copy_exception*) 0); + } + + hash& hash::operator=(hash const& x) + { + exception_trigger((hash_copy_exception*) 0); + offset = x.offset; + exception_trigger((hash_copy_exception*) 0); + + return *this; + } + + std::size_t hash::calculate_hash(std::size_t x) const + { + exception_trigger((hash_exception*) 0); + return x + offset; + } + + std::size_t hash::operator()(char const* x) const + { + return calculate_hash(boost::hash()(x)); + } + + bool hash::operator==(hash const& x) const + { + return offset == x.offset; + } + + std::ostream& operator<<(std::ostream& out, hash x) + { + out<<"Test Hash("< +#include + +namespace test +{ + struct hash + { + int offset; + + explicit hash(int x = 1); + hash(hash const&); + hash& operator=(hash const&); + + std::size_t calculate_hash(std::size_t) const; + + template + std::size_t operator()(T const& x) const + { + return calculate_hash(boost::hash()(x)); + } + + std::size_t operator()(char const* x) const; + bool operator==(hash const& x) const; + }; + + std::ostream& operator<<(std::ostream& out, hash x); + hash create_hasher(hash*); + hash create_hasher(hash*, int x); + + struct equals + { + int tag; + + explicit equals(int x = 1); + equals(equals const&); + equals& operator=(equals const&); + + bool calculate_equals(bool) const; + + template + bool operator()(T1 const& x, T2 const& y) const + { + return calculate_equals(x == y); + } + + bool operator()(char const*, char const*) const; + bool operator==(equals const& x) const; + }; + + std::ostream& operator<<(std::ostream& out, equals x); + equals create_key_equal(equals*); + equals create_key_equal(equals*, int x); + + struct less + { + int tag; + + explicit less(int x = 0); + + template + bool operator()(T1 const& x, T2 const& y) const + { + return x < y; + } + + bool operator()(char const*, char const*) const; + }; + + std::ostream& operator<<(std::ostream& out, less x); +} + +#endif diff --git a/test/helpers/generators.cpp b/test/helpers/generators.cpp new file mode 100644 index 00000000..247a795c --- /dev/null +++ b/test/helpers/generators.cpp @@ -0,0 +1,43 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "generators.hpp" + +// Generators + +namespace test +{ + int generate(int const*) + { + using namespace std; + return rand(); + } + + char generate(char const*) + { + using namespace std; + return (char)(rand() % 26) + 'a'; + } + + std::string generate(std::string const*) + { + using namespace std; + + static test::generator char_gen; + + std::string result; + + int length = rand() % 10; + for(int i = 0; i < length; ++i) + result += char_gen(); + + //std::generate_n( + // std::back_inserter(result), + // rand() % 10, + // char_gen); + + return result; + } +} diff --git a/test/helpers/generators.hpp b/test/helpers/generators.hpp new file mode 100644 index 00000000..3cbb9e37 --- /dev/null +++ b/test/helpers/generators.hpp @@ -0,0 +1,41 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER + +#include +#include +#include + +namespace test +{ + int generate(int const*); + char generate(char const*); + std::string generate(std::string const*); + template std::pair generate( + std::pair const*); + + template + struct generator + { + typedef T value_type; + value_type operator()() + { + return generate((T const*) 0); + } + }; + + template + std::pair generate(std::pair const*) + { + static generator g1; + static generator g2; + + return std::pair(g1(), g2()); + } +} + +#endif diff --git a/test/helpers/input_iterator_adaptor.hpp b/test/helpers/input_iterator_adaptor.hpp new file mode 100644 index 00000000..715e123a --- /dev/null +++ b/test/helpers/input_iterator_adaptor.hpp @@ -0,0 +1,35 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER + +#include + +namespace test +{ + template + struct input_iterator_adaptor + : boost::iterator_adaptor< + input_iterator_adaptor, Iterator, + boost::use_default, std::input_iterator_tag> + { + typedef boost::iterator_adaptor< + input_iterator_adaptor, Iterator, + boost::use_default, std::input_iterator_tag> base; + + explicit input_iterator_adaptor(Iterator it = Iterator()) + : base(it) {} + }; + + template + input_iterator_adaptor make_input_iterator(Iterator it) + { + return input_iterator_adaptor(it); + } +} + +#endif + diff --git a/test/helpers/invariant_checker.cpp b/test/helpers/invariant_checker.cpp new file mode 100644 index 00000000..2f74750a --- /dev/null +++ b/test/helpers/invariant_checker.cpp @@ -0,0 +1,54 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include +#include "./invariant_checker.hpp" +#include +#include +#include + +namespace test +{ + namespace + { + typedef std::set check_set; + check_set checks; + } + + invariant_checker_base::invariant_checker_base() + { + } + + invariant_checker_base::~invariant_checker_base() + { + } + + void check_invariants() + { + // This was causing compile errors on Visual C++, because check + // has return type void. + //std::for_each(checks.begin(), checks.end(), + // boost::mem_fun(&invariant_checker_base::check)); + + check_set::iterator end = checks.end(); + for(check_set::iterator it = checks.begin(); it != end; ++it) + (*it)->check(); + } + + void invariant_add(invariant_checker_base* check) + { + checks.insert(check); + } + + void invariant_remove(invariant_checker_base* check) + { + checks.erase(check); + } + + void initial_check(invariant_checker_base const& x) + { + x.check(); + } +} diff --git a/test/helpers/invariant_checker.hpp b/test/helpers/invariant_checker.hpp new file mode 100644 index 00000000..a678e3b3 --- /dev/null +++ b/test/helpers/invariant_checker.hpp @@ -0,0 +1,78 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER + +#include +#include "./exception_trigger.hpp" + +namespace test +{ + struct invariant_checker_base + { + invariant_checker_base(); + virtual void check() const = 0; + protected: + virtual ~invariant_checker_base(); + }; + + void check_invariants(); + void invariant_add(invariant_checker_base*); + void invariant_remove(invariant_checker_base*); + + template + struct invariant_checker : invariant_checker_base + { + T& object_; + + invariant_checker(T& o) : object_(o) + { + invariant_add(this); + } + + ~invariant_checker() + { + check(); + invariant_remove(this); + } + + void check() const + { + DEACTIVATE_EXCEPTIONS; + invariant_impl(object_); + } + }; + + // On compilers without RVO check() will be called multiple times. + // No big deal I suppose. + template + invariant_checker make_invariant_checker(T& o) + { + return invariant_checker(o); + } + + // Calling this also prevents an unused variable warning when using + // an invariant checker. + void initial_check(::test::invariant_checker_base const&); + + // A one time invariant check. + template + void invariant_check(T const& x) + { + DEACTIVATE_EXCEPTIONS; + invariant_impl(x); + } +} + +#define INVARIANT_CHECK(o) \ + INVARIANT_CHECK2(o, BOOST_PP_CAT(invariant_checker_, __LINE__)) + +#define INVARIANT_CHECK2(o, name) \ + ::test::invariant_checker_base const& name = \ + ::test::make_invariant_checker(o); \ + ::test::initial_check(name) + +#endif diff --git a/test/helpers/less.hpp b/test/helpers/less.hpp new file mode 100644 index 00000000..9151685f --- /dev/null +++ b/test/helpers/less.hpp @@ -0,0 +1,37 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_LESS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_LESS_HEADER + +#include + +namespace test +{ + template + bool compare_impl(T const& x, T const& y, float) + { + return x < y; + } + + template + bool compare_impl(std::pair const& x, + std::pair const& y, int) + { + return x.first < y.first || + (x.first == y.first && x.second < y.second); + } + + struct compare { + template + bool operator()(T const& x, T const& y) + { + return compare_impl(x, y, 0); + } + }; +} + +#endif + diff --git a/test/helpers/member.cpp b/test/helpers/member.cpp new file mode 100644 index 00000000..7edfc27e --- /dev/null +++ b/test/helpers/member.cpp @@ -0,0 +1,79 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./config.hpp" +#include "./member.hpp" +#include "./exception_trigger.hpp" +#include "./generators.hpp" + +#if !defined(BOOST_OLD_IOSTREAMS) +# include +#else +# include +#endif + +namespace test +{ + member::member(int x) + : value(x) + { + exception_trigger(); + } + + member::member(member const& x) + : value(x.value) + { + exception_trigger(); + } + + member& member::operator=(member const& x) + { + exception_trigger(); + value = x.value; + exception_trigger(); + + return *this; + } + + member::~member() + { + value = -1; + } + + bool member::operator==(member const& x) const + { + exception_trigger(); + return value == x.value; + } + + bool member::operator<(member const& x) const + { + exception_trigger(); + return value < x.value; + } + + std::ostream& operator<<(std::ostream& out, member const& x) + { + out<<"Test class("<()()); + } +} + +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace test +#else +namespace boost +#endif +{ + std::size_t hash_value(test::member const& x) + { + return x.value; + } +} diff --git a/test/helpers/member.hpp b/test/helpers/member.hpp new file mode 100644 index 00000000..2ea51c11 --- /dev/null +++ b/test/helpers/member.hpp @@ -0,0 +1,40 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_MEMBER_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_MEMBER_HEADER + +#include +#include + +namespace test +{ + struct member + { + int value; + + explicit member(int x = 0); + member(member const&); + member& operator=(member const&); + ~member(); + + bool operator==(member const&) const; + bool operator<(member const&) const; + }; + + std::ostream& operator<<(std::ostream&, member const&); + test::member generate(test::member const*); +} + +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace test +#else +namespace boost +#endif +{ + std::size_t hash_value(test::member const& x); +} + +#endif diff --git a/test/helpers/metafunctions.hpp b/test/helpers/metafunctions.hpp new file mode 100644 index 00000000..26702abb --- /dev/null +++ b/test/helpers/metafunctions.hpp @@ -0,0 +1,100 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_METAFUNCTIONS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_METAFUNCTIONS_HEADER + +#include +#include +#include +#include +#include + +namespace test +{ + struct unordered_set_type { char x[100]; }; + struct unordered_multiset_type { char x[200]; }; + struct unordered_map_type { char x[300]; }; + struct unordered_multimap_type { char x[400]; }; + + template + unordered_set_type container_type( + boost::unordered_set const*); + template + unordered_multiset_type container_type( + boost::unordered_multiset const*); + template + unordered_map_type container_type( + boost::unordered_map const*); + template + unordered_multimap_type container_type( + boost::unordered_multimap const*); + + template + struct is_set + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(container_type((Container const*)0)) + == sizeof(unordered_set_type) || + sizeof(container_type((Container const*)0)) + == sizeof(unordered_multiset_type) + ); + }; + + template + struct is_map + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(container_type((Container const*)0)) + == sizeof(unordered_map_type) || + sizeof(container_type((Container const*)0)) + == sizeof(unordered_multimap_type) + ); + }; + + template + struct has_unique_keys + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(container_type((Container const*)0)) + == sizeof(unordered_set_type) || + sizeof(container_type((Container const*)0)) + == sizeof(unordered_map_type) + ); + }; + + template + struct has_equivalent_keys + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(container_type((Container const*)0)) + == sizeof(unordered_multiset_type) || + sizeof(container_type((Container const*)0)) + == sizeof(unordered_multimap_type) + ); + }; + + // Non Const Value Type + + template + struct map_non_const_value_type + { + typedef std::pair< + typename Container::key_type, + typename Container::mapped_type> type; + }; + + + template + struct non_const_value_type + : boost::mpl::eval_if, + map_non_const_value_type, + boost::mpl::identity > + { + }; +} + +#endif + diff --git a/test/helpers/random_values.hpp b/test/helpers/random_values.hpp new file mode 100644 index 00000000..4ba605c3 --- /dev/null +++ b/test/helpers/random_values.hpp @@ -0,0 +1,203 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER + +#include "./generators.hpp" +#include "./metafunctions.hpp" +#include +#include +#include + +namespace test +{ + template + struct accessors + { + // get_key + // + // Given either the value_type or the key_type returns the key. + static typename Container::key_type const& + get_key(typename Container::key_type const& x) + { + return x; + } + + template + static typename Container::key_type const& + get_key(std::pair const& x) + { + return x.first; + } + + static typename Container::value_type const& + get_mapped(typename Container::key_type const& x) + { + return x; + } + + template + static M const& + get_mapped(std::pair const& x) + { + return x.second; + } + }; + + template + struct random_values : public accessors + { + typedef accessors base; + + typedef typename non_const_value_type::type value_type; + typedef typename Container::key_type key_type; + + std::vector values_; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + + explicit random_values(std::size_t count) + { + values_.reserve(count); + std::generate_n(std::back_inserter(values_), + count, test::generator()); + } + + iterator begin() { return values_.begin(); } + iterator end() { return values_.end(); } + const_iterator begin() const { return values_.begin(); } + const_iterator end() const { return values_.end(); } + + value_type const& operator[](std::size_t i) const { return values_[i]; } + + struct key_matcher0 + { + template + bool operator()(X const& x, Y const& y) const + { + return base::get_key(x) == base::get_key(y); + } + }; + + // No, I don't know why didn't I just use bind. + struct key_matcher1 + { + key_type x; + + key_matcher1(key_type const& x) : x(x) {} + + bool operator()(key_type const& y) + { + return x == y; + } + + template + bool operator()(std::pair const& y) + { + return x == y.first; + } + }; + + static key_matcher0 key_match() + { + return key_matcher0(); + } + + static key_matcher1 key_match(key_type const& x) + { + return key_matcher1(x); + } + + template + static key_matcher1 key_match(std::pair const& x) + { + return key_matcher1(x.first); + } + + template + iterator find(K const& x) + { + return std::find_if(values_.begin(), values_.end(), key_match(x)); + } + + template + std::size_t count(K const& x) + { + return std::count_if(values_.begin(), values_.end(), + key_match(x)); + } + + template + std::size_t key_count(K const& x) + { + if(has_unique_keys::value) + return find(x) != values_.end(); + else + return count(x); + } + + static bool is_unique() + { + return has_unique_keys::value; + } + }; + + template + struct sorted_random_values : public random_values + { + typedef random_values base; + typedef typename base::value_type value_type; + typedef typename base::key_type key_type; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + + explicit sorted_random_values(std::size_t count) + : base(count) + { + std::stable_sort(this->begin(), this->end()); + } + + struct key_compare0 + { + template + bool operator()(X const& x, Y const& y) const + { + return base::get_key(x) < base::get_key(y); + } + }; + + static key_compare0 key_compare() + { + return key_compare0(); + } + + template + iterator find(K const& x) + { + iterator pos = std::lower_bound(this->begin(), this->end(), x, key_compare()); + return this->key_match()(x, *pos) ? pos : this->end(); + } + + template + std::size_t count(K const& x) + { + std::pair range = + std::equal_range(this->begin(), this->end(), x, key_compare()); + return range.second - range.first; + } + + template + std::size_t key_count(K const& x) + { + if(has_unique_keys::value) + return find(x) != this->end(); + else + return count(x); + } + }; +} + +#endif diff --git a/test/helpers/strong.cpp b/test/helpers/strong.cpp new file mode 100644 index 00000000..0290f42f --- /dev/null +++ b/test/helpers/strong.cpp @@ -0,0 +1,32 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./strong.hpp" +#include + +namespace test +{ + strong_tester::strong_tester() : dismissed_(false) {} + strong_tester::~strong_tester() { BOOST_CHECK(dismissed_); } + void strong_tester::dismiss() const { dismissed_ = true; } + bool strong_tester::is_dismissed() const { return dismissed_; } + void strong_tester::call_test() { + if(!is_dismissed()) + { + DEACTIVATE_EXCEPTIONS; + try { + test(); + } catch(...) { + BOOST_ERROR("Exception thrown in strong test."); + } + dismissed_ = true; + } + } + + strong_test_holder::strong_test_holder(strong_tester_ptr const& x) : ptr_(x) {} + strong_test_holder::~strong_test_holder() { ptr_->call_test(); } + bool strong_test_holder::is_dismissed() const { return ptr_->is_dismissed(); } + void strong_test_holder::dismiss() { ptr_->dismiss(); } +} diff --git a/test/helpers/strong.hpp b/test/helpers/strong.hpp new file mode 100644 index 00000000..c90c80e8 --- /dev/null +++ b/test/helpers/strong.hpp @@ -0,0 +1,78 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER + +#include +#include "./exception_trigger.hpp" + +namespace test +{ + class strong_tester + { + mutable bool dismissed_; + protected: + strong_tester(); + public: + virtual ~strong_tester(); + void dismiss() const; + bool is_dismissed() const; + void call_test(); + virtual void test() = 0; + }; + + template + class default_strong_tester + : public strong_tester + { + T const& reference; + T copy; + public: + default_strong_tester(T const& x) : reference(x), copy(x) {} + + void test() + { + BOOST_CHECK(reference == copy); + } + }; + + typedef boost::shared_ptr strong_tester_ptr; + + //template + //strong_tester_ptr create_tester_impl(T const& x, float) + //{ + // return strong_tester_ptr(new default_strong_tester(x)); + //} + + template + strong_tester_ptr create_tester(T const& x) + { + DEACTIVATE_EXCEPTIONS; + return create_tester_impl(x, 0); + } + + class strong_test_holder + { + strong_tester_ptr ptr_; + public: + strong_test_holder(strong_tester_ptr const&); + ~strong_test_holder(); + bool is_dismissed() const; + void dismiss(); + private: + strong_test_holder(strong_test_holder const&); + strong_test_holder& operator=(strong_test_holder const&); + }; +} + +#define STRONG_TEST_ANON(x) \ + STRONG_TEST(BOOST_PP_CAT(STRONG_TEST_tester, __LINE__), x) + +#define STRONG_TEST(tester, x) \ + for(::test::strong_test_holder tester(::test::create_tester(x)); \ + !tester.is_dismissed(); tester.dismiss()) + +#endif diff --git a/test/helpers/unit_test.hpp b/test/helpers/unit_test.hpp new file mode 100644 index 00000000..3fe6efee --- /dev/null +++ b/test/helpers/unit_test.hpp @@ -0,0 +1,77 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_AUTO_UNIT_TEST_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_AUTO_UNIT_TEST_HEADER + +#include "./base.hpp" +#include +#include +#include +#include +#include + + +#define AUTO_UNIT_TEST(name) \ + AUTO_UNIT_TEST2(name, BOOST_PP_CAT(name##_, impl)) + +#define AUTO_UNIT_TEST2(name, impl_name) \ + void impl_name(); \ + BOOST_AUTO_UNIT_TEST(name) \ + { \ + impl_name(); \ + ::test::end(); \ + } \ + void impl_name() + +#define AUTO_TEMPLATE_TEST(name, T, type_seq) \ + AUTO_TEMPLATE_TEST2(name, BOOST_PP_CAT(name##_, impl), T, type_seq) + +#define AUTO_TEMPLATE_TEST2(name, impl_name, T, type_seq) \ + template \ + void impl_name(); \ + BOOST_PP_SEQ_FOR_EACH(AUTO_TEMPLATE_TEST_OP, name, type_seq) \ + template \ + void impl_name() + +#define AUTO_TEMPLATE_TEST_OP(r, name, type) \ + static boost::unit_test::ut_detail::auto_unit_test_registrar \ + BOOST_PP_CAT(test_registrar_##name##_, type) \ + ( BOOST_TEST_CASE( BOOST_PP_CAT(name##_, impl) ) ); + +#define META_FUNC_TEST_CASE(name, T) \ + META_FUNC_TEST_CASE2(name, T, BOOST_PP_CAT(name##_, impl)) + +#define META_FUNC_TEST_CASE2(name, T, impl_name) \ + template \ + void impl_name(T* = 0); \ + template \ + void name(T* x = 0) { \ + impl_name(x); \ + ::test::end(); \ + } \ + template \ + void impl_name(T*) + +#define RUN_TEST_OP(r, product) \ + RUN_TEST_OP2( \ + BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \ + BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \ + ), \ + BOOST_PP_SEQ_ELEM(0, product), \ + BOOST_PP_SEQ_ELEM(1, product) \ + ) + +#define RUN_TEST_OP2(name, test_func, type) \ + BOOST_AUTO_UNIT_TEST(name) \ + { \ + test_func((type*) 0); \ + ::test::end(); \ + } + +#define AUTO_META_TESTS(test_seq, param_seq) \ + BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_TEST_OP, (test_seq)(param_seq)) + +#endif diff --git a/test/insert_tests.cpp b/test/insert_tests.cpp new file mode 100644 index 00000000..8166349e --- /dev/null +++ b/test/insert_tests.cpp @@ -0,0 +1,193 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/input_iterator_adaptor.hpp" +#include "./strong.hpp" +#include "./invariant.hpp" + +META_FUNC_TEST_CASE(insert_individual,Container) +{ + test::random_values values(100); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + + INVARIANT_CHECK(x); + + ACTIVATE_EXCEPTIONS; + + for(typename test::random_values::iterator + it = values.begin(); it != values.end(); ++it) + { + STRONG_TEST(tester, x) { + try { + x.insert(*it); + } catch(test::hash_exception) { + tester.dismiss(); + throw; + } + } + + DEACTIVATE_EXCEPTIONS; + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end() && + x.key_eq()(values.get_key(*pos), values.get_key(*it))); + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(insert_with_previous_item_hint,Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + + Container x; + INVARIANT_CHECK(x); + + ACTIVATE_EXCEPTIONS; + + typename Container::const_iterator prev = x.begin(); + + for(typename test::random_values::iterator + it = values.begin(); it != values.end(); ++it) + { + x.insert(prev, *it); + + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end() && + x.key_eq()(values.get_key(*pos), values.get_key(*it))); + prev = pos; + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(insert_with_begin_hint,Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + INVARIANT_CHECK(x); + ACTIVATE_EXCEPTIONS; + + for(typename test::random_values::iterator + it = values.begin(); it != values.end(); ++it) + { + x.insert(x.begin(), *it); + + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end() && + x.key_eq()(values.get_key(*pos), values.get_key(*it))); + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(insert_with_end_hint,Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + INVARIANT_CHECK(x); + ACTIVATE_EXCEPTIONS; + + for(typename test::random_values::iterator + it = values.begin(); it != values.end(); ++it) + { + x.insert(x.end(), *it); + + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end() && + x.key_eq()(values.get_key(*pos), values.get_key(*it))); + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(insert_with_random_hint,Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + INVARIANT_CHECK(x); + ACTIVATE_EXCEPTIONS; + + for(typename test::random_values::iterator + it = values.begin(); it != values.end(); ++it) + { + using namespace std; + x.insert(boost::next(x.begin(), rand() % (x.size() + 1)), *it); + + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end() && + x.key_eq()(values.get_key(*pos), values.get_key(*it))); + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(insert_range,Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + INVARIANT_CHECK(x); + ACTIVATE_EXCEPTIONS; + + x.insert(values.begin(), values.end()); + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(insert_range_input_iterator,Container) +{ + test::random_values values(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + INVARIANT_CHECK(x); + ACTIVATE_EXCEPTIONS; + + x.insert(test::make_input_iterator(values.begin()), + test::make_input_iterator(values.end())); + } + EXCEPTION_TEST_END +} + +AUTO_META_TESTS( + (insert_individual)(insert_with_previous_item_hint)(insert_with_begin_hint) + (insert_with_end_hint)(insert_with_random_hint)(insert_range) + (insert_range_input_iterator), + CONTAINER_SEQ +) diff --git a/test/invariant.hpp b/test/invariant.hpp new file mode 100644 index 00000000..a91714cb --- /dev/null +++ b/test/invariant.hpp @@ -0,0 +1,128 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TEST_CONTAINER_INVARIANT_HEADER) +#define BOOST_UNORDERED_TEST_CONTAINER_INVARIANT_HEADER + +#include +#include +#include +#include "./helpers/invariant_checker.hpp" +#include "./helpers/functional.hpp" + +namespace test +{ + template + bool check_matches(Key const&, Pred const&) + { + return true; + } + + bool check_matches(hash const& h, equals const& p) + { + // TODO: This isn't actually true - change functional so that it is. + BOOST_CHECK_EQUAL(h.offset, p.tag); + return true; + } + + template + void invariant_check_container(Container const& x) + { + // Check that the begin and end iterators match the container size. + // (And also that you can iterate through all the elements). + BOOST_CHECK_EQUAL((std::size_t) std::distance(x.begin(), x.end()), + x.size()); + + BOOST_CHECK(check_matches(x.hash_function(), x.key_eq())); + + // It is possible for this to legally fail, eg. if you + // set max_load_factor to lower than the current load factor and + // don't give the table a chance to rehash. + BOOST_WARN(x.load_factor() <= x.max_load_factor()); + } + + template + void invariant_check_set(Container const& x) + { + invariant_check_container(x); + + // Check that the elements are in the correct buckets. + std::size_t count = 0; + std::size_t bucket_count = x.bucket_count(); + for(std::size_t i = 0; i < bucket_count; ++i) { + std::size_t bucket_size = 0; + for(typename Container::const_local_iterator j = x.begin(i); + j != x.end(i); ++j) + { + ++bucket_size; + BOOST_CHECK_EQUAL(i, x.bucket(*j)); + BOOST_CHECK_EQUAL(i, + x.hash_function()(*j) % bucket_count); + } + BOOST_CHECK_EQUAL(bucket_size, x.bucket_size(i)); + + count += bucket_size; + } + + // Check that the size matches what we've just seen. + BOOST_CHECK_EQUAL(count, x.size()); + } + + template + void invariant_check_map(Container const& x) + { + invariant_check_container(x); + + // Check that the elements are in the correct buckets. + std::size_t count = 0; + std::size_t bucket_count = x.bucket_count(); + for(std::size_t i = 0; i < bucket_count; ++i) { + std::size_t bucket_size = 0; + for(typename Container::const_local_iterator j = x.begin(i); + j != x.end(i); ++j) + { + ++bucket_size; + BOOST_CHECK_EQUAL(i, x.bucket(j->first)); + BOOST_CHECK_EQUAL(i, + x.hash_function()(j->first) % bucket_count); + } + BOOST_CHECK_EQUAL(bucket_size, x.bucket_size(i)); + + count += bucket_size; + } + + // Check that the size matches what we've just seen. + BOOST_CHECK_EQUAL(count, x.size()); + } +} + +namespace boost +{ + template + void invariant_impl(boost::unordered_set const& x) + { + test::invariant_check_set(x); + } + + template + void invariant_impl(boost::unordered_multiset const& x) + { + test::invariant_check_set(x); + } + + template + void invariant_impl(boost::unordered_map const& x) + { + test::invariant_check_map(x); + } + + template + void invariant_impl(boost::unordered_multimap const& x) + { + test::invariant_check_map(x); + } +} + +#endif diff --git a/test/iterator_tests.cpp b/test/iterator_tests.cpp new file mode 100644 index 00000000..19a12277 --- /dev/null +++ b/test/iterator_tests.cpp @@ -0,0 +1,141 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include +#include + +#define BOOST_AUTO_TEST_MAIN +#include + +// TODO: Add these headers to new_iterator_tests.hpp +#include +#include +#include + +#include +#include +#include +#include "./helpers/unit_test.hpp" + +BOOST_AUTO_UNIT_TEST(iterator_tests) +{ + boost::unordered_set > set; + boost::unordered_multiset multiset; + boost::unordered_map map; + boost::unordered_multimap > multimap; + + set.insert(std::pair("Anthony","Cleopatra")); + set.insert(std::pair("Victoria","Albert")); + set.insert(std::pair("Pete","Dud")); + set.insert(std::pair("Blair","Brown")); + set.insert(std::pair("John","Yoko")); + set.insert(std::pair("Charles","Diana")); + set.insert(std::pair("Marx","Engels")); + set.insert(std::pair("Sid","Nancy")); + set.insert(std::pair("Lucy","Ricky")); + set.insert(std::pair("George","Mildred")); + set.insert(std::pair("Fanny","Alexander")); + set.insert(std::pair("Den","Angie")); + set.insert(std::pair("Sonny","Cher")); + set.insert(std::pair("Bonnie","Clyde")); + set.insert(std::pair("Punch","Judy")); + set.insert(std::pair("Powell","Pressburger")); + set.insert(std::pair("Jekyll","Hyde")); + + multiset.insert(0.434321); + multiset.insert(443421); + multiset.insert(0.434321); + + map[98] = 3; + map[99] = 4; + map[2000] = 788421; + map[2001] = 2; + + static char* strings1 = "Banjo\0Banjo\0Ukulele"; + + static char* strings[] = { + strings1, + strings1 + 6, + strings1 + 12 + }; + + BOOST_CHECK(std::string(strings[0]) == std::string(strings[1])); + BOOST_CHECK(strings[0] != strings[1]); + + multimap.insert(std::make_pair(strings[0], std::make_pair(5,6))); + multimap.insert(std::make_pair(strings[1], std::make_pair(85,32))); + multimap.insert(std::make_pair(strings[1], std::make_pair(91,142))); + multimap.insert(std::make_pair(strings[2], std::make_pair(12,3))); + multimap.insert(std::make_pair(strings[2], std::make_pair(10,94))); + multimap.insert(std::make_pair(strings[2], std::make_pair(345,42))); + + BOOST_CHECK_EQUAL(multimap.count(strings[0]), 1); + BOOST_CHECK_EQUAL(multimap.count(strings[1]), 2); + BOOST_CHECK_EQUAL(multimap.count(strings[2]), 3); + + boost::forward_readable_iterator_test(set.begin(), set.end(), + *set.begin(), *boost::next(set.begin())); + boost::forward_readable_iterator_test(multiset.begin(), multiset.end(), + *multiset.begin(), *boost::next(multiset.begin())); + boost::forward_readable_iterator_test(map.begin(), map.end(), + *map.begin(), *boost::next(map.begin())); + boost::forward_readable_iterator_test(multimap.begin(), multimap.end(), + *multimap.begin(), *boost::next(multimap.begin())); +} + +BOOST_AUTO_UNIT_TEST(rubbish_iterator_test) +{ + typedef boost::unordered_map map; + typedef map::local_iterator local_iterator; + typedef map::const_local_iterator const_local_iterator; + typedef map::iterator iterator; + typedef map::const_iterator const_iterator; + + map m; + iterator it; + const_iterator const_it(it); + local_iterator local; + const_local_iterator const_local(local); + + m[10] = 3; + m[25] = 5; + m[2] = 21; + + it = m.begin(); + const_it = m.begin(); + map::size_type index = m.bucket(10); + local = m.begin(index); + const_local = m.begin(index); + + BOOST_CHECK(it == const_it); + BOOST_CHECK(const_it == it); + BOOST_CHECK(local == const_local); + BOOST_CHECK(const_local == local); + + BOOST_CHECK(it++ == const_it); + BOOST_CHECK(local++ == const_local); + + BOOST_CHECK(it != const_it); + BOOST_CHECK(const_it != it); + BOOST_CHECK(local != const_local); + BOOST_CHECK(const_local != local); + + BOOST_CHECK(++const_it == it); + BOOST_CHECK(++const_local == local); + + it = m.begin(); + int values[3]; + std::pair const& r1= *it++; + values[0] = r1.second; + values[1] = it++->second; + values[2] = it++->second; + BOOST_CHECK(it == m.end()); + + std::sort(values, values+3); + + BOOST_CHECK_EQUAL(values[0], 3); + BOOST_CHECK_EQUAL(values[1], 5); + BOOST_CHECK_EQUAL(values[2], 21); +} diff --git a/test/map_operator_tests.cpp b/test/map_operator_tests.cpp new file mode 100644 index 00000000..238d2860 --- /dev/null +++ b/test/map_operator_tests.cpp @@ -0,0 +1,69 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/input_iterator_adaptor.hpp" +#include "./strong.hpp" +#include "./invariant.hpp" + +// TODO: This is just the first insert test slightly modified, should do better. + +META_FUNC_TEST_CASE(insert_individual,Container) +{ + test::random_values values(100); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + Container x; + + INVARIANT_CHECK(x); + + ACTIVATE_EXCEPTIONS; + + for(typename test::random_values::iterator + it = values.begin(); it != values.end(); ++it) + { + typename Container::value_type::second_type* ref; + + // Looking at TR1 I can't find this requirement anywhere, but it + // would seem silly not to require it so I think it's either an + // omission or I haven't looked hard enough. + STRONG_TEST(tester, x) { + try { + ref = &x[it->first]; + } catch(test::hash_exception) { + tester.dismiss(); + throw; + } + } + + DEACTIVATE_EXCEPTIONS; + *ref = it->second; + + typename Container::iterator pos = x.find(values.get_key(*it)); + BOOST_CHECK(pos != x.end() && + x.key_eq()(values.get_key(*pos), values.get_key(*it)) && + test::equivalent(*it, *pos)); + } + } + EXCEPTION_TEST_END +} + +typedef boost::unordered_map map1; +typedef boost::unordered_map > map2; + +AUTO_META_TESTS( + (insert_individual), + (map1)(map2) +) diff --git a/test/max_load_factor_test.cpp b/test/max_load_factor_test.cpp new file mode 100644 index 00000000..c4a0570b --- /dev/null +++ b/test/max_load_factor_test.cpp @@ -0,0 +1,170 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include +#include + +#define BOOST_AUTO_TEST_MAIN +#include +#include + +#include + +// If the bucket count is higher than the upper bounds in this file, it's not a +// bug (but it's not that great either). There are also some tests on when the +// number of buckets is increased on an insert, these tests are checking that +// some implementation details are working - if the implementation is changed +// they can be removed. +// +// TODO: the argument to max_load_factor is just a hint, so test against the +// container's actual max_load_factor. + +BOOST_AUTO_UNIT_TEST(test_rehash) +{ + boost::counting_iterator begin(0); + boost::counting_iterator end(1000); + + boost::unordered_set x1(begin, end); + BOOST_CHECK(x1.bucket_count() >= 1000); + BOOST_WARN(x1.bucket_count() < 2000); + + x1.max_load_factor(0.5); + x1.rehash(0); + BOOST_CHECK(x1.bucket_count() >= 2000); + BOOST_WARN(x1.bucket_count() < 4000); + x1.rehash(0); + BOOST_CHECK(x1.bucket_count() >= 2000); + BOOST_WARN(x1.bucket_count() < 4000); + + x1.max_load_factor(2.0); + x1.rehash(0); + BOOST_CHECK(x1.bucket_count() >= 500); + BOOST_WARN(x1.bucket_count() < 1000); + x1.rehash(1500); + BOOST_CHECK(x1.bucket_count() >= 1500); + BOOST_WARN(x1.bucket_count() < 3000); + + x1.max_load_factor(0.5); + x1.rehash(0); + BOOST_CHECK(x1.bucket_count() >= 2000); + BOOST_WARN(x1.bucket_count() < 4000); +} + +BOOST_AUTO_UNIT_TEST(test_insert_range) +{ + boost::counting_iterator begin(0); + boost::counting_iterator end(1000); + + boost::unordered_set x1(begin, end); + BOOST_CHECK(x1.bucket_count() >= 1000); + BOOST_WARN(x1.bucket_count() < 2000); + + x1.clear(); + x1.max_load_factor(0.5); + x1.rehash(0); + x1.insert(begin, end); + BOOST_CHECK(x1.bucket_count() >= 2000); + BOOST_WARN(x1.bucket_count() < 4000); + + x1.clear(); + x1.max_load_factor(2.0); + x1.rehash(0); + x1.insert(begin, end); + BOOST_CHECK(x1.bucket_count() >= 500); + BOOST_WARN(x1.bucket_count() < 1000); +} + +BOOST_AUTO_UNIT_TEST(test_insert) +{ + boost::unordered_map x1; + + size_t i; + for(i = 0; i < 1000; ++i) + { + size_t old_bucket_count = x1.bucket_count(); + x1[i] = i; + BOOST_CHECK(i <= x1.bucket_count()); + BOOST_CHECK(x1.bucket_count() == old_bucket_count || + x1.size() >= old_bucket_count); + + // This isn't really required: + BOOST_WARN(x1.size() < x1.bucket_count()); + } + + x1.clear(); + x1.max_load_factor(2.0); + x1.rehash(0); + + for(i = 0; i < 1000; ++i) + { + size_t old_bucket_count = x1.bucket_count(); + x1[i] = i; + BOOST_CHECK(i <= x1.bucket_count() * 2); + BOOST_CHECK(x1.bucket_count() == old_bucket_count || + x1.size() >= old_bucket_count * 2); + + // This isn't really required: + BOOST_WARN(x1.size() < x1.bucket_count() * 2); + } + + x1.clear(); + x1.rehash(0); + x1.max_load_factor(0.5); + + for(i = 0; i < 1000; ++i) + { + size_t old_bucket_count = x1.bucket_count(); + x1[i] = i; + BOOST_CHECK(i * 2 <= x1.bucket_count()); + BOOST_CHECK(x1.bucket_count() == old_bucket_count || + x1.size() * 2 >= old_bucket_count); + + // This isn't really required: + BOOST_WARN(x1.size() * 2 < x1.bucket_count()); + } +} + +BOOST_AUTO_UNIT_TEST(test_large_mlf) +{ + boost::unordered_set x1; + x1.max_load_factor(static_cast( + (std::numeric_limits::size_type>::max)() + ) * 10); + + boost::unordered_map::size_type bucket_count = x1.bucket_count(); + + for(int i = 0; i < 1000; ++i) + { + x1.insert(i); + BOOST_CHECK(x1.bucket_count() == bucket_count); + } + + boost::counting_iterator begin(1000); + boost::counting_iterator end(2000); + x1.insert(begin, end); + BOOST_CHECK(x1.bucket_count() == bucket_count); +} + +BOOST_AUTO_UNIT_TEST(test_infinite_mlf) +{ + if(std::numeric_limits::has_infinity) + { + boost::unordered_set x1; + x1.max_load_factor(std::numeric_limits::infinity()); + + boost::unordered_map::size_type bucket_count = x1.bucket_count(); + + for(int i = 0; i < 1000; ++i) + { + x1.insert(i); + BOOST_CHECK(x1.bucket_count() == bucket_count); + } + + boost::counting_iterator begin(1000); + boost::counting_iterator end(2000); + x1.insert(begin, end); + BOOST_CHECK(x1.bucket_count() == bucket_count); + } +} diff --git a/test/next_prime_tests.cpp b/test/next_prime_tests.cpp new file mode 100644 index 00000000..b3a81f81 --- /dev/null +++ b/test/next_prime_tests.cpp @@ -0,0 +1,18 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include + +#define BOOST_AUTO_TEST_MAIN +#include + +BOOST_AUTO_UNIT_TEST(next_prime_test) +{ + BOOST_CHECK_EQUAL(53ul, boost::unordered_detail::next_prime(0)); + BOOST_CHECK_EQUAL(53ul, boost::unordered_detail::next_prime(52)); + BOOST_CHECK_EQUAL(53ul, boost::unordered_detail::next_prime(53)); + BOOST_CHECK_EQUAL(97ul, boost::unordered_detail::next_prime(54)); + BOOST_CHECK_EQUAL(98317ul, boost::unordered_detail::next_prime(50000ul)); +} diff --git a/test/set_assign_fail_test.cpp b/test/set_assign_fail_test.cpp new file mode 100644 index 00000000..ccf4e93d --- /dev/null +++ b/test/set_assign_fail_test.cpp @@ -0,0 +1,14 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include + +void func() +{ + boost::unordered_set x; + x.insert(10); + boost::unordered_set::iterator it = x.begin(); + *x = 25; +} diff --git a/test/strong.hpp b/test/strong.hpp new file mode 100644 index 00000000..86218568 --- /dev/null +++ b/test/strong.hpp @@ -0,0 +1,102 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#if !defined(BOOST_UNORDERED_TESTS_STRONG_HEADER) +#define BOOST_UNORDERED_TESTS_STRONG_HEADER + +#include "./helpers/strong.hpp" +#include "./helpers/equivalent.hpp" +#include "./helpers/metafunctions.hpp" +#include +#include +#include +#include + +namespace test +{ + struct equals_t + { + template + bool operator()(X const& x, Y const& y) + { + return x == y; + } + + template + bool operator()(std::pair const& x, std::pair const& y) + { + return x.first == y.first && x.second == y.second; + } + } equals1; + + template + class unordered_strong_tester + : public strong_tester + { + Container const& reference_; + + typename Container::size_type size_; + typename Container::hasher hasher_; + typename Container::key_equal key_equal_; + + std::deque::type> values_; + public: + unordered_strong_tester(Container const &x) + : reference_(x), size_(x.size()), + hasher_(x.hash_function()), key_equal_(x.key_eq()), + values_(x.begin(), x.end()) + { + } + + void test() + { + BOOST_CHECK(size_ == reference_.size()); + BOOST_CHECK(test::equivalent(hasher_, reference_.hash_function())); + BOOST_CHECK(test::equivalent(key_equal_, reference_.key_eq())); + BOOST_CHECK(values_.size() == reference_.size()); + BOOST_CHECK(values_.size() == reference_.size() && + std::equal(values_.begin(), values_.end(), reference_.begin(), equals1)); + } + private: + unordered_strong_tester(); + }; +} + +namespace boost +{ + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_set const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_set >(x)); + } + + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_multiset const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_multiset >(x)); + } + + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_map const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_map >(x)); + } + + template + test::strong_tester_ptr create_tester_impl( + boost::unordered_multimap const& x, int) + { + return test::strong_tester_ptr(new test::unordered_strong_tester< + boost::unordered_multimap >(x)); + } +} + +#endif diff --git a/test/swap_tests.hpp b/test/swap_tests.hpp new file mode 100644 index 00000000..1c4bbbf3 --- /dev/null +++ b/test/swap_tests.hpp @@ -0,0 +1,120 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/constructors.hpp" +#include "./helpers/equivalent.hpp" +#include "./invariant.hpp" + +META_FUNC_TEST_CASE(swap_test1, Container) +{ + test::constructors constructor; + + test::random_values values_x(10); + test::random_values values_y(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + + Container x(values_x.begin(), values_x.end(), 0, + constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + x.max_load_factor(0.5); + Container y(values_y.begin(), values_y.end(), 0, + constructor.hasher(23), constructor.key_equal(23), constructor.allocator(12)); + y.max_load_factor(2.0); + + INVARIANT_CHECK(x); + INVARIANT_CHECK(y); + + ACTIVATE_EXCEPTIONS; + + if(BOOST_UNORDERED_SWAP_METHOD == 1 + && !test::equivalent(x.get_allocator(), y.get_allocator())) { + BOOST_CHECK_THROW(x.swap(y), std::runtime_error); + } + else { +#if BOOST_UNORDERED_SWAP_METHOD == 2 + // Swap Method 2 can't meet TR1's exception specifications. Sigh. + x.swap(y); +#else + try { + x.swap(y); + } + catch (test::hash_copy_exception&) { + throw; + } + catch (test::pred_copy_exception&) { + throw; + } + catch (...) { + BOOST_ERROR("Only the copy constructor/assigned of the hash " + "and predicate objects are allowed to throw in swap."); + throw; + } +#endif + + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(23))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(23))); + BOOST_CHECK_EQUAL(x.max_load_factor(), 2.0); +#if BOOST_UNORDERED_SWAP_METHOD == 2 + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(10))); +#else + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(12))); +#endif + + BOOST_CHECK(test::equivalent(y.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(y.key_eq(), constructor.key_equal(55))); + BOOST_CHECK_EQUAL(y.max_load_factor(), 0.5); +#if BOOST_UNORDERED_SWAP_METHOD == 2 + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator(12))); +#else + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator(10))); +#endif + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(self_swap, Container) +{ + test::constructors constructor; + test::random_values values_x(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + + Container x(values_x.begin(), values_x.end(), 0, + constructor.hasher(55), constructor.key_equal(55), + constructor.allocator(10)); + x.max_load_factor(0.5); + + INVARIANT_CHECK(x); + + ACTIVATE_EXCEPTIONS; + + x.swap(x); + + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(55))); + BOOST_CHECK_EQUAL(x.max_load_factor(), 0.5); + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(10))); + } + EXCEPTION_TEST_END +} + +AUTO_META_TESTS( + (swap_test1)(self_swap), + CONTAINER_SEQ +) diff --git a/test/swap_tests.ipp b/test/swap_tests.ipp new file mode 100644 index 00000000..67623d99 --- /dev/null +++ b/test/swap_tests.ipp @@ -0,0 +1,102 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include "./containers.hpp" + +#define BOOST_AUTO_TEST_MAIN +#include + +#include +#include "./helpers/unit_test.hpp" +#include "./helpers/exception_test.hpp" +#include "./helpers/random_values.hpp" +#include "./helpers/constructors.hpp" +#include "./helpers/equivalent.hpp" +#include "./invariant.hpp" + +META_FUNC_TEST_CASE(swap_test1, Container) +{ + test::constructors constructor; + + test::random_values values_x(10); + test::random_values values_y(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + + Container x(values_x.begin(), values_x.end(), 0, + constructor.hasher(55), constructor.key_equal(55), constructor.allocator(10)); + x.max_load_factor(0.5); + Container y(values_y.begin(), values_y.end(), 0, + constructor.hasher(23), constructor.key_equal(23), constructor.allocator(12)); + y.max_load_factor(2.0); + + INVARIANT_CHECK(x); + INVARIANT_CHECK(y); + + ACTIVATE_EXCEPTIONS; + + if(BOOST_UNORDERED_SWAP_METHOD == 1 + && !test::equivalent(x.get_allocator(), y.get_allocator())) { + BOOST_CHECK_THROW(x.swap(y), std::runtime_error); + } + else { + x.swap(y); + + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(23))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(23))); + BOOST_CHECK_EQUAL(x.max_load_factor(), 2.0); +#if BOOST_UNORDERED_SWAP_METHOD == 2 + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(10))); +#else + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(12))); +#endif + + BOOST_CHECK(test::equivalent(y.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(y.key_eq(), constructor.key_equal(55))); + BOOST_CHECK_EQUAL(y.max_load_factor(), 0.5); +#if BOOST_UNORDERED_SWAP_METHOD == 2 + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator(12))); +#else + BOOST_CHECK(test::equivalent(y.get_allocator(), constructor.allocator(10))); +#endif + } + } + EXCEPTION_TEST_END +} + +META_FUNC_TEST_CASE(self_swap, Container) +{ + test::constructors constructor; + test::random_values values_x(10); + + EXCEPTION_TEST(1000) + { + DEACTIVATE_EXCEPTIONS; + + Container x(values_x.begin(), values_x.end(), 0, + constructor.hasher(55), constructor.key_equal(55), + constructor.allocator(10)); + x.max_load_factor(0.5); + + INVARIANT_CHECK(x); + + ACTIVATE_EXCEPTIONS; + + x.swap(x); + + BOOST_CHECK(test::equivalent(x.hash_function(), constructor.hasher(55))); + BOOST_CHECK(test::equivalent(x.key_eq(), constructor.key_equal(55))); + BOOST_CHECK_EQUAL(x.max_load_factor(), 0.5); + BOOST_CHECK(test::equivalent(x.get_allocator(), constructor.allocator(10))); + } + EXCEPTION_TEST_END +} + +AUTO_META_TESTS( + (swap_test1)(self_swap), + CONTAINER_SEQ +) diff --git a/test/swap_tests1.cpp b/test/swap_tests1.cpp new file mode 100644 index 00000000..5a61be4f --- /dev/null +++ b/test/swap_tests1.cpp @@ -0,0 +1,7 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#define BOOST_UNORDERED_SWAP_METHOD 1 +#include "./swap_tests.hpp" diff --git a/test/swap_tests2.cpp b/test/swap_tests2.cpp new file mode 100644 index 00000000..56ccbd27 --- /dev/null +++ b/test/swap_tests2.cpp @@ -0,0 +1,7 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#define BOOST_UNORDERED_SWAP_METHOD 2 +#include "./swap_tests.hpp" diff --git a/test/swap_tests3.cpp b/test/swap_tests3.cpp new file mode 100644 index 00000000..13a5951f --- /dev/null +++ b/test/swap_tests3.cpp @@ -0,0 +1,7 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#define BOOST_UNORDERED_SWAP_METHOD 3 +#include "./swap_tests.hpp" diff --git a/test/type_tests.cpp b/test/type_tests.cpp new file mode 100644 index 00000000..3c494b5c --- /dev/null +++ b/test/type_tests.cpp @@ -0,0 +1,206 @@ + +// Copyright Daniel James 2005. Use, modification, and distribution are +// 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) + +#include +#include +#include +#include +#include +#include "./helpers/functional.hpp" + +template +struct iterator_checks +{ + typedef Iterator iterator; + + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_value::type, + typename Container::value_type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_reference::type, + typename Container::reference>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_pointer::type, + typename Container::pointer>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_difference::type, + typename Container::difference_type>)); +}; + +template +struct const_iterator_checks +{ + typedef ConstIterator const_iterator; + + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_value::type, + typename Container::value_type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_reference::type, + typename Container::const_reference>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_pointer::type, + typename Container::const_pointer>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_difference::type, + typename Container::difference_type>)); +}; + +template +struct unordered_typedef_checks +{ + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef typename Container::local_iterator local_iterator; + typedef typename Container::const_local_iterator const_local_iterator; + + // 6.3.1/9 rows 1-3 + BOOST_MPL_ASSERT((boost::is_same< + Key, + typename Container::key_type>)); + BOOST_MPL_ASSERT((boost::is_same< + Hash, + typename Container::hasher>)); + BOOST_MPL_ASSERT((boost::is_same< + Pred, + typename Container::key_equal>)); + + // 6.3.1/9 rows 4-5 + // TODO: A local_iterator may be used to iterate through a single + // bucket but may not be used to iterate across buckets. + BOOST_MPL_ASSERT((boost::is_same< + typename boost::BOOST_ITERATOR_CATEGORY::type, + typename boost::BOOST_ITERATOR_CATEGORY::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_value::type, + typename boost::iterator_value::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_difference::type, + typename boost::iterator_difference::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_pointer::type, + typename boost::iterator_pointer::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_reference::type, + typename boost::iterator_reference::type>)); + + BOOST_MPL_ASSERT((boost::is_same< + typename boost::BOOST_ITERATOR_CATEGORY::type, + typename boost::BOOST_ITERATOR_CATEGORY::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_value::type, + typename boost::iterator_value::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_difference::type, + typename boost::iterator_difference::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_pointer::type, + typename boost::iterator_pointer::type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename boost::iterator_reference::type, + typename boost::iterator_reference::type>)); + + // TODO: Is this ever specified? + BOOST_MPL_ASSERT((boost::is_same< + AllocatorType, + typename Container::allocator_type>)); + BOOST_MPL_ASSERT((boost::is_same< + typename AllocatorType::pointer, + typename Container::pointer>)); + BOOST_MPL_ASSERT((boost::is_same< + typename AllocatorType::const_pointer, + typename Container::const_pointer>)); + BOOST_MPL_ASSERT((boost::is_same< + typename AllocatorType::reference, + typename Container::reference>)); + BOOST_MPL_ASSERT((boost::is_same< + typename AllocatorType::const_reference, + typename Container::const_reference>)); +}; + +template +struct unordered_map_checks +{ + unordered_typedef_checks c1; + iterator_checks c2; + const_iterator_checks c3; + iterator_checks c4; + const_iterator_checks c5; + + // 6.3.1/7 + BOOST_MPL_ASSERT((boost::is_same< + typename Container::value_type, + std::pair >)); +}; + +template +struct unordered_set_checks +{ + unordered_typedef_checks c1; + const_iterator_checks c2; + const_iterator_checks c3; + const_iterator_checks c4; + const_iterator_checks c5; + + // 6.3.1/7 + BOOST_MPL_ASSERT((boost::is_same< + typename Container::value_type, + typename Container::key_type>)); +}; + +unordered_set_checks< + boost::unordered_multiset, int, + boost::hash, std::equal_to, std::allocator +> int_multiset_check; + +unordered_set_checks< + boost::unordered_multiset, + std::string, test::hash, test::less, std::allocator +> custom_string_multiset_check; + +unordered_set_checks< + boost::unordered_set, int, + boost::hash, std::equal_to, std::allocator +> int_set_check; + +unordered_set_checks< + boost::unordered_set, + std::string, test::hash, test::less, std::allocator +> custom_string_set_check; + +unordered_map_checks< + boost::unordered_map, std::string, int, + boost::hash, std::equal_to, + std::allocator > +> string_int_check; + +unordered_map_checks< + boost::unordered_map, + char const*, std::string, + test::hash, test::less, + std::allocator > +> custom_check; + +unordered_map_checks< + boost::unordered_multimap, + int, int, + boost::hash, std::equal_to, + std::allocator > +> int_int_multi_check; + +unordered_map_checks< + boost::unordered_multimap, + std::string, int, + boost::hash, std::equal_to, + std::allocator > +> string_int_multi_check; + +unordered_map_checks< + boost::unordered_multimap, + float, std::string, + test::hash, test::less, + std::allocator > +> custom_multi_check;