From cb402fd14b0450964dffc2afed5765c428bffb23 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Tue, 28 Apr 2015 11:56:07 +0200 Subject: [PATCH] Added test cases for Cache --- .../caching/cache/CacheTest.cpp | 14 -- .../cache/CacheTest_MoveConstructor.cpp | 34 +++++ .../caching/cache/CacheTest_PushAndPop.cpp | 133 ++++++++++++++++++ .../cache/QueueMapTest_MoveConstructor.cpp | 49 +++---- .../caching/cache/testutils/CacheTest.cpp | 13 ++ .../caching/cache/testutils/CacheTest.h | 25 ++++ .../testutils/CopyableMovableValueType.cpp | 3 + .../testutils/CopyableMovableValueType.h | 23 +++ 8 files changed, 247 insertions(+), 47 deletions(-) delete mode 100644 test/implementations/caching/cache/CacheTest.cpp create mode 100644 test/implementations/caching/cache/CacheTest_MoveConstructor.cpp create mode 100644 test/implementations/caching/cache/CacheTest_PushAndPop.cpp create mode 100644 test/implementations/caching/cache/testutils/CacheTest.cpp create mode 100644 test/implementations/caching/cache/testutils/CacheTest.h create mode 100644 test/implementations/caching/cache/testutils/CopyableMovableValueType.cpp create mode 100644 test/implementations/caching/cache/testutils/CopyableMovableValueType.h diff --git a/test/implementations/caching/cache/CacheTest.cpp b/test/implementations/caching/cache/CacheTest.cpp deleted file mode 100644 index 2305fdf3..00000000 --- a/test/implementations/caching/cache/CacheTest.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#include "../../../../implementations/caching/cache/Cache.h" - -using ::testing::Test; - -using namespace blockstore::caching; - -class CacheTest: public Test { -public: - Cache cache; -}; - -//TODO Write test cases diff --git a/test/implementations/caching/cache/CacheTest_MoveConstructor.cpp b/test/implementations/caching/cache/CacheTest_MoveConstructor.cpp new file mode 100644 index 00000000..925ab99f --- /dev/null +++ b/test/implementations/caching/cache/CacheTest_MoveConstructor.cpp @@ -0,0 +1,34 @@ +#include +#include +#include "../../../../implementations/caching/cache/Cache.h" +#include "testutils/MinimalKeyType.h" +#include "testutils/CopyableMovableValueType.h" + +using namespace blockstore::caching; + +using ::testing::Test; +using std::unique_ptr; +using std::make_unique; + +//Test that Cache uses a move constructor for Value if possible +class CacheTest_MoveConstructor: public Test { +public: + CacheTest_MoveConstructor() { + CopyableMovableValueType::numCopyConstructorCalled = 0; + cache = make_unique>(); + } + unique_ptr> cache; +}; + +TEST_F(CacheTest_MoveConstructor, MoveIntoCache) { + cache->push(MinimalKeyType::create(0), CopyableMovableValueType(2)); + CopyableMovableValueType val = cache->pop(MinimalKeyType::create(0)).value(); + EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled); +} + +TEST_F(CacheTest_MoveConstructor, CopyIntoCache) { + CopyableMovableValueType value(2); + cache->push(MinimalKeyType::create(0), value); + CopyableMovableValueType val = cache->pop(MinimalKeyType::create(0)).value(); + EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled); +} diff --git a/test/implementations/caching/cache/CacheTest_PushAndPop.cpp b/test/implementations/caching/cache/CacheTest_PushAndPop.cpp new file mode 100644 index 00000000..6203fe1a --- /dev/null +++ b/test/implementations/caching/cache/CacheTest_PushAndPop.cpp @@ -0,0 +1,133 @@ +#include "testutils/CacheTest.h" + +#include "../../../../implementations/caching/cache/Cache.h" +#include "testutils/MinimalKeyType.h" +#include "testutils/MinimalValueType.h" + +using ::testing::Test; + +using namespace blockstore::caching; + +class CacheTest_PushAndPop: public CacheTest {}; + +TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_EmptyCache) { + EXPECT_EQ(boost::none, pop(10)); +} + +TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_NonEmptyCache) { + push(9, 10); + EXPECT_EQ(boost::none, pop(10)); +} + +TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_FullCache) { + //Add a lot of even numbered keys + for (int i = 0; i < Cache::MAX_ENTRIES; ++i) { + push(2*i, 2*i); + } + //Request an odd numbered key + EXPECT_EQ(boost::none, pop(9)); +} + +TEST_F(CacheTest_PushAndPop, OneEntry) { + push(10, 20); + EXPECT_EQ(20, pop(10).value()); +} + +TEST_F(CacheTest_PushAndPop, MultipleEntries) { + push(10, 20); + push(20, 30); + push(30, 40); + EXPECT_EQ(30, pop(20).value()); + EXPECT_EQ(20, pop(10).value()); + EXPECT_EQ(40, pop(30).value()); +} + +TEST_F(CacheTest_PushAndPop, FullCache) { + for(int i = 0; i < Cache::MAX_ENTRIES; ++i) { + push(i, 2*i); + } + for(int i = 0; i < Cache::MAX_ENTRIES; ++i) { + EXPECT_EQ(2*i, pop(i).value()); + } +} + +TEST_F(CacheTest_PushAndPop, FullCache_PushNonOrdered_PopOrdered) { + for(int i = 1; i < Cache::MAX_ENTRIES; i += 2) { + push(i, 2*i); + } + for(int i = 0; i < Cache::MAX_ENTRIES; i += 2) { + push(i, 2*i); + } + for(int i = 0; i < Cache::MAX_ENTRIES; ++i) { + EXPECT_EQ(2*i, pop(i).value()); + } +} + +TEST_F(CacheTest_PushAndPop, FullCache_PushOrdered_PopNonOrdered) { + for(int i = 0; i < Cache::MAX_ENTRIES; ++i) { + push(i, 2*i); + } + for(int i = 1; i < Cache::MAX_ENTRIES; i += 2) { + EXPECT_EQ(2*i, pop(i).value()); + } + for(int i = 0; i < Cache::MAX_ENTRIES; i += 2) { + EXPECT_EQ(2*i, pop(i).value()); + } +} + +int roundDownToEven(int number) { + if (number % 2 == 0) { + return number; + } else { + return number - 1; + } +} + +int roundDownToOdd(int number) { + if (number % 2 != 0) { + return number; + } else { + return number - 1; + } +} + +TEST_F(CacheTest_PushAndPop, FullCache_PushNonOrdered_PopNonOrdered) { + for(int i = roundDownToEven(Cache::MAX_ENTRIES - 1); i >= 0; i -= 2) { + push(i, 2*i); + } + for(int i = 1; i < Cache::MAX_ENTRIES; i += 2) { + push(i, 2*i); + } + for(int i = roundDownToOdd(Cache::MAX_ENTRIES-1); i >= 0; i -= 2) { + EXPECT_EQ(2*i, pop(i).value()); + } + for(int i = 0; i < Cache::MAX_ENTRIES; i += 2) { + EXPECT_EQ(2*i, pop(i).value()); + } +} + +TEST_F(CacheTest_PushAndPop, MoreThanFullCache) { + for(int i = 0; i < Cache::MAX_ENTRIES + 2; ++i) { + push(i, 2*i); + } + //Check that the oldest two elements got deleted automatically + EXPECT_EQ(boost::none, pop(0)); + EXPECT_EQ(boost::none, pop(1)); + //Check the other elements are still there + for(int i = 2; i < Cache::MAX_ENTRIES + 2; ++i) { + EXPECT_EQ(2*i, pop(i).value()); + } +} + +TEST_F(CacheTest_PushAndPop, AfterTimeout) { + constexpr double TIMEOUT1_SEC = Cache::MAX_LIFETIME_SEC * 3/4; + constexpr double TIMEOUT2_SEC = Cache::PURGE_LIFETIME_SEC * 3/4; + static_assert(TIMEOUT1_SEC + TIMEOUT2_SEC > Cache::MAX_LIFETIME_SEC, "Ensure that our chosen timeouts push the first entry out of the cache"); + + push(10, 20); + boost::this_thread::sleep_for(boost::chrono::milliseconds(static_cast(1000 * TIMEOUT1_SEC))); + push(20, 30); + boost::this_thread::sleep_for(boost::chrono::milliseconds(static_cast(1000 * TIMEOUT2_SEC))); + EXPECT_EQ(boost::none, pop(10)); + EXPECT_EQ(30, pop(20).value()); +} diff --git a/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp b/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp index e762f3d0..c0bebd71 100644 --- a/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp +++ b/test/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp @@ -2,6 +2,7 @@ #include #include "../../../../implementations/caching/cache/QueueMap.h" #include "testutils/MinimalKeyType.h" +#include "testutils/CopyableMovableValueType.h" using namespace blockstore::caching; @@ -9,56 +10,38 @@ 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>(); + CopyableMovableValueType::numCopyConstructorCalled = 0; + map = make_unique>(); } - unique_ptr> map; + 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); + map->push(MinimalKeyType::create(0), CopyableMovableValueType(2)); + CopyableMovableValueType val = map->pop().value(); + EXPECT_EQ(0, CopyableMovableValueType::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); + map->push(MinimalKeyType::create(0), CopyableMovableValueType(2)); + CopyableMovableValueType val = map->pop(MinimalKeyType::create(0)).value(); + EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled); } TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_CopyIntoMap) { - CopyableValueType value(2); + CopyableMovableValueType value(2); map->push(MinimalKeyType::create(0), value); - CopyableValueType val = map->pop().value(); - EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled); + CopyableMovableValueType val = map->pop().value(); + EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled); } TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_CopyIntoMap) { - CopyableValueType value(2); + CopyableMovableValueType value(2); map->push(MinimalKeyType::create(0), value); - CopyableValueType val = map->pop(MinimalKeyType::create(0)).value(); - EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled); + CopyableMovableValueType val = map->pop(MinimalKeyType::create(0)).value(); + EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled); } diff --git a/test/implementations/caching/cache/testutils/CacheTest.cpp b/test/implementations/caching/cache/testutils/CacheTest.cpp new file mode 100644 index 00000000..b93bbccb --- /dev/null +++ b/test/implementations/caching/cache/testutils/CacheTest.cpp @@ -0,0 +1,13 @@ +#include "CacheTest.h" + +void CacheTest::push(int key, int value) { + return _cache.push(MinimalKeyType::create(key), MinimalValueType::create(value)); +} + +boost::optional CacheTest::pop(int key) { + boost::optional entry = _cache.pop(MinimalKeyType::create(key)); + if (!entry) { + return boost::none; + } + return entry->value(); +} diff --git a/test/implementations/caching/cache/testutils/CacheTest.h b/test/implementations/caching/cache/testutils/CacheTest.h new file mode 100644 index 00000000..61769936 --- /dev/null +++ b/test/implementations/caching/cache/testutils/CacheTest.h @@ -0,0 +1,25 @@ +#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 "../../../../../implementations/caching/cache/Cache.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 CacheTest: public ::testing::Test { +public: + void push(int key, int value); + boost::optional pop(int key); + + using Cache = blockstore::caching::Cache; + +private: + Cache _cache; +}; + +#endif diff --git a/test/implementations/caching/cache/testutils/CopyableMovableValueType.cpp b/test/implementations/caching/cache/testutils/CopyableMovableValueType.cpp new file mode 100644 index 00000000..cf23bd88 --- /dev/null +++ b/test/implementations/caching/cache/testutils/CopyableMovableValueType.cpp @@ -0,0 +1,3 @@ +#include "CopyableMovableValueType.h" + +int CopyableMovableValueType::numCopyConstructorCalled = 0; diff --git a/test/implementations/caching/cache/testutils/CopyableMovableValueType.h b/test/implementations/caching/cache/testutils/CopyableMovableValueType.h new file mode 100644 index 00000000..c3201423 --- /dev/null +++ b/test/implementations/caching/cache/testutils/CopyableMovableValueType.h @@ -0,0 +1,23 @@ +#pragma once +#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_COPYABLEMOVABLEVALUETYPE_H_ +#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_COPYABLEMOVABLEVALUETYPE_H_ + +class CopyableMovableValueType { +public: + static int numCopyConstructorCalled; + CopyableMovableValueType(int value): _value(value) {} + CopyableMovableValueType(const CopyableMovableValueType &rhs): CopyableMovableValueType(rhs._value) { + ++numCopyConstructorCalled; + } + CopyableMovableValueType(CopyableMovableValueType &&rhs): CopyableMovableValueType(rhs._value) { + //Don't increase numCopyConstructorCalled + } + int value() const { + return _value; + } +private: + int _value; +}; + + +#endif