diff --git a/test/implementations/caching/cache/QueueMapTest.cpp b/test/implementations/caching/cache/QueueMapTest.cpp deleted file mode 100644 index 1ba2c368..00000000 --- a/test/implementations/caching/cache/QueueMapTest.cpp +++ /dev/null @@ -1,513 +0,0 @@ -#include -#include -#include "../../../../implementations/caching/cache/QueueMap.h" -#include -#include - -using ::testing::Test; -using std::unique_ptr; -using std::make_unique; - -using namespace blockstore::caching; - -// This is a not-default-constructible Key type -class MinimalKeyType { -public: - static int instances; - static MinimalKeyType create(int value) { - return MinimalKeyType(value); - } - bool operator==(const MinimalKeyType &rhs) const { - return _value == rhs._value; - } - int value() const { - return _value; - } - MinimalKeyType(const MinimalKeyType &rhs): MinimalKeyType(rhs.value()) { - } - ~MinimalKeyType() { - --instances; - } -private: - MinimalKeyType(int value): _value(value) { - ++instances; - } - int _value; -}; -int MinimalKeyType::instances = 0; -namespace std { -template <> struct hash { - size_t operator()(const MinimalKeyType &obj) const { - return obj.value(); - } -}; -} -// This is a not-default-constructible non-copyable but moveable Value type -class MinimalValueType { -public: - static int instances; - static MinimalValueType create(int value) { - return MinimalValueType(value); - } - MinimalValueType(MinimalValueType &&rhs): MinimalValueType(rhs.value()) { - rhs._isMoved = true; - } - ~MinimalValueType() { - assert(!_isDestructed); - --instances; - _isDestructed = true; - } - int value() const { - assert(!_isMoved && !_isDestructed); - return _value; - } -private: - MinimalValueType(int value): _value(value), _isMoved(false), _isDestructed(false) { - ++instances; - } - int _value; - bool _isMoved; - bool _isDestructed; - DISALLOW_COPY_AND_ASSIGN(MinimalValueType); -}; -int MinimalValueType::instances = 0; - -class QueueMapTest: public Test { -public: - QueueMapTest() { - MinimalKeyType::instances = 0; - MinimalValueType::instances = 0; - _map = make_unique>(); - } - ~QueueMapTest() { - _map.reset(); - EXPECT_EQ(0, MinimalKeyType::instances); - EXPECT_EQ(0, MinimalValueType::instances); - } - void push(int key, int value) { - _map->push(MinimalKeyType::create(key), MinimalValueType::create(value)); - } - boost::optional pop() { - auto elem = _map->pop(); - if (!elem) { - return boost::none; - } - return elem.value().value(); - } - boost::optional pop(int key) { - auto elem = _map->pop(MinimalKeyType::create(key)); - if (!elem) { - return boost::none; - } - return elem.value().value(); - } - boost::optional peek() { - auto elem = _map->peek(); - if (!elem) { - return boost::none; - } - return elem.value().value(); - } - int size() { - return _map->size(); - } -private: - unique_ptr> _map; -}; - -class QueueMapSizeTest: public QueueMapTest {}; - -TEST_F(QueueMapSizeTest, Empty) { - EXPECT_EQ(0, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOne) { - push(2, 3); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_EQ(2, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingTwoAndPoppingOldest) { - push(2, 3); - push(3, 4); - pop(); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingTwoAndPoppingLast) { - push(2, 3); - push(3, 4); - pop(3); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOnePoppingOne) { - push(2, 3); - pop(); - EXPECT_EQ(0, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOnePoppingOnePerKey) { - push(2, 3); - pop(2); - EXPECT_EQ(0, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOnePoppingOnePushingOne) { - push(2, 3); - pop(); - push(3, 4); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOnePoppingOnePerKeyPushingOne) { - push(2, 3); - pop(2); - push(3, 4); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOnePoppingOnePushingSame) { - push(2, 3); - pop(); - push(2, 3); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapSizeTest, AfterPushingOnePoppingOnePerKeyPushingSame) { - push(2, 3); - pop(2); - push(2, 3); - EXPECT_EQ(1, size()); -} - -class QueueMapMemoryLeakTest: public QueueMapTest { -public: - void EXPECT_NUM_INSTANCES(int num) { - EXPECT_EQ(num, MinimalKeyType::instances); - EXPECT_EQ(num, MinimalValueType::instances); - } -}; - -TEST_F(QueueMapMemoryLeakTest, Empty) { - EXPECT_NUM_INSTANCES(0); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOne) { - push(2, 3); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_NUM_INSTANCES(2); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingTwoAndPoppingOldest) { - push(2, 3); - push(3, 4); - pop(); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingTwoAndPoppingLast) { - push(2, 3); - push(3, 4); - pop(3); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOnePoppingOne) { - push(2, 3); - pop(); - EXPECT_NUM_INSTANCES(0); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOnePoppingOnePerKey) { - push(2, 3); - pop(2); - EXPECT_NUM_INSTANCES(0); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOnePoppingOnePushingOne) { - push(2, 3); - pop(); - push(3, 4); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOnePoppingOnePerKeyPushingOne) { - push(2, 3); - pop(2); - push(3, 4); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOnePoppingOnePushingSame) { - push(2, 3); - pop(); - push(2, 3); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapMemoryLeakTest, AfterPushingOnePoppingOnePerKeyPushingSame) { - push(2, 3); - pop(2); - push(2, 3); - EXPECT_NUM_INSTANCES(1); -} - -class QueueMapValueTest: public QueueMapTest {}; - -TEST_F(QueueMapValueTest, PoppingFromEmpty) { - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, PoppingFromEmptyPerKey) { - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapValueTest, PoppingNonexistingPerKey) { - push(3, 2); - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapValueTest, PushingOne) { - push(3, 2); - EXPECT_EQ(2, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, PushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_EQ(3, pop().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, AfterPushingTwoAndPoppingLast) { - push(2, 3); - push(3, 4); - pop(3); - EXPECT_EQ(boost::none, pop(3)); - EXPECT_EQ(3, pop(2).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, AfterPushingOnePoppingOne) { - push(2, 3); - pop(); - EXPECT_EQ(boost::none, pop()); - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapValueTest, AfterPushingOnePoppingOnePerKey) { - push(2, 3); - pop(2); - EXPECT_EQ(boost::none, pop()); - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapValueTest, AfterPushingOnePoppingOnePushingOne) { - push(2, 3); - pop(); - push(3, 4); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, AfterPushingOnePoppingOnePerKeyPushingOne) { - push(2, 3); - pop(2); - push(3, 4); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, PushingSomePoppingMiddlePerKey) { - push(1, 2); - push(2, 3); - push(3, 4); - push(4, 5); - push(5, 6); - EXPECT_EQ(3, pop(2).value()); - EXPECT_EQ(5, pop(4).value()); - EXPECT_EQ(2, pop().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(6, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, PushingSomePoppingFirstPerKey) { - push(1, 2); - push(2, 3); - push(3, 4); - push(4, 5); - push(5, 6); - EXPECT_EQ(2, pop(1).value()); - EXPECT_EQ(3, pop(2).value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(5, pop().value()); - EXPECT_EQ(6, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapValueTest, PushingSomePoppingLastPerKey) { - push(1, 2); - push(2, 3); - push(3, 4); - push(4, 5); - push(5, 6); - EXPECT_EQ(6, pop(5).value()); - EXPECT_EQ(5, pop(4).value()); - EXPECT_EQ(2, pop().value()); - EXPECT_EQ(3, pop().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -//This test forces the underlying datastructure (std::map or std::unordered_map) to grow and reallocate memory. -//So it tests, that QueueMap still works after reallocating memory. -TEST_F(QueueMapValueTest, ManyValues) { - //Push 1 million entries - for (int i = 0; i < 1000000; ++i) { - push(i, 2*i); - } - //pop every other one by key - for (int i = 0; i < 1000000; i += 2) { - EXPECT_EQ(2*i, pop(i).value()); - } - //pop the rest in queue order - for (int i = 1; i < 1000000; i += 2) { - EXPECT_EQ(2*i, peek().value()); - EXPECT_EQ(2*i, pop().value()); - } - EXPECT_EQ(0, size()); - EXPECT_EQ(boost::none, pop()); - EXPECT_EQ(boost::none, peek()); -} - -TEST_F(QueueMapValueTest, PushAlreadyExistingValue) { - push(2, 3); - EXPECT_ANY_THROW( - push(2, 4); - ); -} - -class QueueMapPeekTest: public QueueMapTest {}; - -TEST_F(QueueMapPeekTest, PoppingFromEmpty) { - EXPECT_EQ(boost::none, peek()); -} - -TEST_F(QueueMapPeekTest, PushingOne) { - push(3, 2); - EXPECT_EQ(2, peek().value()); -} - -TEST_F(QueueMapPeekTest, PushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_EQ(3, peek().value()); - EXPECT_EQ(3, peek().value()); - EXPECT_EQ(3, pop().value()); - EXPECT_EQ(4, peek().value()); - EXPECT_EQ(4, peek().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(boost::none, peek()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapPeekTest, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, peek().value()); -} - -class CopyableValueType { -public: - static int numCopyConstructorCalled; - CopyableValueType(int value): _value(value) {} - CopyableValueType(const CopyableValueType &rhs): CopyableValueType(rhs._value) { - ++numCopyConstructorCalled; - } - CopyableValueType(CopyableValueType &&rhs): CopyableValueType(rhs._value) { - //Don't increase numCopyConstructorCalled - } - int value() const { - return _value; - } -private: - int _value; -}; -int CopyableValueType::numCopyConstructorCalled = 0; - -//Test that QueueMap uses a move constructor for Value if possible -class QueueMapMoveConstructorTest: public Test { -public: - QueueMapMoveConstructorTest() { - CopyableValueType::numCopyConstructorCalled = 0; - map = make_unique>(); - } - unique_ptr> map; -}; - -TEST_F(QueueMapMoveConstructorTest, PushingAndPopping_MoveIntoMap) { - map->push(MinimalKeyType::create(0), CopyableValueType(2)); - CopyableValueType val = map->pop().value(); - EXPECT_EQ(0, CopyableValueType::numCopyConstructorCalled); -} - -TEST_F(QueueMapMoveConstructorTest, PushingAndPoppingPerKey_MoveIntoMap) { - map->push(MinimalKeyType::create(0), CopyableValueType(2)); - CopyableValueType val = map->pop(MinimalKeyType::create(0)).value(); - EXPECT_EQ(0, CopyableValueType::numCopyConstructorCalled); -} - -TEST_F(QueueMapMoveConstructorTest, PushingAndPopping_CopyIntoMap) { - CopyableValueType value(2); - map->push(MinimalKeyType::create(0), value); - CopyableValueType val = map->pop().value(); - EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled); -} - -TEST_F(QueueMapMoveConstructorTest, PushingAndPoppingPerKey_CopyIntoMap) { - CopyableValueType value(2); - map->push(MinimalKeyType::create(0), value); - CopyableValueType val = map->pop(MinimalKeyType::create(0)).value(); - EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled); -} diff --git a/test/implementations/caching/cache/QueueMapTest_MemoryLeak.cpp b/test/implementations/caching/cache/QueueMapTest_MemoryLeak.cpp new file mode 100644 index 00000000..74012fc0 --- /dev/null +++ b/test/implementations/caching/cache/QueueMapTest_MemoryLeak.cpp @@ -0,0 +1,87 @@ +#include "testutils/QueueMapTest.h" + +// Tests that QueueMap calls destructors correctly. +// This is needed, because QueueMap does its own memory management. +class QueueMapTest_MemoryLeak: public QueueMapTest { +public: + void EXPECT_NUM_INSTANCES(int num) { + EXPECT_EQ(num, MinimalKeyType::instances); + EXPECT_EQ(num, MinimalValueType::instances); + } +}; + +TEST_F(QueueMapTest_MemoryLeak, Empty) { + EXPECT_NUM_INSTANCES(0); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOne) { + push(2, 3); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwo) { + push(2, 3); + push(3, 4); + EXPECT_NUM_INSTANCES(2); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwoAndPoppingOldest) { + push(2, 3); + push(3, 4); + pop(); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwoAndPoppingFirst) { + push(2, 3); + push(3, 4); + pop(2); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwoAndPoppingLast) { + push(2, 3); + push(3, 4); + pop(3); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOne) { + push(2, 3); + pop(); + EXPECT_NUM_INSTANCES(0); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePerKey) { + push(2, 3); + pop(2); + EXPECT_NUM_INSTANCES(0); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePushingOne) { + push(2, 3); + pop(); + push(3, 4); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePerKeyPushingOne) { + push(2, 3); + pop(2); + push(3, 4); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePushingSame) { + push(2, 3); + pop(); + push(2, 3); + EXPECT_NUM_INSTANCES(1); +} + +TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePerKeyPushingSame) { + push(2, 3); + pop(2); + push(2, 3); + EXPECT_NUM_INSTANCES(1); +} diff --git a/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp b/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp new file mode 100644 index 00000000..e762f3d0 --- /dev/null +++ b/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp @@ -0,0 +1,64 @@ +#include +#include +#include "../../../../implementations/caching/cache/QueueMap.h" +#include "testutils/MinimalKeyType.h" + +using namespace blockstore::caching; + +using ::testing::Test; +using std::unique_ptr; +using std::make_unique; + +class CopyableValueType { +public: + static int numCopyConstructorCalled; + CopyableValueType(int value): _value(value) {} + CopyableValueType(const CopyableValueType &rhs): CopyableValueType(rhs._value) { + ++numCopyConstructorCalled; + } + CopyableValueType(CopyableValueType &&rhs): CopyableValueType(rhs._value) { + //Don't increase numCopyConstructorCalled + } + int value() const { + return _value; + } +private: + int _value; +}; +int CopyableValueType::numCopyConstructorCalled = 0; + +//Test that QueueMap uses a move constructor for Value if possible +class QueueMapTest_MoveConstructor: public Test { +public: + QueueMapTest_MoveConstructor() { + CopyableValueType::numCopyConstructorCalled = 0; + map = make_unique>(); + } + unique_ptr> map; +}; + +TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_MoveIntoMap) { + map->push(MinimalKeyType::create(0), CopyableValueType(2)); + CopyableValueType val = map->pop().value(); + EXPECT_EQ(0, CopyableValueType::numCopyConstructorCalled); +} + +TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_MoveIntoMap) { + map->push(MinimalKeyType::create(0), CopyableValueType(2)); + CopyableValueType val = map->pop(MinimalKeyType::create(0)).value(); + EXPECT_EQ(0, CopyableValueType::numCopyConstructorCalled); +} + +TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_CopyIntoMap) { + CopyableValueType value(2); + map->push(MinimalKeyType::create(0), value); + CopyableValueType val = map->pop().value(); + EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled); +} + +TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_CopyIntoMap) { + CopyableValueType value(2); + map->push(MinimalKeyType::create(0), value); + CopyableValueType val = map->pop(MinimalKeyType::create(0)).value(); + EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled); +} diff --git a/test/implementations/caching/cache/QueueMapTest_Peek.cpp b/test/implementations/caching/cache/QueueMapTest_Peek.cpp new file mode 100644 index 00000000..ba3c7ead --- /dev/null +++ b/test/implementations/caching/cache/QueueMapTest_Peek.cpp @@ -0,0 +1,34 @@ +#include "testutils/QueueMapTest.h" +#include + +class QueueMapPeekTest: public QueueMapTest {}; + +TEST_F(QueueMapPeekTest, PoppingFromEmpty) { + EXPECT_EQ(boost::none, peek()); +} + +TEST_F(QueueMapPeekTest, PushingOne) { + push(3, 2); + EXPECT_EQ(2, peek().value()); +} + +TEST_F(QueueMapPeekTest, PushingTwo) { + push(2, 3); + push(3, 4); + EXPECT_EQ(3, peek().value()); + EXPECT_EQ(3, peek().value()); + EXPECT_EQ(3, pop().value()); + EXPECT_EQ(4, peek().value()); + EXPECT_EQ(4, peek().value()); + EXPECT_EQ(4, pop().value()); + EXPECT_EQ(boost::none, peek()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapPeekTest, AfterPushingTwoAndPoppingFirst) { + push(2, 3); + push(3, 4); + pop(2); + EXPECT_EQ(boost::none, pop(2)); + EXPECT_EQ(4, peek().value()); +} diff --git a/test/implementations/caching/cache/QueueMapTest_Size.cpp b/test/implementations/caching/cache/QueueMapTest_Size.cpp new file mode 100644 index 00000000..e4d72c9d --- /dev/null +++ b/test/implementations/caching/cache/QueueMapTest_Size.cpp @@ -0,0 +1,79 @@ +#include "testutils/QueueMapTest.h" + +class QueueMapTest_Size: public QueueMapTest {}; + +TEST_F(QueueMapTest_Size, Empty) { + EXPECT_EQ(0, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOne) { + push(2, 3); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingTwo) { + push(2, 3); + push(3, 4); + EXPECT_EQ(2, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingTwoAndPoppingOldest) { + push(2, 3); + push(3, 4); + pop(); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingTwoAndPoppingFirst) { + push(2, 3); + push(3, 4); + pop(2); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingTwoAndPoppingLast) { + push(2, 3); + push(3, 4); + pop(3); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOne) { + push(2, 3); + pop(); + EXPECT_EQ(0, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePerKey) { + push(2, 3); + pop(2); + EXPECT_EQ(0, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePushingOne) { + push(2, 3); + pop(); + push(3, 4); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePerKeyPushingOne) { + push(2, 3); + pop(2); + push(3, 4); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePushingSame) { + push(2, 3); + pop(); + push(2, 3); + EXPECT_EQ(1, size()); +} + +TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePerKeyPushingSame) { + push(2, 3); + pop(2); + push(2, 3); + EXPECT_EQ(1, size()); +} diff --git a/test/implementations/caching/cache/QueueMapTest_Values.cpp b/test/implementations/caching/cache/QueueMapTest_Values.cpp new file mode 100644 index 00000000..1acd5069 --- /dev/null +++ b/test/implementations/caching/cache/QueueMapTest_Values.cpp @@ -0,0 +1,150 @@ +#include "testutils/QueueMapTest.h" + +class QueueMapTest_Values: public QueueMapTest {}; + +TEST_F(QueueMapTest_Values, PoppingFromEmpty) { + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, PoppingFromEmptyPerKey) { + EXPECT_EQ(boost::none, pop(2)); +} + +TEST_F(QueueMapTest_Values, PoppingNonexistingPerKey) { + push(3, 2); + EXPECT_EQ(boost::none, pop(2)); +} + +TEST_F(QueueMapTest_Values, PushingOne) { + push(3, 2); + EXPECT_EQ(2, pop(3).value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, PushingTwo) { + push(2, 3); + push(3, 4); + EXPECT_EQ(3, pop().value()); + EXPECT_EQ(4, pop().value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, AfterPushingTwoAndPoppingFirst) { + push(2, 3); + push(3, 4); + pop(2); + EXPECT_EQ(boost::none, pop(2)); + EXPECT_EQ(4, pop(3).value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, AfterPushingTwoAndPoppingLast) { + push(2, 3); + push(3, 4); + pop(3); + EXPECT_EQ(boost::none, pop(3)); + EXPECT_EQ(3, pop(2).value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOne) { + push(2, 3); + pop(); + EXPECT_EQ(boost::none, pop()); + EXPECT_EQ(boost::none, pop(2)); +} + +TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOnePerKey) { + push(2, 3); + pop(2); + EXPECT_EQ(boost::none, pop()); + EXPECT_EQ(boost::none, pop(2)); +} + +TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOnePushingOne) { + push(2, 3); + pop(); + push(3, 4); + EXPECT_EQ(boost::none, pop(2)); + EXPECT_EQ(4, pop(3).value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOnePerKeyPushingOne) { + push(2, 3); + pop(2); + push(3, 4); + EXPECT_EQ(boost::none, pop(2)); + EXPECT_EQ(4, pop(3).value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, PushingSomePoppingMiddlePerKey) { + push(1, 2); + push(2, 3); + push(3, 4); + push(4, 5); + push(5, 6); + EXPECT_EQ(3, pop(2).value()); + EXPECT_EQ(5, pop(4).value()); + EXPECT_EQ(2, pop().value()); + EXPECT_EQ(4, pop().value()); + EXPECT_EQ(6, pop().value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, PushingSomePoppingFirstPerKey) { + push(1, 2); + push(2, 3); + push(3, 4); + push(4, 5); + push(5, 6); + EXPECT_EQ(2, pop(1).value()); + EXPECT_EQ(3, pop(2).value()); + EXPECT_EQ(4, pop().value()); + EXPECT_EQ(5, pop().value()); + EXPECT_EQ(6, pop().value()); + EXPECT_EQ(boost::none, pop()); +} + +TEST_F(QueueMapTest_Values, PushingSomePoppingLastPerKey) { + push(1, 2); + push(2, 3); + push(3, 4); + push(4, 5); + push(5, 6); + EXPECT_EQ(6, pop(5).value()); + EXPECT_EQ(5, pop(4).value()); + EXPECT_EQ(2, pop().value()); + EXPECT_EQ(3, pop().value()); + EXPECT_EQ(4, pop().value()); + EXPECT_EQ(boost::none, pop()); +} + +//This test forces the underlying datastructure (std::map or std::unordered_map) to grow and reallocate memory. +//So it tests, that QueueMap still works after reallocating memory. +TEST_F(QueueMapTest_Values, ManyValues) { + //Push 1 million entries + for (int i = 0; i < 1000000; ++i) { + push(i, 2*i); + } + //pop every other one by key + for (int i = 0; i < 1000000; i += 2) { + EXPECT_EQ(2*i, pop(i).value()); + } + //pop the rest in queue order + for (int i = 1; i < 1000000; i += 2) { + EXPECT_EQ(2*i, peek().value()); + EXPECT_EQ(2*i, pop().value()); + } + EXPECT_EQ(0, size()); + EXPECT_EQ(boost::none, pop()); + EXPECT_EQ(boost::none, peek()); +} + +TEST_F(QueueMapTest_Values, PushAlreadyExistingValue) { + push(2, 3); + EXPECT_ANY_THROW( + push(2, 4); + ); +} diff --git a/test/implementations/caching/cache/testutils/MinimalKeyType.cpp b/test/implementations/caching/cache/testutils/MinimalKeyType.cpp new file mode 100644 index 00000000..f6b327ff --- /dev/null +++ b/test/implementations/caching/cache/testutils/MinimalKeyType.cpp @@ -0,0 +1,3 @@ +#include "MinimalKeyType.h" + +int MinimalKeyType::instances = 0; diff --git a/test/implementations/caching/cache/testutils/MinimalKeyType.h b/test/implementations/caching/cache/testutils/MinimalKeyType.h new file mode 100644 index 00000000..9133d1f8 --- /dev/null +++ b/test/implementations/caching/cache/testutils/MinimalKeyType.h @@ -0,0 +1,47 @@ +#pragma once +#ifndef BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALKEYTYPE_H_ +#define BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALKEYTYPE_H_ + +#include + +// This is a not-default-constructible Key type +class MinimalKeyType { +public: + static int instances; + + static MinimalKeyType create(int value) { + return MinimalKeyType(value); + } + + MinimalKeyType(const MinimalKeyType &rhs): MinimalKeyType(rhs.value()) { + } + + ~MinimalKeyType() { + --instances; + } + + int value() const { + return _value; + } + +private: + MinimalKeyType(int value): _value(value) { + ++instances; + } + + int _value; +}; + +namespace std { +template <> struct hash { + size_t operator()(const MinimalKeyType &obj) const { + return obj.value(); + } +}; +} + +inline bool operator==(const MinimalKeyType &lhs, const MinimalKeyType &rhs) { + return lhs.value() == rhs.value(); +} + +#endif diff --git a/test/implementations/caching/cache/testutils/MinimalValueType.cpp b/test/implementations/caching/cache/testutils/MinimalValueType.cpp new file mode 100644 index 00000000..f5cbdbae --- /dev/null +++ b/test/implementations/caching/cache/testutils/MinimalValueType.cpp @@ -0,0 +1,3 @@ +#include "MinimalValueType.h" + +int MinimalValueType::instances = 0; diff --git a/test/implementations/caching/cache/testutils/MinimalValueType.h b/test/implementations/caching/cache/testutils/MinimalValueType.h new file mode 100644 index 00000000..9e48e43e --- /dev/null +++ b/test/implementations/caching/cache/testutils/MinimalValueType.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALVALUETYPE_H_ +#define BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALVALUETYPE_H_ + +#include +#include + +// This is a not-default-constructible non-copyable but moveable Value type +class MinimalValueType { +public: + static int instances; + + static MinimalValueType create(int value) { + return MinimalValueType(value); + } + + MinimalValueType(MinimalValueType &&rhs): MinimalValueType(rhs.value()) { + rhs._isMoved = true; + } + + ~MinimalValueType() { + assert(!_isDestructed); + --instances; + _isDestructed = true; + } + + int value() const { + assert(!_isMoved && !_isDestructed); + return _value; + } + +private: + MinimalValueType(int value): _value(value), _isMoved(false), _isDestructed(false) { + ++instances; + } + + int _value; + bool _isMoved; + bool _isDestructed; + + DISALLOW_COPY_AND_ASSIGN(MinimalValueType); +}; + +#endif diff --git a/test/implementations/caching/cache/testutils/QueueMapTest.cpp b/test/implementations/caching/cache/testutils/QueueMapTest.cpp new file mode 100644 index 00000000..f61b41a3 --- /dev/null +++ b/test/implementations/caching/cache/testutils/QueueMapTest.cpp @@ -0,0 +1,45 @@ +#include "QueueMapTest.h" + +QueueMapTest::QueueMapTest() { + MinimalKeyType::instances = 0; + MinimalValueType::instances = 0; + _map = std::make_unique>(); +} + +QueueMapTest::~QueueMapTest() { + _map.reset(); + EXPECT_EQ(0, MinimalKeyType::instances); + EXPECT_EQ(0, MinimalValueType::instances); +} + +void QueueMapTest::push(int key, int value) { + _map->push(MinimalKeyType::create(key), MinimalValueType::create(value)); +} + +boost::optional QueueMapTest::pop() { + auto elem = _map->pop(); + if (!elem) { + return boost::none; + } + return elem.value().value(); +} + +boost::optional QueueMapTest::pop(int key) { + auto elem = _map->pop(MinimalKeyType::create(key)); + if (!elem) { + return boost::none; + } + return elem.value().value(); +} + +boost::optional QueueMapTest::peek() { + auto elem = _map->peek(); + if (!elem) { + return boost::none; + } + return elem.value().value(); +} + +int QueueMapTest::size() { + return _map->size(); +} diff --git a/test/implementations/caching/cache/testutils/QueueMapTest.h b/test/implementations/caching/cache/testutils/QueueMapTest.h new file mode 100644 index 00000000..e49ad93f --- /dev/null +++ b/test/implementations/caching/cache/testutils/QueueMapTest.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_ +#define BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_ + +#include +#include +#include "../../../../../implementations/caching/cache/QueueMap.h" +#include "MinimalKeyType.h" +#include "MinimalValueType.h" +#include + +// This class is a parent class for tests on QueueMap. +// It offers functions to work with a QueueMap test object which is built using types having only the minimal type requirements. +// Furthermore, the class checks that there are no memory leaks left after destructing the QueueMap (by counting leftover instances of Keys/Values). +class QueueMapTest: public ::testing::Test { +public: + QueueMapTest(); + ~QueueMapTest(); + + void push(int key, int value); + boost::optional pop(); + boost::optional pop(int key); + boost::optional peek(); + int size(); + +private: + std::unique_ptr> _map; +}; + + + +#endif