From ec310f7b80a86d49cbae74216b490aacacc8e215 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 31 Oct 2006 22:19:26 +0000 Subject: [PATCH] Update the unordered tests. Several changes including extra erase tests. The newer version of the containers have a hairy erase implementation, so need to test all the special cases. Also, a few extra tests here and there, avoid a couple of warnings and remove some old TODOs. [SVN r3341] --- test/container/compile_tests.hpp | 2 +- test/container/simple_tests.cpp | 7 - test/exception/erase_tests.cpp | 7 - test/exception/rehash_tests.cpp | 2 - test/helpers/generators.hpp | 61 +++------ test/helpers/input_iterator.hpp | 1 - test/helpers/invariants.hpp | 4 +- test/helpers/random_values.hpp | 8 +- test/helpers/strong.hpp | 8 -- test/helpers/tracker.hpp | 3 +- test/objects/exception.hpp | 38 +++--- test/objects/minimal.hpp | 27 +--- test/objects/test.hpp | 16 +-- test/unordered/Jamfile.v2 | 1 + test/unordered/assign_tests.cpp | 2 - test/unordered/constructor_tests.cpp | 43 ++++++ test/unordered/copy_tests.cpp | 2 - test/unordered/erase_equiv_tests.cpp | 195 +++++++++++++++++++++++++++ test/unordered/erase_tests.cpp | 2 - test/unordered/insert_tests.cpp | 21 ++- 20 files changed, 316 insertions(+), 134 deletions(-) create mode 100644 test/unordered/erase_equiv_tests.cpp diff --git a/test/container/compile_tests.hpp b/test/container/compile_tests.hpp index 70c02a13..264e038a 100644 --- a/test/container/compile_tests.hpp +++ b/test/container/compile_tests.hpp @@ -17,7 +17,7 @@ typedef long double comparison_type; template void sink(T const&) {} template -void container_test(X& r, T& value) +void container_test(X& r, T&) { typedef typename X::iterator iterator; typedef typename X::const_iterator const_iterator; diff --git a/test/container/simple_tests.cpp b/test/container/simple_tests.cpp index 265df168..91640148 100644 --- a/test/container/simple_tests.cpp +++ b/test/container/simple_tests.cpp @@ -43,7 +43,6 @@ void simple_test(X const& a) } { - // TODO: Also test with a random container... X b(a); X c; BOOST_TEST(equivalent(b)); @@ -59,8 +58,6 @@ void simple_test(X const& a) { X u; X& r = u; - // TODO: I can't actually see a requirement for that assignment - // returns a reference to itself (just that it returns a reference). BOOST_TEST(&(r = r) == &r); BOOST_TEST(r.empty()); BOOST_TEST(&(r = a) == &r); @@ -74,8 +71,6 @@ void simple_test(X const& a) (typename X::size_type) std::distance(a.begin(), a.end())); } - // TODO: Test max_size against allocator? - { BOOST_TEST(a.empty() == (a.size() == 0)); } @@ -85,8 +80,6 @@ void simple_test(X const& a) X u; BOOST_TEST(u.begin() == u.end()); } - - // TODO: Test construction with allocator? } int main() diff --git a/test/exception/erase_tests.cpp b/test/exception/erase_tests.cpp index 98cc5b1e..c1709a9d 100644 --- a/test/exception/erase_tests.cpp +++ b/test/exception/erase_tests.cpp @@ -27,8 +27,6 @@ struct erase_test_base : public test::exception_base void check(T const& x) const { std::string scope(test::scope); - // TODO: Instead of checking for 'operator==', I should check against - // a scope stack. BOOST_CHECK(scope.find("hash::") != std::string::npos || scope.find("equal_to::") != std::string::npos || scope == "operator==(object, object)"); @@ -52,11 +50,6 @@ struct erase_by_key_test1 : public erase_test_base } }; -// TODO: More tests... -// Better test by key. -// Test other erase signatures - generally they won't throw, but the standard -// does allow them to. And test clear as well. - RUN_EXCEPTION_TESTS( (erase_by_key_test1), CONTAINER_SEQ) diff --git a/test/exception/rehash_tests.cpp b/test/exception/rehash_tests.cpp index 9811c162..0634b44d 100644 --- a/test/exception/rehash_tests.cpp +++ b/test/exception/rehash_tests.cpp @@ -33,8 +33,6 @@ struct rehash_test_base : public test::exception_base void check(T const& x, strong_type const& strong) const { std::string scope(test::scope); - // TODO: Instead of checking for 'operator==', I should check against - // a scope stack. if(scope.find("hash::operator()") == std::string::npos && scope.find("equal_to::operator()") == std::string::npos && scope != "operator==(object, object)") diff --git a/test/helpers/generators.hpp b/test/helpers/generators.hpp index 84350fa0..260a45b5 100644 --- a/test/helpers/generators.hpp +++ b/test/helpers/generators.hpp @@ -10,25 +10,31 @@ #include #include - -#if 0 +#include #include #include #include #include #include -#else -#include -#endif #include "./fwd.hpp" namespace test { -#if 0 typedef boost::hellekalek1995 integer_generator_type; typedef boost::lagged_fibonacci607 real_generator_type; -#endif + + template + struct generator; + + template std::pair generate( + std::pair const*) + { + static generator g1; + static generator g2; + + return std::pair(g1(), g2()); + } template struct generator @@ -42,30 +48,20 @@ namespace test inline int generate(int const*) { -#if 0 - integer_generator_type gen; - boost::uniform_int<> dist(0, 1000); + static integer_generator_type gen; + static boost::uniform_int<> dist(0, 1000); static boost::variate_generator > vg(gen, dist); return vg(); -#else - using namespace std; - return rand(); -#endif } inline char generate(char const*) { -#if 0 - integer_generator_type gen; - boost::uniform_int dist(32, 127); + static integer_generator_type gen; + static boost::uniform_int dist(32, 127); static boost::variate_generator > vg(gen, dist); return vg(); -#else - using namespace std; - return rand() % (128 - 32) + 32; -#endif } inline std::string generate(std::string const*) @@ -80,35 +76,16 @@ namespace test 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*) { -#if 0 - real_generator_type gen; - boost::uniform_real dist; + static real_generator_type gen; + static boost::uniform_real dist; static boost::variate_generator > vg(gen, dist); return vg(); -#else - using namespace std; - return (double) rand() / (double) RAND_MAX; -#endif - } - - template std::pair generate( - std::pair const*) - { - static generator g1; - static generator g2; - - return std::pair(g1(), g2()); } } diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index 3731a408..06a1eade 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -11,7 +11,6 @@ namespace test { - // TODO: Make this a stricter input iterator. template struct input_iterator_adaptor : boost::iterator_adaptor< diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index 50dcfd2b..177a94f2 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -49,8 +49,10 @@ namespace test if(test::has_unique_keys::value && count != 1) BOOST_ERROR("Non-unique key."); - if(x1.count(key) != count) + if(x1.count(key) != count) { BOOST_ERROR("Incorrect output of count."); + std::cerr< +#include #include #include "./generators.hpp" -#include "./metafunctions.hpp" namespace test { template struct random_values - : public std::vector::type> + : public std::list { random_values(int count) { - typedef typename non_const_value_type::type value_type; + typedef typename X::value_type value_type; static test::generator gen; - this->reserve(count); std::generate_n(std::back_inserter(*this), count, gen); } }; diff --git a/test/helpers/strong.hpp b/test/helpers/strong.hpp index c3fcfaa5..9636c3e1 100644 --- a/test/helpers/strong.hpp +++ b/test/helpers/strong.hpp @@ -22,14 +22,6 @@ namespace test values_type values_; public: void store(X const& x) { - // TODO: Well, I shouldn't be disabling exceptions here. Instead - // the test runner should provide a method to the test which - // disables exceptions and calls this. - // - // Actually, the test runner could also keep track of how many times - // store is called in a run. Because it knows that in the next run - // the first n-1 stores are unnecessary - since no exceptions will - // be thrown for them. DISABLE_EXCEPTIONS; values_.clear(); values_.reserve(x.size()); diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index 217724b2..54b25db5 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -138,8 +138,7 @@ namespace test }; template - typename equals_to_compare::type create_compare( - Equals const& equals) + typename equals_to_compare::type create_compare(Equals const&) { typename equals_to_compare::type x; return x; diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index fe7e31a6..7b3911f6 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -17,12 +17,6 @@ #include #include "../helpers/fwd.hpp" -// TODO: -// a) This can only be included in compile unit. -// b) This stuff should be somewhere else. -// but I'm feeling too lazy right now (although sadly not lazy enough to -// avoid reinventing yet another wheel). - #define RUN_EXCEPTION_TESTS(test_seq, param_seq) \ BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, (test_seq)(param_seq)) @@ -213,6 +207,11 @@ namespace exception } } + ~object() { + tag1_ = -1; + tag2_ = -1; + } + object& operator=(object const& x) { SCOPE(object::operator=(object)) { @@ -346,7 +345,7 @@ namespace exception return *this; } - std::size_t operator()(object const& x1, object const& x2) const { + bool operator()(object const& x1, object const& x2) const { SCOPE(equal_to::operator()(object, object)) { EPOINT("Mock equal_to function."); } @@ -376,10 +375,6 @@ namespace exception } }; - // TODO: Need to track that same allocator is used to allocate, construct, - // deconstruct and destroy objects. Also, need to check that constructed - // objects are deconstructed (Boost.Test should take care of memory leaks - // for us). template class allocator { @@ -394,14 +389,14 @@ namespace exception template struct rebind { typedef allocator other; }; - explicit allocator(int t = 0) + explicit allocator(int = 0) { SCOPE(allocator::allocator()) { EPOINT("Mock allocator default constructor."); } } - template allocator(allocator const& x) + template allocator(allocator const&) { SCOPE(allocator::allocator()) { EPOINT("Mock allocator template copy constructor."); @@ -424,8 +419,11 @@ namespace exception return *this; } + // If address throws, then it can't be used in erase or the + // destructor, which is very limiting. I need to check up on + // this. + pointer address(reference r) { - // TODO: Is this no throw? Major problems if it isn't. //SCOPE(allocator::address(reference)) { // EPOINT("Mock allocator address function."); //} @@ -433,7 +431,6 @@ namespace exception } const_pointer address(const_reference r) { - // TODO: Is this no throw? Major problems if it isn't. //SCOPE(allocator::address(const_reference)) { // EPOINT("Mock allocator const address function."); //} @@ -469,7 +466,7 @@ namespace exception //return pointer(static_cast(::operator new(n * sizeof(T)))); } - void deallocate(pointer p, size_type n) + void deallocate(pointer p, size_type) { //::operator delete((void*) p); if(p) { @@ -495,13 +492,12 @@ namespace exception } }; + // It's pretty much impossible to write a compliant swap when these + // two can throw. So they don't. + template - inline bool operator==(allocator const& x, allocator const& y) + inline bool operator==(allocator const&, allocator const&) { - // TODO: I can't meet the exception requirements for swap if this - // throws. Does the standard specify that allocator comparisons can't - // throw? - // //SCOPE(operator==(allocator, allocator)) { // EPOINT("Mock allocator equality operator."); //} diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 587b81fe..ee1d7aa2 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -47,19 +47,12 @@ namespace minimal { public: static hash create() { return hash(); } - // TODO: hash has to be default constructible for the default - // parameters. Maybe use an alternative version for testing - // other member functions. - // - // Or maybe it's required to be default constructible? - // The Container requirements include a default constructor. hash() {} hash(hash const&) {} - // TODO: Required to be assignable? hash& operator=(hash const&) { return *this; } ~hash() {} - std::size_t operator()(T const& x) const { return 0; } + std::size_t operator()(T const&) const { return 0; } }; template @@ -67,15 +60,8 @@ namespace minimal { public: static equal_to create() { return equal_to(); } - // TODO: equal_to has to be default constructible for the default - // parameters. Maybe use an alternative version for testing - // other member functions. - // - // Or maybe it's required to be default constructible? - // The Container requirements include a default constructor. equal_to() {} equal_to(equal_to const&) {} - // TODO: Required to be assignable? equal_to& operator=(equal_to const&) { return *this; } ~equal_to() {} @@ -173,9 +159,6 @@ namespace minimal bool operator>=(const_pointer const& x) const { return ptr_ >= x.ptr_; } }; - // TODO: Issue 560 suggests that an allocator doesn't have to have - // a default constructor. - // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#560 template class allocator { @@ -207,7 +190,7 @@ namespace minimal return pointer(static_cast(::operator new(n * sizeof(T)))); } - void deallocate(pointer p, size_type n) + void deallocate(pointer p, size_type) { ::operator delete((void*) p.ptr_); } @@ -225,19 +208,19 @@ namespace minimal }; template - inline bool operator==(allocator const& x, allocator const& y) + inline bool operator==(allocator const&, allocator const&) { return true; } template - inline bool operator!=(allocator const& x, allocator const& y) + inline bool operator!=(allocator const&, allocator const&) { return false; } template - void swap(allocator& x, allocator& y) + void swap(allocator&, allocator&) { } } diff --git a/test/objects/test.hpp b/test/objects/test.hpp index ba61a68c..9f4702c0 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -32,6 +32,11 @@ namespace test public: explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {} + ~object() { + tag1_ = -1; + tag2_ = -1; + } + friend bool operator==(object const& x1, object const& x2) { return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_; } @@ -222,7 +227,7 @@ namespace test void track_allocate(void *ptr, std::size_t n, std::size_t size, int tag) { if(n == 0) { - // TODO: This is unspecified - not undefined, so what to do? + BOOST_ERROR("Allocating 0 length array."); } else { ++count_allocations; @@ -238,7 +243,6 @@ namespace test if(pos == allocated_memory.end()) { BOOST_ERROR("Deallocating unknown pointer."); } else { - // TODO: Not exception safe. BOOST_TEST(pos->first.start == ptr); BOOST_TEST(pos->first.end == (char*) ptr + n * size); BOOST_TEST(pos->second.tag_ == tag); @@ -249,21 +253,18 @@ namespace test if(count_allocations > 0) --count_allocations; } - void track_construct(void* ptr, std::size_t size, int tag) + void track_construct(void* ptr, std::size_t /*size*/, int tag) { std::map::iterator pos = allocated_memory.find(memory_area(ptr, ptr)); if(pos == allocated_memory.end()) BOOST_ERROR("Constructing unknown pointer."); BOOST_TEST(pos->second.tag_ == tag); - //TODO: Track the number of allocations, and make sure the number - // of constructions doesn't exceed it. If you're feeling keen, - // perhaps track the individual objects in the array. ++count_constructions; ++pos->second.constructed_; } - void track_destroy(void* ptr, std::size_t size, int tag) + void track_destroy(void* ptr, std::size_t /*size*/, int tag) { std::map::iterator pos = allocated_memory.find(memory_area(ptr, ptr)); @@ -302,7 +303,6 @@ namespace test allocator(allocator const& x) : tag_(x.tag_) { detail::allocator_ref(); } ~allocator() { detail::allocator_unref(); } - // TODO: Shall I check these? pointer address(reference r) { return pointer(&r); } const_pointer address(const_reference r) { return const_pointer(&r); } diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 68d54582..ffa20a42 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -19,6 +19,7 @@ test-suite unordered-tests [ run assign_tests.cpp ] [ run insert_tests.cpp ] [ run erase_tests.cpp ] + [ run erase_equiv_tests.cpp ] [ run find_tests.cpp ] [ run bucket_tests.cpp ] [ run load_factor_tests.cpp ] diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 434e1c3e..ca36910a 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -61,7 +61,6 @@ void assign_tests2(T* = 0) 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); @@ -73,7 +72,6 @@ void assign_tests2(T* = 0) std::cerr<<"assign_tests2.2\n"; { - // TODO: Need to generate duplicates... test::random_values v1(100), v2(100); T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1); T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2); diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 48d7be23..2fb27911 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -11,6 +11,7 @@ #include "../helpers/tracker.hpp" #include "../helpers/equivalent.hpp" #include "../helpers/input_iterator.hpp" +#include "../helpers/invariants.hpp" #include @@ -29,6 +30,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf)); BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 2\n"; @@ -39,6 +41,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf)); BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 3\n"; @@ -49,6 +52,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf)); BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 4\n"; @@ -58,6 +62,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf)); BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 5\n"; @@ -69,6 +74,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } std::cerr<<"Construct 6\n"; @@ -80,6 +86,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } std::cerr<<"Construct 7\n"; @@ -91,6 +98,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } std::cerr<<"Construct 8\n"; @@ -101,6 +109,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } std::cerr<<"Construct 9\n"; @@ -111,6 +120,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf)); BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 10\n"; @@ -122,6 +132,7 @@ void constructor_tests1(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } } @@ -145,6 +156,7 @@ void constructor_tests2(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf1)); BOOST_TEST(test::equivalent(x.key_eq(), eq1)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 2\n"; @@ -155,6 +167,7 @@ void constructor_tests2(T* = 0) BOOST_TEST(test::equivalent(x.hash_function(), hf1)); BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); } std::cerr<<"Construct 3\n"; @@ -165,6 +178,7 @@ void constructor_tests2(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq1)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } std::cerr<<"Construct 4\n"; @@ -176,6 +190,7 @@ void constructor_tests2(T* = 0) BOOST_TEST(test::equivalent(x.key_eq(), eq)); BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); + test::check_equivalent_keys(x); } @@ -186,6 +201,8 @@ void constructor_tests2(T* = 0) T y(x.begin(), x.end(), 0, hf1, eq1, al2); test::check_container(x, v); test::check_container(y, x); + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); } std::cerr<<"Construct 6\n"; @@ -195,6 +212,8 @@ void constructor_tests2(T* = 0) T y(x.begin(), x.end(), 0, hf, eq); test::check_container(x, v); test::check_container(y, x); + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); } std::cerr<<"Construct 7\n"; @@ -204,6 +223,8 @@ void constructor_tests2(T* = 0) T y(x.begin(), x.end(), 0, hf2, eq2); test::check_container(x, v); test::check_container(y, x); + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); } std::cerr<<"Construct 8 - from input iterator\n"; @@ -213,9 +234,26 @@ void constructor_tests2(T* = 0) T y(test::input_iterator(x.begin()), test::input_iterator(x.end()), 0, hf2, eq2); test::check_container(x, v); test::check_container(y, x); + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); } } +template +void map_constructor_test(T* = 0) +{ + std::cerr<<"map_constructor_test\n"; + + typedef std::list > list; + test::random_values v(1000); + list l(v.begin(), v.end()); + + T x(l.begin(), l.end()); + + test::check_container(x, v); + test::check_equivalent_keys(x); +} + int main() { std::cerr<<"Test1 unordered_set\n"; @@ -245,5 +283,10 @@ int main() std::cerr<<"Test2 unordered_multimap\n"; constructor_tests2((boost::unordered_multimap >*) 0); + std::cerr<<"Map Test unordered_map\n"; + map_constructor_test((boost::unordered_map >*) 0); + std::cerr<<"Map Test unordered_multimap\n"; + map_constructor_test((boost::unordered_multimap >*) 0); + return boost::report_errors(); } diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index 6111c3ba..2a0671f4 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -67,7 +67,6 @@ void copy_construct_tests2(T* ptr = 0) typename T::allocator_type al(1); { - // TODO: I could check how many buckets y has, it should be lower (QOI issue). T x(10000, hf, eq, al); T y(x); BOOST_TEST(y.empty()); @@ -79,7 +78,6 @@ void copy_construct_tests2(T* ptr = 0) } { - // TODO: Invariant checks are especially important here. test::random_values v(1000); T x(v.begin(), v.end(), 0, hf, eq, al); diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp new file mode 100644 index 00000000..780ffae4 --- /dev/null +++ b/test/unordered/erase_equiv_tests.cpp @@ -0,0 +1,195 @@ + +// Copyright 2006 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The code for erasing elements from containers with equivalent keys is very +// hairy with several tricky edge cases - so explicitly test each one. + +#include +#include +#include +#include +#include +#include +#include +#include "../objects/test.hpp" + +struct write_pair_type +{ + template + void operator()(std::pair const& x) const + { + std::cout<<"("< +void write_container(Container const& x) +{ + std::for_each(x.begin(), x.end(), write_pair); + std::cout<<"\n"; +} + +// Make everything collide - for testing erase in a single bucket. +struct collision_hash +{ + int operator()(int) const { return 0; } +}; + +// For testing erase in 2 buckets. +struct collision2_hash +{ + int operator()(int x) const { return x & 1; } +}; + +typedef boost::unordered_multimap, + test::allocator > > collide_map; +typedef boost::unordered_multimap, + test::allocator > > collide_map2; +typedef collide_map::value_type pair; +typedef std::list list; + + +void empty_range_tests() +{ + collide_map x; + x.erase(x.begin(), x.end()); + x.erase(x.begin(), x.begin()); + x.erase(x.end(), x.end()); +} + +void single_item_tests() +{ + list init; + init.push_back(pair(1,1)); + + collide_map x(init.begin(), init.end()); + x.erase(x.begin(), x.begin()); + BOOST_TEST(x.count(1) == 1 && x.size() == 1); + x.erase(x.end(), x.end()); + BOOST_TEST(x.count(1) == 1 && x.size() == 1); + x.erase(x.begin(), x.end()); + BOOST_TEST(x.count(1) == 0 && x.size() == 0); +} + +void two_equivalent_item_tests() +{ + list init; + init.push_back(pair(1,1)); + init.push_back(pair(1,2)); + + { + collide_map x(init.begin(), init.end()); + x.erase(x.begin(), x.end()); + BOOST_TEST(x.count(1) == 0 && x.size() == 0); + } + + { + collide_map x(init.begin(), init.end()); + int value = boost::next(x.begin())->second; + x.erase(x.begin(), boost::next(x.begin())); + BOOST_TEST(x.count(1) == 1 && x.size() == 1 && + x.begin()->first == 1 && x.begin()->second == value); + } + + { + collide_map x(init.begin(), init.end()); + int value = x.begin()->second; + x.erase(boost::next(x.begin()), x.end()); + BOOST_TEST(x.count(1) == 1 && x.size() == 1 && + x.begin()->first == 1 && x.begin()->second == value); + } +} + +// At this point I got bored and wrote more automated tests... + +template +bool compare(Range1 const& x, Range2 const& y) +{ + list a(x.begin(), x.end()); + list b(y.begin(), y.end()); + a.sort(); + b.sort(); + return a == b; +} + +template +bool general_erase_range_test(Container& x, int start, int end) +{ + list l(x.begin(), x.end()); + l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end)); + x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end)); + return compare(l, x); +} + +template +void erase_subrange_tests(Container const& x) +{ + for(std::size_t length = 0; length < x.size(); ++length) { + for(std::size_t position = 0; position < x.size() - length; ++position) { + Container y(x); + list init(y.begin(), y.end()); + if(!general_erase_range_test(y, position, position + length)) { + BOOST_ERROR("general_erase_range_test failed."); + std::cout<<"Erase: ["< +void x_by_y_erase_range_tests(Container*, int values, int duplicates) +{ + Container y; + + for(int i = 0; i < values; ++i) { + for(int j = 0; j < duplicates; ++j) { + y.insert(pair(i, j)); + } + } + + std::cout<<"Values: "< +void exhaustive_erase_tests(Container* x, int num_values, + int num_duplicated) +{ + for(int i = 0; i < num_values; ++i) { + for(int j = 0; j < num_duplicated; ++j) { + x_by_y_erase_range_tests(x, i, j); + } + } +} + +void exhaustive_collide_tests() +{ + std::cout<<"exhaustive_collide_tests:\n"; + collide_map m; + exhaustive_erase_tests((collide_map*) 0, 4, 4); + std::cout<<"\n"; +} + +void exhaustive_collide2_tests() +{ + std::cout<<"exhaustive_collide2_tests:\n"; + exhaustive_erase_tests((collide_map2*) 0, 8, 4); + std::cout<<"\n"; +} + +int main() +{ + empty_range_tests(); + single_item_tests(); + two_equivalent_item_tests(); + exhaustive_collide_tests(); + exhaustive_collide2_tests(); + + return boost::report_errors(); +} diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index d6cb1408..274471f9 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -105,8 +105,6 @@ void erase_tests1(Container* = 0) BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin()); } - // TODO: More range erase tests. - std::cerr<<"clear().\n"; { test::random_values v(500); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index c3664d34..687866b8 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -196,8 +196,8 @@ void insert_tests2(X* = 0) test::random_values v(1000); x.insert(v.begin(), v.end()); - test::check_container(x, v); + test::check_container(x, v); test::check_equivalent_keys(x); } @@ -218,6 +218,8 @@ void insert_tests2(X* = 0) template void map_tests(X* = 0) { + std::cerr<<"map tests.\n"; + X x; test::ordered tracker = test::create_ordered(x); @@ -240,6 +242,20 @@ void map_tests(X* = 0) test::check_equivalent_keys(x); } +template +void associative_insert_range_test(X* = 0) +{ + std::cerr<<"associative_insert_range_test\n"; + + typedef std::list > list; + test::random_values v(1000); + list l(v.begin(), v.end()); + + X x; x.insert(l.begin(), l.end()); + + test::check_equivalent_keys(x); +} + int main() { unique_insert_tests1((boost::unordered_set*) 0); @@ -265,5 +281,8 @@ int main() map_tests((boost::unordered_map*) 0); map_tests((boost::unordered_map >*) 0); + associative_insert_range_test((boost::unordered_map >*) 0); + associative_insert_range_test((boost::unordered_multimap >*) 0); + return boost::report_errors(); }