thin-provisioning-tools/unit-tests/sequence_generator_t.cc
2020-07-29 16:18:23 +08:00

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
}
//----------------------------------------------------------------