From 1be8ab0d30f14d797e65e89142c96c63f2e85c0b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 May 2006 17:19:16 +0000 Subject: [PATCH] Add some tests for the unordered associative containers. [SVN r2954] --- test/Jamfile.v2 | 7 + test/container/Jamfile.v2 | 1 + test/helpers/equivalent.hpp | 75 ++++++ test/helpers/fwd.hpp | 20 ++ test/helpers/generators.hpp | 88 +++++++ test/helpers/helpers.hpp | 30 +++ test/helpers/invariants.hpp | 82 +++++++ test/helpers/metafunctions.hpp | 103 ++++++++ test/helpers/random_values.hpp | 29 +++ test/helpers/tracker.hpp | 146 +++++++++++ test/objects/fwd.hpp | 18 ++ test/objects/test.hpp | 202 +++++++++++++++ test/unordered/Jamfile.v2 | 23 ++ test/unordered/assign_tests.cpp | 91 +++++++ test/unordered/compile_tests.cpp | 297 +++++++++++++++++++++++ test/unordered/constructor_tests.cpp | 202 +++++++++++++++ test/unordered/copy_tests.cpp | 103 ++++++++ test/unordered/equivalent_keys_tests.cpp | 85 +++++++ test/unordered/erase_tests.cpp | 140 +++++++++++ test/unordered/find_tests.cpp | 90 +++++++ test/unordered/insert_tests.cpp | 188 ++++++++++++++ 21 files changed, 2020 insertions(+) create mode 100644 test/Jamfile.v2 create mode 100644 test/helpers/equivalent.hpp create mode 100644 test/helpers/fwd.hpp create mode 100644 test/helpers/generators.hpp create mode 100644 test/helpers/helpers.hpp create mode 100644 test/helpers/invariants.hpp create mode 100644 test/helpers/metafunctions.hpp create mode 100644 test/helpers/random_values.hpp create mode 100644 test/helpers/tracker.hpp create mode 100644 test/objects/fwd.hpp create mode 100644 test/objects/test.hpp create mode 100644 test/unordered/Jamfile.v2 create mode 100644 test/unordered/assign_tests.cpp create mode 100644 test/unordered/compile_tests.cpp create mode 100644 test/unordered/constructor_tests.cpp create mode 100644 test/unordered/copy_tests.cpp create mode 100644 test/unordered/equivalent_keys_tests.cpp create mode 100644 test/unordered/erase_tests.cpp create mode 100644 test/unordered/find_tests.cpp create mode 100644 test/unordered/insert_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 00000000..122f58d6 --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,7 @@ + +# Copyright Daniel James 2006. 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) + +build-project container ; +build-project unordered ; diff --git a/test/container/Jamfile.v2 b/test/container/Jamfile.v2 index a0dcd090..6ec50a34 100644 --- a/test/container/Jamfile.v2 +++ b/test/container/Jamfile.v2 @@ -14,4 +14,5 @@ test-suite container-tests : [ run set_compile.cpp ] [ run map_compile.cpp ] + [ run simple_tests.cpp ] ; diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp new file mode 100644 index 00000000..8d44fafd --- /dev/null +++ b/test/helpers/equivalent.hpp @@ -0,0 +1,75 @@ + +// Copyright Daniel James 2005-2006. 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 +#include +#include +#include +#include "./metafunctions.hpp" + +namespace test +{ + template + bool equivalent(T const& x, T const& y) { + return x == y; + } + + template + bool equivalent(boost::hash const&, boost::hash const&) { + return true; + } + + template + bool equivalent(std::equal_to const&, std::equal_to const&) { + return true; + } + + template + class unordered_equivalence_tester + { + typename Container::size_type size_; + typename Container::hasher hasher_; + typename Container::key_equal key_equal_; + float max_load_factor_; + + typedef typename non_const_value_type::type value_type; + std::vector 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_() + { + // Can't initialise values_ straight from x because of Visual C++ 6 + values_.reserve(x.size()); + std::copy(x.begin(), x.end(), std::back_inserter(values_)); + + std::sort(values_.begin(), values_.end()); + } + + bool operator()(Container const& x) const + { + if(!((size_ == x.size()) && + (test::equivalent(hasher_, x.hash_function())) && + (test::equivalent(key_equal_, x.key_eq())) && + (max_load_factor_ == x.max_load_factor()) && + (values_.size() == x.size()))) return false; + + std::vector copy; + copy.reserve(x.size()); + std::copy(x.begin(), x.end(), std::back_inserter(copy)); + std::sort(copy.begin(), copy.end()); + return(std::equal(values_.begin(), values_.end(), copy.begin())); + } + private: + unordered_equivalence_tester(); + }; +} + +#endif diff --git a/test/helpers/fwd.hpp b/test/helpers/fwd.hpp new file mode 100644 index 00000000..77032bf9 --- /dev/null +++ b/test/helpers/fwd.hpp @@ -0,0 +1,20 @@ + +// Copyright Daniel James 2006. 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_FWD_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER + +namespace test +{ + int generate(int const*); + char generate(char const*); + std::string generate(std::string*); + float generate(float const*); + template + std::pair generate(std::pair*); +} + +#endif + diff --git a/test/helpers/generators.hpp b/test/helpers/generators.hpp new file mode 100644 index 00000000..3ed8cf1b --- /dev/null +++ b/test/helpers/generators.hpp @@ -0,0 +1,88 @@ + +// Copyright Daniel James 2005-2006. 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) + +// A crude wrapper round Boost.Random to make life easier. + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER + +#include +#include + +#include +#include +#include +#include +#include + +#include "./fwd.hpp" + +namespace test +{ + typedef boost::hellekalek1995 integer_generator_type; + typedef boost::lagged_fibonacci607 real_generator_type; + + template + struct generator + { + typedef T value_type; + value_type operator()() + { + return generate((T const*) 0); + } + }; + + inline int generate(int const*) + { + static boost::variate_generator > + vg((integer_generator_type()), boost::uniform_int<>(0, 1000)); + return vg(); + } + + inline char generate(char const*) + { + static boost::variate_generator > + vg((integer_generator_type()), boost::uniform_int(32, 128)); + return vg(); + } + + inline 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; + } + + float generate(float const*) + { + static boost::variate_generator > + vg((real_generator_type()), boost::uniform_real()); + return vg(); + } + + template std::pair generate( + std::pair const*) + { + static generator g1; + static generator g2; + + return std::pair(g1(), g2()); + } +} + +#endif diff --git a/test/helpers/helpers.hpp b/test/helpers/helpers.hpp new file mode 100644 index 00000000..fa219cda --- /dev/null +++ b/test/helpers/helpers.hpp @@ -0,0 +1,30 @@ + +// Copyright Daniel James 2006. 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_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_HEADER + +namespace test +{ + template + inline typename Container::key_type get_key(typename Container::key_type const& x) + { + return x; + } + + template + inline typename Container::key_type get_key(std::pair const& x) + { + return x.first; + } + + template + inline typename Container::key_type get_key(std::pair const& x) + { + return x.first; + } +} + +#endif diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp new file mode 100644 index 00000000..ac37891b --- /dev/null +++ b/test/helpers/invariants.hpp @@ -0,0 +1,82 @@ + +// Copyright Daniel James 2006. 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) + +// This header contains metafunctions/functions to get the equivalent +// associative container for an unordered container, and compare the contents. + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER + +#include +#include "./metafunctions.hpp" +#include "./helpers.hpp" + +namespace test +{ + template + void check_equivalent_keys(X const& x1) + { + typename X::key_equal eq = x1.key_eq(); + typedef typename X::key_type key_type; + std::set found_; + + typename X::const_iterator it = x1.begin(), end = x1.end(); + typename X::size_type size = 0; + while(it != end) { + // First test that the current key has not occured before, required + // to test either that keys are unique or that equivalent keys are + // adjacent. (6.3.1/6) + key_type key = get_key(*it); + if(found_.find(key) != found_.end()) + BOOST_ERROR("Elements with equivalent keys aren't adjacent."); + found_.insert(key); + + // Iterate over equivalent keys, counting them. + unsigned int count = 0; + do { + ++it; + ++count; + ++size; + } while(it != end && eq(get_key(*it), key)); + + // If the container has unique keys, test that there's only one. + // Since the previous test makes sure that all equivalent keys are + // adjacent, this is all the equivalent keys - so the test is + // sufficient. (6.3.1/6 again). + if(test::has_unique_keys::value && count != 1) + BOOST_ERROR("Non-unique key."); + + if(x1.count(key) != count) + BOOST_ERROR("Incorrect output of count."); + + // Check that the keys are in the correct bucket and are adjacent in + // the bucket. + typename X::size_type bucket = x1.bucket(key); + typename X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket); + for(; lit != lend && !eq(get_key(*lit), key); ++lit) continue; + if(lit == lend) + BOOST_ERROR("Unable to find element with a local_iterator"); + unsigned int count2 = 0; + for(; lit != lend && eq(get_key(*lit), key); ++lit) ++count2; + if(count != count2) + BOOST_ERROR("Element count doesn't match local_iterator."); + for(; lit != lend; ++lit) { + if(eq(get_key(*lit), key)) { + BOOST_ERROR("Non-adjacent element with equivalent key in bucket."); + break; + } + } + }; + + // Finally, check that size matches up. + if(x1.size() != size) + BOOST_ERROR("x1.size() doesn't match actual size."); + if(static_cast(size) / x1.bucket_count() != x1.load_factor()) + BOOST_ERROR("x1.load_factor() doesn't match actual load_factor."); + } +} + +#endif + diff --git a/test/helpers/metafunctions.hpp b/test/helpers/metafunctions.hpp new file mode 100644 index 00000000..5f8a8ab9 --- /dev/null +++ b/test/helpers/metafunctions.hpp @@ -0,0 +1,103 @@ + +// 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 +#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 + : public boost::is_same< + typename Container::key_type, + typename Container::value_type> {}; + + template + struct is_map + : public boost::mpl::not_ > {}; + + struct yes_type { char x[100]; }; + struct no_type { char x[200]; }; + + template + yes_type has_unique_key_impl( + boost::unordered_set const*); + template + no_type has_unique_key_impl( + boost::unordered_multiset const*); + template + yes_type has_unique_key_impl( + boost::unordered_map const*); + template + no_type has_unique_key_impl( + boost::unordered_multimap const*); + + template + struct has_unique_keys + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(has_unique_key_impl((Container const*)0)) + == sizeof(yes_type)); + }; + + template + struct has_equivalent_keys + { + BOOST_STATIC_CONSTANT(bool, value = + sizeof(has_unique_key_impl((Container const*)0)) + == sizeof(no_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..91e41902 --- /dev/null +++ b/test/helpers/random_values.hpp @@ -0,0 +1,29 @@ + +// Copyright Daniel James 2005-2006. 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 +#include +#include "./generators.hpp" +#include "./metafunctions.hpp" + +namespace test +{ + template + struct random_values + : public std::vector::type> + { + random_values(int count) { + typedef typename non_const_value_type::type value_type; + static test::generator gen; + this->reserve(count); + std::generate_n(std::back_inserter(*this), count, gen); + } + }; +} + +#endif diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp new file mode 100644 index 00000000..d64bd92d --- /dev/null +++ b/test/helpers/tracker.hpp @@ -0,0 +1,146 @@ + +// Copyright Daniel James 2006. 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) + +// This header contains metafunctions/functions to get the equivalent +// associative container for an unordered container, and compare the contents. + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER + +#include +#include +#include +#include +#include +#include +#include +#include "../objects/fwd.hpp" +#include "./metafunctions.hpp" +#include "./helpers.hpp" + +namespace test +{ + template + struct equals_to_compare + { + typedef std::less type; + }; + + template <> + struct equals_to_compare + { + typedef test::less type; + }; + + template + void compare_range(X1 const& x1, X2 const& x2) + { + typedef typename non_const_value_type::type value_type; + std::vector values1, values2; + values1.reserve(x1.size()); + values2.reserve(x2.size()); + std::copy(x1.begin(), x1.end(), std::back_inserter(values1)); + std::copy(x2.begin(), x2.end(), std::back_inserter(values2)); + std::sort(values1.begin(), values1.end()); + std::sort(values2.begin(), values2.end()); + BOOST_TEST(values1 == values2); + } + + template + void compare_pairs(X1 const& x1, X2 const& x2, T*) + { + std::vector values1, values2; + values1.reserve(std::distance(x1.first, x1.second)); + values2.reserve(std::distance(x2.first, x2.second)); + std::copy(x1.first, x1.second, std::back_inserter(values1)); + std::copy(x2.first, x2.second, std::back_inserter(values2)); + std::sort(values1.begin(), values1.end()); + std::sort(values2.begin(), values2.end()); + BOOST_TEST(values1 == values2); + } + + template + struct ordered_set + : public boost::mpl::if_< + test::has_unique_keys, + std::set::type>, + std::multiset::type> + > {}; + + template + struct ordered_map + : public boost::mpl::if_< + test::has_unique_keys, + std::map::type>, + std::multimap::type> + > {}; + + template + struct ordered_base + : public boost::mpl::eval_if< + test::is_set, + test::ordered_set, + test::ordered_map > + { + }; + + template + class ordered : public ordered_base::type + { + typedef typename ordered_base::type base; + public: + typedef typename base::key_compare key_compare; + + ordered() + : base() + {} + + explicit ordered(key_compare const& compare) + : base(compare) + {} + + void compare(X const& x) + { + compare_range(x, *this); + } + + void compare_key(X const& x, typename X::value_type const& val) + { + compare_pairs( + x.equal_range(get_key(val)), + this->equal_range(get_key(val)), + (typename non_const_value_type::type*) 0 + ); + } + }; + + template + typename equals_to_compare::type create_compare( + Equals equals) + { + return typename equals_to_compare::type(); + } + + template + ordered create_ordered(X const& container) + { + return ordered(create_compare(container.key_eq())); + } + + template + void check_container(X1 const& container, X2 const& values) + { + ordered tracker = create_ordered(container); + tracker.insert(values.begin(), values.end()); + tracker.compare(container); + } +} + +#endif + diff --git a/test/objects/fwd.hpp b/test/objects/fwd.hpp new file mode 100644 index 00000000..c055de70 --- /dev/null +++ b/test/objects/fwd.hpp @@ -0,0 +1,18 @@ + +// Copyright Daniel James 2006. 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_FWD_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER + +namespace test +{ + class object; + class hash; + class less; + class equal_to; + template class allocator; +} + +#endif diff --git a/test/objects/test.hpp b/test/objects/test.hpp new file mode 100644 index 00000000..aacedfca --- /dev/null +++ b/test/objects/test.hpp @@ -0,0 +1,202 @@ + +// Copyright Daniel James 2006. 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_OBJECTS_HEADER) +#define BOOST_UNORDERED_TEST_OBJECTS_HEADER + +#include +#include "../helpers/fwd.hpp" +#include + +namespace test +{ + // Note that the default hash function will work for any equal_to (but not + // very well). + class object; + class hash; + class less; + class equal_to; + template class allocator; + + class object + { + friend class hash; + friend class equal_to; + friend class less; + int tag1_, tag2_; + public: + explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {} + + friend bool operator==(object const& x1, object const& x2) { + return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_; + } + + friend bool operator!=(object const& x1, object const& x2) { + return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_; + } + + friend bool operator<(object const& x1, object const& x2) { + return x1.tag1_ < x2.tag1_ || + (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); + } + + + friend object generate(object const*) { + int* x; + return object(generate(x), generate(x)); + } + + friend std::ostream& operator<<(std::ostream& out, object const& o) + { + return out<<"("< + class allocator + { + public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + 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; }; + + explicit allocator(int t = 0) {} + template allocator(allocator const& x) {} + allocator(allocator const&) {} + ~allocator() {} + + 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(::operator new(n * sizeof(T)))); + } + + pointer allocate(size_type n, const_pointer u) + { + return pointer(static_cast(::operator new(n * sizeof(T)))); + } + + void deallocate(pointer p, size_type n) + { + ::operator delete((void*) p); + } + + void construct(pointer p, T const& t) { new(p) T(t); } + void destroy(pointer p) { p->~T(); } + + size_type max_size() const { return 1000; } + }; + + template + inline bool operator==(allocator const& x, allocator const& y) + { + return true; + } + + template + inline bool operator!=(allocator const& x, allocator const& y) + { + return false; + } +} + +#endif diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 new file mode 100644 index 00000000..007f7759 --- /dev/null +++ b/test/unordered/Jamfile.v2 @@ -0,0 +1,23 @@ + +# Copyright Daniel James 2006. 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/unordered + : requirements + intel-linux:"-strict_ansi -cxxlib-icc" + ; + +test-suite unordered-tests + : + [ run equivalent_keys_tests.cpp ] + [ run compile_tests.cpp ] + [ run constructor_tests.cpp ] + [ run copy_tests.cpp ] + [ run assign_tests.cpp ] + [ run insert_tests.cpp ] + [ run erase_tests.cpp ] + [ run find_tests.cpp ] + ; diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp new file mode 100644 index 00000000..91b47371 --- /dev/null +++ b/test/unordered/assign_tests.cpp @@ -0,0 +1,91 @@ + +// Copyright Daniel James 2006. 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" + +#include + +template +void assign_tests1(T* = 0) +{ + typename T::hasher hf; + typename T::key_equal eq; + + std::cerr<<"assign_tests1.1\n"; + { + T x; + x = x; + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + } + + std::cerr<<"assign_tests1.2\n"; + { + test::random_values v(1000); + T x(v.begin(), v.end()); + + test::ordered tracker = test::create_ordered(x); + tracker.insert(v.begin(), v.end()); + + x = x; + tracker.compare(x); + + T y; + y.max_load_factor(x.max_load_factor() / 20); + y = x; + tracker.compare(y); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); + } +} + +template +void assign_tests2(T* = 0) +{ + typename T::hasher hf; + typename T::key_equal eq; + typename T::hasher hf1(1); + typename T::key_equal eq1(1); + typename T::hasher hf2(2); + typename T::key_equal eq2(2); + + std::cerr<<"assign_tests2.1\n"; + { + // TODO: Need to generate duplicates... + test::random_values v(1000); + T x1(v.begin(), v.end(), 0, hf1, eq1); + T x2(0, hf2, eq2); + x2 = x1; + BOOST_TEST(test::equivalent(x2.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x2.key_eq(), eq1)); + check_container(x2, v); + } +} + +int main() +{ + assign_tests1((boost::unordered_set*) 0); + assign_tests1((boost::unordered_multiset*) 0); + assign_tests1((boost::unordered_map*) 0); + assign_tests1((boost::unordered_multimap*) 0); + + assign_tests1((boost::unordered_set >*) 0); + assign_tests1((boost::unordered_multiset >*) 0); + assign_tests1((boost::unordered_map >*) 0); + assign_tests1((boost::unordered_multimap >*) 0); + + assign_tests2((boost::unordered_set >*) 0); + assign_tests2((boost::unordered_multiset >*) 0); + assign_tests2((boost::unordered_map >*) 0); + assign_tests2((boost::unordered_multimap >*) 0); + + return boost::report_errors(); +} diff --git a/test/unordered/compile_tests.cpp b/test/unordered/compile_tests.cpp new file mode 100644 index 00000000..ccc90b0c --- /dev/null +++ b/test/unordered/compile_tests.cpp @@ -0,0 +1,297 @@ + +// Copyright Daniel James 2006. 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/check_return_type.hpp" + +#include +#include +#include "../objects/minimal.hpp" + +template void sink(T const&) {} + +template +void unordered_set_test(X& r, Key const& k) +{ + BOOST_MPL_ASSERT((boost::is_same< + typename X::value_type, + typename X::key_type>)); +} + +template +void unordered_map_test(X& r, Key const& k, T const& t) +{ + BOOST_MPL_ASSERT((boost::is_same< + typename X::value_type, + std::pair >)); +} + +template +void unordered_unique_test(X& r, T const& t) +{ + typedef typename X::iterator iterator; + test::check_return_type >::equals(r.insert(t)); +} + +template +void unordered_equivalent_test(X& r, T const& t) +{ + typedef typename X::iterator iterator; + test::check_return_type::equals(r.insert(t)); +} + +template +void unordered_test(X& ref, Key& k, T& t, Hash& hf, Pred& eq) +{ + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::local_iterator local_iterator; + typedef typename X::const_local_iterator const_local_iterator; + + typedef typename X::key_type key_type; + typedef typename X::hasher hasher; + typedef typename X::key_equal key_equal; + + BOOST_MPL_ASSERT((boost::is_same)); + boost::function_requires >(); + boost::function_requires >(); + + BOOST_MPL_ASSERT((boost::is_same)); + test::check_return_type::equals(hf(k)); + + BOOST_MPL_ASSERT((boost::is_same)); + test::check_return_type::convertible(eq(k, k)); + // TODO: Pred is an equivalence relation. Doesn't really matter for these + // tests. + + boost::function_requires >(); + 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_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::function_requires >(); + 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_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 >)); + + X(10, hf, eq); + X a(10, hf, eq); + X(10, hf); + X a2(10, hf); + X(10); + X a3(10); + X(); + X a4(); + + typename X::value_type* i = 0; + typename X::value_type* j = 0; + + X(i, j, 10, hf, eq); + X a5(i, j, 10, hf, eq); + X(i, j, 10, hf); + X a6(i, j, 10, hf); + X(i, j, 10); + X a7(i, j, 10); + X(i, j); + X a8(i, j); + + X const b; + sink(X(b)); + X a9(b); + a = b; + + test::check_return_type::equals(b.hash_function()); + test::check_return_type::equals(b.key_eq()); + + iterator q = a.begin(); + const_iterator r = a.begin(); + test::check_return_type::equals(a.insert(q, t)); + test::check_return_type::equals(a.insert(r, t)); + + // TODO: void return? + a.insert(i, j); + test::check_return_type::equals(a.erase(k)); + + BOOST_TEST(a.empty()); + if(a.empty()) { + a.insert(t); + q = a.begin(); + test::check_return_type::equals(a.erase(q)); + } + + BOOST_TEST(a.empty()); + if(a.empty()) { + a.insert(t); + r = a.begin(); + test::check_return_type::equals(a.erase(r)); + } + + iterator q1 = a.begin(), q2 = a.end(); + test::check_return_type::equals(a.erase(q1, q2)); + + const_iterator r1 = a.begin(), r2 = a.end(); + test::check_return_type::equals(a.erase(r1, r2)); + + // TODO: void return? + a.clear(); + + test::check_return_type::equals(a.find(k)); + test::check_return_type::equals(b.find(k)); + test::check_return_type::equals(b.count(k)); + test::check_return_type >::equals( + a.equal_range(k)); + test::check_return_type >::equals( + b.equal_range(k)); + test::check_return_type::equals(b.bucket_count()); + test::check_return_type::equals(b.max_bucket_count()); + test::check_return_type::equals(b.bucket(k)); + test::check_return_type::equals(b.bucket_size(0)); + + test::check_return_type::equals(a.begin(0)); + test::check_return_type::equals(b.begin(0)); + test::check_return_type::equals(a.end(0)); + test::check_return_type::equals(b.end(0)); + + test::check_return_type::equals(b.load_factor()); + test::check_return_type::equals(b.max_load_factor()); + a.max_load_factor((float) 2.0); + a.rehash(100); +} + +void test1() +{ + boost::hash hash; + std::equal_to equal_to; + int value = 0; + std::pair map_value(0, 0); + + std::cout<<"Test unordered_set.\n"; + + boost::unordered_set set; + + unordered_unique_test(set, value); + unordered_set_test(set, value); + unordered_test(set, value, value, hash, equal_to); + + std::cout<<"Test unordered_multiset.\n"; + + boost::unordered_multiset multiset; + + unordered_equivalent_test(multiset, value); + unordered_set_test(multiset, value); + unordered_test(multiset, value, value, hash, equal_to); + + std::cout<<"Test unordered_map.\n"; + + boost::unordered_map map; + + unordered_unique_test(map, map_value); + unordered_map_test(map, value, value); + unordered_test(map, value, map_value, hash, equal_to); + + std::cout<<"Test unordered_multimap.\n"; + + boost::unordered_multimap multimap; + + unordered_equivalent_test(multimap, map_value); + unordered_map_test(multimap, value, value); + unordered_test(multimap, value, map_value, hash, equal_to); +} + +void test2() +{ + test::minimal::assignable assignable + = test::minimal::assignable::create(); + test::minimal::copy_constructible copy_constructible + = test::minimal::copy_constructible::create(); + test::minimal::hash hash + = test::minimal::hash::create(); + test::minimal::equal_to equal_to + = test::minimal::equal_to::create(); + + typedef std::pair map_value_type; + map_value_type map_value(assignable, copy_constructible); + + std::cout<<"Test unordered_set.\n"; + + boost::unordered_set< + test::minimal::assignable, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator > set; + + unordered_unique_test(set, assignable); + unordered_set_test(set, assignable); + unordered_test(set, assignable, assignable, hash, equal_to); + + std::cout<<"Test unordered_multiset.\n"; + + boost::unordered_multiset< + test::minimal::assignable, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator > multiset; + + unordered_equivalent_test(multiset, assignable); + unordered_set_test(multiset, assignable); + unordered_test(multiset, assignable, assignable, hash, equal_to); + + std::cout<<"Test unordered_map.\n"; + + boost::unordered_map< + test::minimal::assignable, + test::minimal::copy_constructible, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator > map; + + unordered_unique_test(map, map_value); + unordered_map_test(map, assignable, copy_constructible); + unordered_test(map, assignable, map_value, hash, equal_to); + + std::cout<<"Test unordered_multimap.\n"; + + boost::unordered_multimap< + test::minimal::assignable, + test::minimal::copy_constructible, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator > multimap; + + unordered_equivalent_test(multimap, map_value); + unordered_map_test(multimap, assignable, copy_constructible); + unordered_test(multimap, assignable, map_value, hash, equal_to); +} + +int main() { + test1(); + test2(); + + return boost::report_errors(); +} diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp new file mode 100644 index 00000000..5114331c --- /dev/null +++ b/test/unordered/constructor_tests.cpp @@ -0,0 +1,202 @@ + +// Copyright Daniel James 2006. 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" + +#include + +template +void constructor_tests1(T* = 0) +{ + typename T::hasher hf; + typename T::key_equal eq; + + std::cerr<<"Construct 1\n"; + { + T x(0, hf, eq); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 0); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + } + + std::cerr<<"Construct 2\n"; + { + T x(100, hf); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 100); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + } + + std::cerr<<"Construct 3\n"; + { + T x(2000); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 2000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + } + + std::cerr<<"Construct 4\n"; + { + T x; + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + } + + std::cerr<<"Construct 5\n"; + { + test::random_values v(1000); + T x(v.begin(), v.end(), 10000, hf, eq); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + check_container(x, v); + } + + std::cerr<<"Construct 6\n"; + { + test::random_values v(10); + T x(v.begin(), v.end(), 10000, hf); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + check_container(x, v); + } + + std::cerr<<"Construct 7\n"; + { + test::random_values v(100); + T x(v.begin(), v.end(), 100); + BOOST_TEST(x.bucket_count() >= 100); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + check_container(x, v); + } + + std::cerr<<"Construct 8\n"; + { + test::random_values v(1); + T x(v.begin(), v.end()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + check_container(x, v); + } +} + +template +void constructor_tests2(T* = 0) +{ + typename T::hasher hf; + typename T::hasher hf1(1); + typename T::hasher hf2(2); + typename T::key_equal eq; + typename T::key_equal eq1(1); + typename T::key_equal eq2(2); + + std::cerr<<"Construct 1\n"; + { + T x(10000, hf1, eq1); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq1)); + } + + std::cerr<<"Construct 2\n"; + { + T x(100, hf1); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 100); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + } + + std::cerr<<"Construct 3\n"; + { + test::random_values v(100); + T x(v.begin(), v.end(), 0, hf1, eq1); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq1)); + check_container(x, v); + } + + std::cerr<<"Construct 4\n"; + { + test::random_values v(5); + T x(v.begin(), v.end(), 1000, hf1); + BOOST_TEST(x.bucket_count() >= 1000); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + check_container(x, v); + } + + + std::cerr<<"Construct 5\n"; + { + test::random_values v(100); + T x(v.begin(), v.end(), 0, hf, eq); + T y(x.begin(), x.end(), 0, hf1, eq1); + check_container(x, v); + check_container(y, x); + } + + std::cerr<<"Construct 6\n"; + { + test::random_values v(100); + T x(v.begin(), v.end(), 0, hf1, eq1); + T y(x.begin(), x.end(), 0, hf, eq); + check_container(x, v); + check_container(y, x); + } + + std::cerr<<"Construct 7\n"; + { + test::random_values v(100); + T x(v.begin(), v.end(), 0, hf1, eq1); + T y(x.begin(), x.end(), 0, hf2, eq2); + check_container(x, v); + check_container(y, x); + } +} + +int main() +{ + std::cerr<<"Test1 unordered_set\n"; + constructor_tests1((boost::unordered_set*) 0); + std::cerr<<"Test1 unordered_multiset\n"; + constructor_tests1((boost::unordered_multiset*) 0); + std::cerr<<"Test1 unordered_map\n"; + constructor_tests1((boost::unordered_map*) 0); + std::cerr<<"Test1 unordered_multimap\n"; + constructor_tests1((boost::unordered_multimap*) 0); + + std::cerr<<"Test1 unordered_set\n"; + constructor_tests1((boost::unordered_set >*) 0); + std::cerr<<"Test1 unordered_multiset\n"; + constructor_tests1((boost::unordered_multiset >*) 0); + std::cerr<<"Test1 unordered_map\n"; + constructor_tests1((boost::unordered_map >*) 0); + std::cerr<<"Test1 unordered_multimap\n"; + constructor_tests1((boost::unordered_multimap >*) 0); + + std::cerr<<"Test2 unordered_set\n"; + constructor_tests2((boost::unordered_set >*) 0); + std::cerr<<"Test2 unordered_multiset\n"; + constructor_tests2((boost::unordered_multiset >*) 0); + std::cerr<<"Test2 unordered_map\n"; + constructor_tests2((boost::unordered_map >*) 0); + std::cerr<<"Test2 unordered_multimap\n"; + constructor_tests2((boost::unordered_multimap >*) 0); + + return boost::report_errors(); +} diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp new file mode 100644 index 00000000..1a72bf9f --- /dev/null +++ b/test/unordered/copy_tests.cpp @@ -0,0 +1,103 @@ + +// Copyright Daniel James 2006. 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" + +template +void copy_construct_tests1(T* = 0) +{ + typename T::hasher hf; + typename T::key_equal eq; + + { + T x; + T y(x); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); + test::check_equivalent_keys(y); + } + + { + test::random_values v(1000); + + T x(v.begin(), v.end()); + T y(x); + test::unordered_equivalence_tester equivalent(x); + equivalent(y); + test::check_equivalent_keys(y); + } + + { + // In this test I drop the original containers max load factor, so it + // is much lower than the load factor. The hash table is not allowed + // to rehash, but the destination container should probably allocate + // enough buckets to decrease the load factor appropriately. Although, + // I don't think it has to. + test::random_values v(1000); + T x(v.begin(), v.end()); + x.max_load_factor(x.load_factor() / 4); + T y(x); + test::unordered_equivalence_tester equivalent(x); + equivalent(y); + // I don't think this is guaranteed: + BOOST_TEST(y.load_factor() < y.max_load_factor()); + test::check_equivalent_keys(y); + } +} + +template +void copy_construct_tests2(T* ptr = 0) +{ + copy_construct_tests1(ptr); + + typename T::hasher hf(1); + typename T::key_equal eq(1); + + { + // TODO: I could check how many buckets y has, it should be lower (QOI issue). + T x(10000, hf, eq); + T y(x); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); + test::check_equivalent_keys(y); + } + + { + // TODO: Invariant checks are especially important here. + test::random_values v(1000); + + T x(v.begin(), v.end(), 0, hf, eq); + T y(x); + test::unordered_equivalence_tester equivalent(x); + equivalent(y); + test::check_equivalent_keys(y); + } +} + +int main() +{ + copy_construct_tests1((boost::unordered_set*) 0); + copy_construct_tests1((boost::unordered_multiset*) 0); + copy_construct_tests1((boost::unordered_map*) 0); + copy_construct_tests1((boost::unordered_multimap*) 0); + + copy_construct_tests2((boost::unordered_set >*) 0); + copy_construct_tests2((boost::unordered_multiset >*) 0); + copy_construct_tests2((boost::unordered_map >*) 0); + copy_construct_tests2((boost::unordered_multimap >*) 0); + + return boost::report_errors(); +} diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp new file mode 100644 index 00000000..d6c6a792 --- /dev/null +++ b/test/unordered/equivalent_keys_tests.cpp @@ -0,0 +1,85 @@ + +// Copyright Daniel James 2006. 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 +#include "../helpers/tracker.hpp" +#include "../helpers/invariants.hpp" + +#include + +template +void test_equal_insertion(Iterator begin, Iterator end) +{ + typedef test::ordered tracker; + + Container x1; + tracker x2 = test::create_ordered(x1); + + for(Iterator it = begin; it != end; ++it) { + x1.insert(*it); + x2.insert(*it); + x2.compare_key(x1, *it); + } + + x2.compare(x1); + test::check_equivalent_keys(x1); +} + +void set_tests() +{ + int values[][5] = { + {1}, + {54, 23}, + {-13, 65}, + {77, 77}, + {986, 25, 986} + }; + + test_equal_insertion >(values[0], values[0] + 1); + test_equal_insertion >(values[1], values[1] + 2); + test_equal_insertion >(values[2], values[2] + 2); + test_equal_insertion >(values[3], values[3] + 2); + test_equal_insertion >(values[4], values[4] + 3); + + test_equal_insertion >(values[0], values[0] + 1); + test_equal_insertion >(values[1], values[1] + 2); + test_equal_insertion >(values[2], values[2] + 2); + test_equal_insertion >(values[3], values[3] + 2); + test_equal_insertion >(values[4], values[4] + 3); +} + +void map_tests() +{ + typedef std::deque > values_type; + values_type v[5]; + v[0].push_back(std::pair(1,1)); + v[1].push_back(std::pair(28,34)); + v[1].push_back(std::pair(16,58)); + v[1].push_back(std::pair(-124, 62)); + v[2].push_back(std::pair(432,12)); + v[2].push_back(std::pair(9,13)); + v[2].push_back(std::pair(432,24)); + + for(int i = 0; i < 5; ++i) + test_equal_insertion >( + v[i].begin(), v[i].end()); + + for(int i2 = 0; i2 < 5; ++i2) + test_equal_insertion >( + v[i2].begin(), v[i2].end()); +} + +int main() +{ + set_tests(); + map_tests(); + + return boost::report_errors(); +} diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp new file mode 100644 index 00000000..5ca4f641 --- /dev/null +++ b/test/unordered/erase_tests.cpp @@ -0,0 +1,140 @@ + +// Copyright Daniel James 2006. 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/helpers.hpp" + +#include + +template +void erase_tests1(Container* = 0) +{ + std::cerr<<"Erase by key.\n"; + { + test::random_values v(1000); + Container x(v.begin(), v.end()); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + std::size_t count = x.count(test::get_key(*it)); + std::size_t old_size = x.size(); + BOOST_TEST(count == x.erase(test::get_key(*it))); + BOOST_TEST(x.size() == old_size - count); + BOOST_TEST(x.count(test::get_key(*it)) == 0); + BOOST_TEST(x.find(test::get_key(*it)) == x.end()); + } + } + + std::cerr<<"erase(begin()).\n"; + { + test::random_values v(1000); + Container x(v.begin(), v.end()); + std::size_t size = x.size(); + while(size > 0 && !x.empty()) + { + typename Container::key_type key = test::get_key(*x.begin()); + std::size_t count = x.count(key); + typename Container::iterator pos = x.erase(x.begin()); + --size; + BOOST_TEST(pos == x.begin()); + BOOST_TEST(x.count(key) == count - 1); + BOOST_TEST(x.size() == size); + } + BOOST_TEST(x.empty()); + } + + std::cerr<<"erase(random position).\n"; + { + test::random_values v(1000); + Container x(v.begin(), v.end()); + std::size_t size = x.size(); + while(size > 0 && !x.empty()) + { + using namespace std; + int index = rand() % x.size(); + typename Container::const_iterator prev, pos, next; + if(index == 0) { + prev = pos = x.begin(); + } + else { + prev = boost::next(x.begin(), index - 1); + pos = boost::next(prev); + } + next = boost::next(pos); + typename Container::key_type key = test::get_key(*x.begin()); + std::size_t count = x.count(key); + BOOST_TEST(next == x.erase(pos)); + --size; + if(size > 0) + BOOST_TEST(next == + (index == 0 ? x.begin() : boost::next(prev))); + BOOST_TEST(x.count(key) == count - 1); + std::cerr< v(500); + Container x(v.begin(), v.end()); + + std::size_t size = x.size(); + + // I'm actually stretching it a little here, as the standard says it + // returns 'the iterator immediately following the erase elements' + // and if nothing is erased, then there's nothing to follow. But I + // think this is the only sensible option... + BOOST_TEST(x.erase(x.end(), x.end()) == x.end()); + BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin()); + BOOST_TEST(x.size() == size); + + BOOST_TEST(x.erase(x.begin(), x.end()) == x.end()); + BOOST_TEST(x.empty()); + BOOST_TEST(x.begin() == x.end()); + + BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin()); + } + + // TODO: More range erase tests. + + std::cerr<<"clear().\n"; + { + test::random_values v(500); + Container x(v.begin(), v.end()); + x.clear(); + BOOST_TEST(x.empty()); + BOOST_TEST(x.begin() == x.end()); + } +} + +int main() +{ + std::cerr<<"Erase unordered_set.\n"; + erase_tests1((boost::unordered_set*) 0); + std::cerr<<"\nErase unordered_multiset.\n"; + erase_tests1((boost::unordered_multiset*) 0); + std::cerr<<"\nErase unordered_map.\n"; + erase_tests1((boost::unordered_map*) 0); + std::cerr<<"\nErase unordered_multimap.\n"; + erase_tests1((boost::unordered_multimap*) 0); + + std::cerr<<"\nErase unordered_set.\n"; + erase_tests1((boost::unordered_set >*) 0); + std::cerr<<"\nErase unordered_multiset.\n"; + erase_tests1((boost::unordered_multiset >*) 0); + std::cerr<<"\nErase unordered_map.\n"; + erase_tests1((boost::unordered_map >*) 0); + std::cerr<<"\nErase unordered_multimap.\n"; + erase_tests1((boost::unordered_multimap >*) 0); +} diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp new file mode 100644 index 00000000..89b53870 --- /dev/null +++ b/test/unordered/find_tests.cpp @@ -0,0 +1,90 @@ + +// Copyright Daniel James 2006. 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/helpers.hpp" + +template +void find_tests1(X*) +{ + { + test::random_values v(500); + X x(v.begin(), v.end()); + X const& x_const = x; + test::ordered tracker = test::create_ordered(x); + tracker.insert(v.begin(), v.end()); + + for(typename test::ordered::const_iterator it = + tracker.begin(); it != tracker.end(); ++it) + { + typename X::key_type key = test::get_key(*it); + typename X::iterator pos = x.find(key); + typename X::const_iterator const_pos = x_const.find(key); + BOOST_TEST(pos != x.end() && + x.key_eq()(key, test::get_key(*pos))); + BOOST_TEST(const_pos != x_const.end() && + x_const.key_eq()(key, test::get_key(*const_pos))); + + BOOST_TEST(x.count(key) == tracker.count(key)); + + test::compare_pairs(x.equal_range(key), + tracker.equal_range(key), + (typename test::non_const_value_type::type*) 0); + test::compare_pairs(x_const.equal_range(key), + tracker.equal_range(key), + (typename test::non_const_value_type::type*) 0); + } + + test::random_values v2(500); + for(typename test::random_values::const_iterator it = + v2.begin(); it != v2.end(); ++it) + { + typename X::key_type key = test::get_key(*it); + if(tracker.find(test::get_key(key)) == tracker.end()) + { + BOOST_TEST(x.find(key) == x.end()); + BOOST_TEST(x_const.find(key) == x_const.end()); + BOOST_TEST(x.count(key) == 0); + std::pair range = x.equal_range(key); + BOOST_TEST(range.first == range.second); + } + } + } + + { + X x; + + test::random_values v2(5); + for(typename test::random_values::const_iterator it = + v2.begin(); it != v2.end(); ++it) + { + typename X::key_type key = test::get_key(*it); + BOOST_TEST(x.find(key) == x.end()); + BOOST_TEST(x.count(key) == 0); + std::pair range = x.equal_range(key); + BOOST_TEST(range.first == range.second); + } + } +} + +int main() +{ + find_tests1((boost::unordered_set*) 0); + find_tests1((boost::unordered_multiset*) 0); + find_tests1((boost::unordered_map*) 0); + find_tests1((boost::unordered_multimap*) 0); + + find_tests1((boost::unordered_set >*) 0); + find_tests1((boost::unordered_multiset >*) 0); + find_tests1((boost::unordered_map >*) 0); + find_tests1((boost::unordered_multimap >*) 0); +} diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp new file mode 100644 index 00000000..14d98347 --- /dev/null +++ b/test/unordered/insert_tests.cpp @@ -0,0 +1,188 @@ + +// Copyright Daniel James 2006. 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" + +#include + +template +void unique_insert_tests1(Container* = 0) +{ + std::cerr<<"insert(value) tests for containers with unique keys.\n"; + + Container x; + test::ordered tracker = test::create_ordered(x); + + test::random_values v(1000); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + std::pair r1 = x.insert(*it); + std::pair::iterator, bool> r2 + = tracker.insert(*it); + + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); + + tracker.compare_key(x, *it); + } + + test::check_equivalent_keys(x); +} + +template +void equivalent_insert_tests1(Container* = 0) +{ + std::cerr<<"insert(value) tests for containers with equivalent keys.\n"; + + Container x; + test::ordered tracker = test::create_ordered(x); + + test::random_values v(1000); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + typename Container::iterator r1 = x.insert(*it); + typename test::ordered::iterator r2 = tracker.insert(*it); + + BOOST_TEST(*r1 == *r2); + + tracker.compare_key(x, *it); + } + + test::check_equivalent_keys(x); +} + +template +void insert_tests2(Container* = 0) +{ + typedef typename test::ordered tracker_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef typename tracker_type::iterator tracker_iterator; + + std::cerr<<"insert(begin(), value) tests.\n"; + + { + Container x; + tracker_type tracker = test::create_ordered(x); + + test::random_values v(1000); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + iterator r1 = x.insert(x.begin(), *it); + tracker_iterator r2 = tracker.insert(tracker.begin(), *it); + BOOST_TEST(*r1 == *r2); + tracker.compare_key(x, *it); + } + + test::check_equivalent_keys(x); + } + + std::cerr<<"insert(end(), value) tests.\n"; + + { + Container x; + Container const& x_const = x; + tracker_type tracker = test::create_ordered(x); + + test::random_values v(100); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + const_iterator r1 = x.insert(x_const.end(), *it); + tracker_iterator r2 = tracker.insert(tracker.end(), *it); + BOOST_TEST(*r1 == *r2); + tracker.compare_key(x, *it); + } + + test::check_equivalent_keys(x); + } + + std::cerr<<"insert(pos, value) tests.\n"; + + { + Container x; + const_iterator pos = x.begin(); + tracker_type tracker = test::create_ordered(x); + + test::random_values v(1000); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + pos = x.insert(pos, *it); + tracker_iterator r2 = tracker.insert(tracker.begin(), *it); + BOOST_TEST(*pos == *r2); + tracker.compare_key(x, *it); + } + + test::check_equivalent_keys(x); + } + + std::cerr<<"insert single item range tests.\n"; + + { + Container x; + tracker_type tracker = test::create_ordered(x); + + test::random_values v(1000); + for(typename test::random_values::iterator it = v.begin(); + it != v.end(); ++it) + { + x.insert(it, boost::next(it)); + tracker.insert(*it); + tracker.compare_key(x, *it); + } + + test::check_equivalent_keys(x); + } + + std::cerr<<"insert range tests.\n"; + + { + Container x; + const_iterator pos = x.begin(); + + test::random_values v(1000); + x.insert(v.begin(), v.end()); + check_container(x, v); + + test::check_equivalent_keys(x); + } +} + +int main() +{ + unique_insert_tests1((boost::unordered_set*) 0); + equivalent_insert_tests1((boost::unordered_multiset*) 0); + unique_insert_tests1((boost::unordered_map*) 0); + equivalent_insert_tests1((boost::unordered_multimap*) 0); + + unique_insert_tests1((boost::unordered_set >*) 0); + equivalent_insert_tests1((boost::unordered_multiset >*) 0); + unique_insert_tests1((boost::unordered_map >*) 0); + equivalent_insert_tests1((boost::unordered_multimap >*) 0); + + insert_tests2((boost::unordered_set*) 0); + insert_tests2((boost::unordered_multiset*) 0); + insert_tests2((boost::unordered_map*) 0); + insert_tests2((boost::unordered_multimap*) 0); + + insert_tests2((boost::unordered_set >*) 0); + insert_tests2((boost::unordered_multiset >*) 0); + insert_tests2((boost::unordered_map >*) 0); + insert_tests2((boost::unordered_multimap >*) 0); + + return boost::report_errors(); +}