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]
This commit is contained in:
Daniel James
2006-10-31 22:19:26 +00:00
parent 136e2fe3ba
commit ec310f7b80
20 changed files with 316 additions and 134 deletions

View File

@ -17,7 +17,7 @@ typedef long double comparison_type;
template <class T> void sink(T const&) {}
template <class X, class T>
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;

View File

@ -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()

View File

@ -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<T>
}
};
// 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)

View File

@ -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)")

View File

@ -10,25 +10,31 @@
#include <string>
#include <utility>
#if 0
#include <stdexcept>
#include <boost/random/inversive_congruential.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/lagged_fibonacci.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#else
#include <cstdlib>
#endif
#include "./fwd.hpp"
namespace test
{
#if 0
typedef boost::hellekalek1995 integer_generator_type;
typedef boost::lagged_fibonacci607 real_generator_type;
#endif
template <class T>
struct generator;
template <class T1, class T2> std::pair<T1, T2> generate(
std::pair<T1, T2> const*)
{
static generator<T1> g1;
static generator<T2> g2;
return std::pair<T1, T2>(g1(), g2());
}
template <class T>
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<integer_generator_type, boost::uniform_int<> >
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<char> dist(32, 127);
static integer_generator_type gen;
static boost::uniform_int<char> dist(32, 127);
static boost::variate_generator<integer_generator_type, boost::uniform_int<char> >
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<float> dist;
static real_generator_type gen;
static boost::uniform_real<float> dist;
static boost::variate_generator<real_generator_type, boost::uniform_real<float> >
vg(gen, dist);
return vg();
#else
using namespace std;
return (double) rand() / (double) RAND_MAX;
#endif
}
template <class T1, class T2> std::pair<T1, T2> generate(
std::pair<T1, T2> const*)
{
static generator<T1> g1;
static generator<T2> g2;
return std::pair<T1, T2>(g1(), g2());
}
}

View File

@ -11,7 +11,6 @@
namespace test
{
// TODO: Make this a stricter input iterator.
template <class Iterator>
struct input_iterator_adaptor
: boost::iterator_adaptor<

View File

@ -49,8 +49,10 @@ namespace test
if(test::has_unique_keys<X>::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<<x1.count(key)<<","<<count<<"\n";
}
// I'm not bothering with the following test for now, as the
// previous test is probably more enough to catch the kind of

View File

@ -6,21 +6,19 @@
#if !defined(BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER
#include <vector>
#include <list>
#include <algorithm>
#include "./generators.hpp"
#include "./metafunctions.hpp"
namespace test
{
template <class X>
struct random_values
: public std::vector<typename non_const_value_type<X>::type>
: public std::list<typename X::value_type>
{
random_values(int count) {
typedef typename non_const_value_type<X>::type value_type;
typedef typename X::value_type value_type;
static test::generator<value_type> gen;
this->reserve(count);
std::generate_n(std::back_inserter(*this), count, gen);
}
};

View File

@ -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());

View File

@ -138,8 +138,7 @@ namespace test
};
template <class Equals>
typename equals_to_compare<Equals>::type create_compare(
Equals const& equals)
typename equals_to_compare<Equals>::type create_compare(Equals const&)
{
typename equals_to_compare<Equals>::type x;
return x;

View File

@ -17,12 +17,6 @@
#include <cstdlib>
#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 T>
class allocator
{
@ -394,14 +389,14 @@ namespace exception
template <class U> struct rebind { typedef allocator<U> other; };
explicit allocator(int t = 0)
explicit allocator(int = 0)
{
SCOPE(allocator::allocator()) {
EPOINT("Mock allocator default constructor.");
}
}
template <class Y> allocator(allocator<Y> const& x)
template <class Y> allocator(allocator<Y> 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<T*>(::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 <class T>
inline bool operator==(allocator<T> const& x, allocator<T> const& y)
inline bool operator==(allocator<T> const&, allocator<T> 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.");
//}

View File

@ -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 <class T>
@ -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 T>
class allocator
{
@ -207,7 +190,7 @@ namespace minimal
return pointer(static_cast<T*>(::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 <class T>
inline bool operator==(allocator<T> const& x, allocator<T> const& y)
inline bool operator==(allocator<T> const&, allocator<T> const&)
{
return true;
}
template <class T>
inline bool operator!=(allocator<T> const& x, allocator<T> const& y)
inline bool operator!=(allocator<T> const&, allocator<T> const&)
{
return false;
}
template <class T>
void swap(allocator<T>& x, allocator<T>& y)
void swap(allocator<T>&, allocator<T>&)
{
}
}

View File

@ -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<memory_area, memory_track>::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<memory_area, memory_track>::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); }

View File

@ -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 ]

View File

@ -61,7 +61,6 @@ void assign_tests2(T* = 0)
std::cerr<<"assign_tests2.1\n";
{
// TODO: Need to generate duplicates...
test::random_values<T> 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<T> v1(100), v2(100);
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);

View File

@ -11,6 +11,7 @@
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/input_iterator.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
@ -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 <class T>
void map_constructor_test(T* = 0)
{
std::cerr<<"map_constructor_test\n";
typedef std::list<std::pair<typename T::key_type, typename T::mapped_type> > list;
test::random_values<T> 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<int>\n";
@ -245,5 +283,10 @@ int main()
std::cerr<<"Test2 unordered_multimap<test::object, test::object>\n";
constructor_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Map Test unordered_map<test::object, test::object>\n";
map_constructor_test((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Map Test unordered_multimap<test::object, test::object>\n";
map_constructor_test((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
return boost::report_errors();
}

View File

@ -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<T> v(1000);
T x(v.begin(), v.end(), 0, hf, eq, al);

View File

@ -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 <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <list>
#include <set>
#include <iostream>
#include <iterator>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
struct write_pair_type
{
template <class X1, class X2>
void operator()(std::pair<X1, X2> const& x) const
{
std::cout<<"("<<x.first<<","<<x.second<<")";
}
} write_pair;
template <class Container>
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<int, int,
collision_hash, std::equal_to<int>,
test::allocator<std::pair<int const, int> > > collide_map;
typedef boost::unordered_multimap<int, int,
collision2_hash, std::equal_to<int>,
test::allocator<std::pair<int const, int> > > collide_map2;
typedef collide_map::value_type pair;
typedef std::list<pair> 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<class Range1, class Range2>
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 <class Container>
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 <class Container>
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: ["<<position<<","<<position + length<<")\n";
write_container(init);
write_container(y);
}
}
}
}
template <class Container>
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: "<<values<<", Duplicates: "<<duplicates<<"\n";
erase_subrange_tests(y);
}
template <class Container>
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();
}

View File

@ -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<Container> v(500);

View File

@ -196,8 +196,8 @@ void insert_tests2(X* = 0)
test::random_values<X> 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 <class X>
void map_tests(X* = 0)
{
std::cerr<<"map tests.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@ -240,6 +242,20 @@ void map_tests(X* = 0)
test::check_equivalent_keys(x);
}
template <class X>
void associative_insert_range_test(X* = 0)
{
std::cerr<<"associative_insert_range_test\n";
typedef std::list<std::pair<typename X::key_type, typename X::mapped_type> > list;
test::random_values<X> 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<int>*) 0);
@ -265,5 +281,8 @@ int main()
map_tests((boost::unordered_map<int, int>*) 0);
map_tests((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
associative_insert_range_test((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
associative_insert_range_test((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
return boost::report_errors();
}