mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-30 19:37:14 +02:00
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:
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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)")
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace test
|
||||
{
|
||||
// TODO: Make this a stricter input iterator.
|
||||
template <class Iterator>
|
||||
struct input_iterator_adaptor
|
||||
: boost::iterator_adaptor<
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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.");
|
||||
//}
|
||||
|
@ -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>&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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 ]
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
195
test/unordered/erase_equiv_tests.cpp
Normal file
195
test/unordered/erase_equiv_tests.cpp
Normal 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();
|
||||
}
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user