209 lines
5.0 KiB
C++
209 lines
5.0 KiB
C++
|
#include "gmock/gmock.h"
|
||
|
|
||
|
#include "base/sequence_generator.h"
|
||
|
|
||
|
using namespace base;
|
||
|
using namespace std;
|
||
|
using namespace testing;
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
namespace {
|
||
|
class SequenceGeneratorTests : public Test {
|
||
|
};
|
||
|
|
||
|
class ForwardSequenceGeneratorTests : public Test {
|
||
|
public:
|
||
|
ForwardSequenceGeneratorTests() {
|
||
|
}
|
||
|
|
||
|
void reset(uint64_t begin, uint64_t size, uint64_t step) {
|
||
|
gen_ = create_forward_sequence_generator(
|
||
|
begin, size, step);
|
||
|
|
||
|
// the maximum value is expected to be less than
|
||
|
// (begin + round_down(size, step))
|
||
|
begin_ = begin;
|
||
|
end_ = begin + (size / step) * step;
|
||
|
step_ = step;
|
||
|
}
|
||
|
|
||
|
void test_full_sequence() {
|
||
|
for (uint64_t i = begin_; i < end_; i += step_)
|
||
|
ASSERT_EQ(i, gen_->next());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
sequence_generator::ptr gen_;
|
||
|
uint64_t begin_;
|
||
|
uint64_t end_;
|
||
|
uint64_t step_;
|
||
|
};
|
||
|
|
||
|
class RandomSequenceGeneratorTests : public Test {
|
||
|
struct span_tracker {
|
||
|
span_tracker(uint64_t begin, uint64_t step)
|
||
|
: last_(begin),
|
||
|
step_(step),
|
||
|
len_(1),
|
||
|
max_len_(1) {
|
||
|
}
|
||
|
|
||
|
void append(uint64_t n) {
|
||
|
if (n == last_ + step_)
|
||
|
++len_;
|
||
|
else
|
||
|
len_ = 1;
|
||
|
|
||
|
if (len_ > max_len_)
|
||
|
max_len_ = len_;
|
||
|
|
||
|
last_ = n;
|
||
|
}
|
||
|
|
||
|
uint64_t last_;
|
||
|
uint64_t step_;
|
||
|
unsigned len_;
|
||
|
unsigned max_len_;
|
||
|
};
|
||
|
|
||
|
public:
|
||
|
RandomSequenceGeneratorTests() {
|
||
|
}
|
||
|
|
||
|
void reset(uint64_t begin, uint64_t size, uint64_t step,
|
||
|
unsigned seq_nr = 1) {
|
||
|
gen_ = create_random_sequence_generator(
|
||
|
begin, size, step, seq_nr);
|
||
|
|
||
|
// the maximum value is expected to be less than
|
||
|
// (begin + round_down(size, step))
|
||
|
begin_ = begin;
|
||
|
nr_steps_ = size / step;
|
||
|
step_ = step;
|
||
|
seq_nr_ = seq_nr;
|
||
|
}
|
||
|
|
||
|
void test_full_sequence() {
|
||
|
std::set<uint64_t> values;
|
||
|
|
||
|
// generate the whole sequence
|
||
|
uint64_t n = gen_->next();
|
||
|
values.insert(n);
|
||
|
span_tracker tracker(n, step_);
|
||
|
|
||
|
for (uint64_t i = 1; i < nr_steps_; i++) {
|
||
|
n = gen_->next();
|
||
|
values.insert(n);
|
||
|
tracker.append(n);
|
||
|
}
|
||
|
|
||
|
// verify the generated sequence
|
||
|
ASSERT_EQ(values.size(), nr_steps_); // assert no duplicates
|
||
|
|
||
|
set<uint64_t>::const_iterator it = values.begin();
|
||
|
uint64_t end = begin_ + nr_steps_ * step_;
|
||
|
for (uint64_t v = begin_; v < end; v += step_) {
|
||
|
ASSERT_EQ(v, *it);
|
||
|
++it;
|
||
|
}
|
||
|
|
||
|
// FIXME: refine this assertion
|
||
|
// The maximum span length depends on the randomness.
|
||
|
// It should be greater than half of the desired length,
|
||
|
// if the probabilities are evenly distributed.
|
||
|
if (seq_nr_ > 1) {
|
||
|
ASSERT_TRUE(tracker.max_len_ >= seq_nr_ / 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
sequence_generator::ptr gen_;
|
||
|
uint64_t begin_;
|
||
|
uint64_t nr_steps_;
|
||
|
uint64_t step_;
|
||
|
unsigned seq_nr_;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
TEST_F(SequenceGeneratorTests, create_with_valid_params)
|
||
|
{
|
||
|
// step < size
|
||
|
create_forward_sequence_generator(0, 10, 2);
|
||
|
|
||
|
// boundary test: step == size
|
||
|
create_forward_sequence_generator(0, 10, 10);
|
||
|
|
||
|
// step < size
|
||
|
create_random_sequence_generator(0, 10, 2);
|
||
|
|
||
|
// boundary test: step == size
|
||
|
create_random_sequence_generator(0, 10, 10);
|
||
|
|
||
|
// seq_nr < nr_steps
|
||
|
create_random_sequence_generator(0, 10, 2, 2);
|
||
|
|
||
|
// boundary test: seq_nr == nr_steps
|
||
|
create_random_sequence_generator(0, 10, 2, 5);
|
||
|
}
|
||
|
|
||
|
TEST_F(SequenceGeneratorTests, create_with_invalid_params)
|
||
|
{
|
||
|
// zero size or step
|
||
|
ASSERT_THROW(create_forward_sequence_generator(0, 1, 0), std::runtime_error);
|
||
|
ASSERT_THROW(create_forward_sequence_generator(0, 0, 1), std::runtime_error);
|
||
|
|
||
|
// step > size
|
||
|
ASSERT_THROW(create_forward_sequence_generator(0, 10, 11), std::runtime_error);
|
||
|
|
||
|
// zero size, step, or seq_nr
|
||
|
ASSERT_THROW(create_random_sequence_generator(0, 1, 0), std::runtime_error);
|
||
|
ASSERT_THROW(create_random_sequence_generator(0, 0, 1), std::runtime_error);
|
||
|
ASSERT_THROW(create_random_sequence_generator(0, 1, 1, 0), std::runtime_error);
|
||
|
|
||
|
// step > size
|
||
|
ASSERT_THROW(create_random_sequence_generator(0, 10, 11), std::runtime_error);
|
||
|
|
||
|
// seq_nr > nr_steps
|
||
|
ASSERT_THROW(create_random_sequence_generator(0, 10, 2, 6), std::runtime_error);
|
||
|
}
|
||
|
|
||
|
TEST_F(ForwardSequenceGeneratorTests, forward_sequence_aligned)
|
||
|
{
|
||
|
reset(50, 100, 2); // begin & size are aligned to step
|
||
|
test_full_sequence();
|
||
|
test_full_sequence(); // wrap-around
|
||
|
}
|
||
|
|
||
|
TEST_F(ForwardSequenceGeneratorTests, forward_sequence_unaligned)
|
||
|
{
|
||
|
reset(50, 100, 7); // begin & size are not aligned to step
|
||
|
test_full_sequence();
|
||
|
test_full_sequence(); // wrap-around
|
||
|
}
|
||
|
|
||
|
TEST_F(RandomSequenceGeneratorTests, random_sequence_aligned)
|
||
|
{
|
||
|
reset(50, 100, 2); // begin & size are aligned to step
|
||
|
test_full_sequence();
|
||
|
test_full_sequence(); // wrap-around
|
||
|
}
|
||
|
|
||
|
TEST_F(RandomSequenceGeneratorTests, random_sequence_unaligned)
|
||
|
{
|
||
|
reset(50, 100, 7); // begin & size are not aligned to step
|
||
|
test_full_sequence();
|
||
|
test_full_sequence(); // wrap-around
|
||
|
}
|
||
|
|
||
|
TEST_F(RandomSequenceGeneratorTests, random_sequence_with_span)
|
||
|
{
|
||
|
reset(50, 10000, 2, 10); // begin & size are aligned to step
|
||
|
test_full_sequence();
|
||
|
test_full_sequence(); // wrap-around
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|