#include #include "base.h" #include "storage.h" #include "cache.h" #include "cursor.h" class CacheCursorTest : public ::testing::Test { protected: CacheCursorTest(): ::testing::Test(), cache (db->getCache("table1")), emptyCache (db->getCache("empty")) {} ~CacheCursorTest() {} static void SetUpTestSuite() { if (db == nullptr) { db = new LMDBAL::Base("testBase"); db->addCache("table1"); db->addCache("empty"); db->open(); } } int getCacheCursorsSize() const { return cache->cursors.size(); } static void TearDownTestSuite() { cursor.drop(); transaction.terminate(); db->close(); db->removeDirectory(); delete db; db = nullptr; } static LMDBAL::Base* db; static LMDBAL::Cursor cursor; static LMDBAL::Transaction transaction; LMDBAL::Cache* cache; LMDBAL::Cache* emptyCache; }; LMDBAL::Base* CacheCursorTest::db = nullptr; LMDBAL::Cursor CacheCursorTest::cursor; LMDBAL::Transaction CacheCursorTest::transaction; static const std::map data({ {245665783, "bothering nerds"}, {3458, "resilent pick forefront"}, {105190, "apportunity legal bat"}, {6510, "outside"}, {7438537, "damocles plush apparently rusty"}, {19373572, "local guidence"}, {138842, "forgetting tusks prepare"}, {981874, "butchered soaking pawn"}, {19302, "tanned inmate"}, {178239, "custody speaks neurotic"}, }); TEST_F(CacheCursorTest, PopulatingTheTable) { uint32_t amount = cache->addRecords(data); EXPECT_EQ(amount, data.size()); } TEST_F(CacheCursorTest, Creation) { EXPECT_EQ(getCacheCursorsSize(), 0); cursor = cache->createCursor(); EXPECT_EQ(getCacheCursorsSize(), 1); EXPECT_THROW(cursor.first(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.last(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.next(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.prev(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.current(), LMDBAL::CursorNotReady); cursor.open(); } TEST_F(CacheCursorTest, FirstPrivate) { EXPECT_EQ(getCacheCursorsSize(), 1); EXPECT_EQ(cache->count(), data.size()); std::pair element = cursor.first(); std::map::const_iterator reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, NextPrivate) { EXPECT_EQ(getCacheCursorsSize(), 1); std::map::const_iterator reference = data.begin(); reference++; for (; reference != data.end(); ++reference) { std::pair element = cursor.next(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } EXPECT_THROW(cursor.next(), LMDBAL::NotFound); EXPECT_EQ(cache->count(), data.size()); std::pair element = cursor.first(); reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, LastPrivate) { EXPECT_EQ(getCacheCursorsSize(), 1); EXPECT_EQ(cache->count(), data.size()); std::pair element = cursor.last(); std::map::const_reverse_iterator reference = data.rbegin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, PrevPrivate) { EXPECT_EQ(getCacheCursorsSize(), 1); std::map::const_reverse_iterator reference = data.rbegin(); reference++; for (; reference != data.rend(); ++reference) { std::pair element = cursor.prev(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } EXPECT_THROW(cursor.prev(), LMDBAL::NotFound); EXPECT_EQ(cache->count(), data.size()); std::pair element = cursor.last(); reference = data.rbegin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, CurrentPrivate) { EXPECT_EQ(getCacheCursorsSize(), 1); std::pair element = cursor.first(); std::map::const_iterator reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); element = cursor.current(); EXPECT_EQ(cache->count(), data.size()); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); cursor.next(); element = cursor.current(); ++reference; EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); cursor.next(); cursor.next(); cursor.prev(); element = cursor.current(); ++reference; ++reference; --reference; EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, SettingPrivate) { EXPECT_EQ(getCacheCursorsSize(), 1); EXPECT_FALSE(cursor.set(6684)); EXPECT_EQ(cursor.current().second, "tanned inmate"); std::map::const_iterator reference = data.begin(); std::advance(reference, 5); EXPECT_TRUE(cursor.set(reference->first)); EXPECT_EQ(cursor.current().second, reference->second); ++reference; cursor.next(); EXPECT_EQ(cursor.current().second, reference->second); ++reference; cursor.next(); EXPECT_EQ(cursor.current().second, reference->second); --reference; cursor.prev(); EXPECT_EQ(cursor.current().second, reference->second); --reference; cursor.prev(); EXPECT_EQ(cursor.current().second, reference->second); --reference; cursor.prev(); EXPECT_EQ(cursor.current().second, reference->second); } TEST_F(CacheCursorTest, Destruction) { EXPECT_EQ(getCacheCursorsSize(), 1); cursor.close(); EXPECT_EQ(getCacheCursorsSize(), 1); EXPECT_THROW(cursor.first(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.last(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.next(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.prev(), LMDBAL::CursorNotReady); EXPECT_THROW(cursor.current(), LMDBAL::CursorNotReady); cursor = LMDBAL::Cursor(); EXPECT_EQ(getCacheCursorsSize(), 0); cursor = cache->createCursor(); EXPECT_EQ(getCacheCursorsSize(), 1); } TEST_F(CacheCursorTest, FirstPublic) { EXPECT_EQ(getCacheCursorsSize(), 1); transaction = db->beginTransaction(); cursor.open(transaction); std::pair element = cursor.first(); std::map::const_iterator reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, NextPublic) { EXPECT_EQ(getCacheCursorsSize(), 1); std::map::const_iterator reference = data.begin(); reference++; for (; reference != data.end(); ++reference) { std::pair element = cursor.next(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } EXPECT_THROW(cursor.next(), LMDBAL::NotFound); EXPECT_EQ(cache->count(), data.size()); std::pair element = cursor.first(); reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); } TEST_F(CacheCursorTest, LastPublic) { EXPECT_EQ(getCacheCursorsSize(), 1); std::pair element = cursor.last(); std::map::const_reverse_iterator reference = data.rbegin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, PrevPublic) { EXPECT_EQ(getCacheCursorsSize(), 1); std::map::const_reverse_iterator reference = data.rbegin(); reference++; for (; reference != data.rend(); ++reference) { std::pair element = cursor.prev(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } EXPECT_THROW(cursor.prev(), LMDBAL::NotFound); std::pair element = cursor.last(); reference = data.rbegin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, CurrentPublic) { EXPECT_EQ(getCacheCursorsSize(), 1); std::pair element = cursor.first(); std::map::const_iterator reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); element = cursor.current(); EXPECT_EQ(cache->count(), data.size()); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); cursor.next(); element = cursor.current(); ++reference; EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); cursor.next(); cursor.next(); cursor.prev(); element = cursor.current(); ++reference; ++reference; --reference; EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_EQ(cache->count(), data.size()); } TEST_F(CacheCursorTest, SettingPublic) { EXPECT_EQ(getCacheCursorsSize(), 1); EXPECT_FALSE(cursor.set(557)); EXPECT_EQ(cursor.current().second, "resilent pick forefront"); std::map::const_iterator reference = data.begin(); std::advance(reference, 3); EXPECT_TRUE(cursor.set(reference->first)); EXPECT_EQ(cursor.current().second, reference->second); ++reference; cursor.next(); EXPECT_EQ(cursor.current().second, reference->second); ++reference; cursor.next(); EXPECT_EQ(cursor.current().second, reference->second); --reference; cursor.prev(); EXPECT_EQ(cursor.current().second, reference->second); --reference; cursor.prev(); EXPECT_EQ(cursor.current().second, reference->second); --reference; cursor.prev(); EXPECT_EQ(cursor.current().second, reference->second); } TEST_F(CacheCursorTest, CursorRAIIBehaviour) { int initialiCursorsAmount = getCacheCursorsSize(); { LMDBAL::Cursor cur = cache->createCursor(); EXPECT_EQ(initialiCursorsAmount + 1, getCacheCursorsSize()); cur.open(transaction); EXPECT_NO_THROW(cur.first()); } EXPECT_EQ(initialiCursorsAmount, getCacheCursorsSize()); LMDBAL::Cursor cur; EXPECT_EQ(initialiCursorsAmount, getCacheCursorsSize()); EXPECT_EQ(cur.empty(), true); cur = cache->createCursor(); EXPECT_EQ(cur.empty(), false); EXPECT_EQ(initialiCursorsAmount + 1, getCacheCursorsSize()); EXPECT_THROW(emptyCache->destroyCursor(cur), LMDBAL::Unknown); cache->destroyCursor(cur); EXPECT_EQ(cur.empty(), true); EXPECT_EQ(initialiCursorsAmount, getCacheCursorsSize()); cur = cache->createCursor(); EXPECT_EQ(initialiCursorsAmount + 1, getCacheCursorsSize()); EXPECT_EQ(cur.empty(), false); cur.drop(); EXPECT_EQ(cur.empty(), true); EXPECT_EQ(initialiCursorsAmount, getCacheCursorsSize()); EXPECT_NO_THROW(cur.drop()); EXPECT_THROW(cache->destroyCursor(cur), LMDBAL::Unknown); } TEST_F(CacheCursorTest, CornerCases) { transaction.terminate(); EXPECT_THROW(cursor.current(), LMDBAL::CursorNotReady); cursor.close(); LMDBAL::Cursor emptyCursor = emptyCache->createCursor(); emptyCursor.open(); EXPECT_THROW(emptyCursor.first(), LMDBAL::NotFound); EXPECT_THROW(emptyCursor.last(), LMDBAL::NotFound); EXPECT_THROW(emptyCursor.next(), LMDBAL::NotFound); EXPECT_THROW(emptyCursor.prev(), LMDBAL::NotFound); EXPECT_THROW(emptyCursor.current(), LMDBAL::Unknown); emptyCursor.close(); cursor.open(); EXPECT_THROW(cursor.current(), LMDBAL::Unknown); //yeah, nice thing to write in the doc std::map::const_reverse_iterator breference = data.rbegin(); std::pair element(cursor.prev()); EXPECT_EQ(element.first, breference->first); //nice thing to write in the doc, again! EXPECT_EQ(element.second, breference->second); element = cursor.current(); EXPECT_EQ(element.first, breference->first); EXPECT_EQ(element.second, breference->second); EXPECT_THROW(cursor.next(), LMDBAL::NotFound); cursor.close(); cursor.open(); element = cursor.next(); std::map::const_iterator reference = data.begin(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); element = cursor.current(); EXPECT_EQ(element.first, reference->first); EXPECT_EQ(element.second, reference->second); EXPECT_THROW(cursor.prev(), LMDBAL::NotFound); cursor.close(); } TEST_F(CacheCursorTest, TerminatedTransaction) { LMDBAL::Cursor cr = cache->createCursor(); { LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); cr.open(txn); EXPECT_NO_THROW(cr.first()); } EXPECT_FALSE(cr.opened()); LMDBAL::Transaction txn2; { LMDBAL::Transaction txn = db->beginReadOnlyTransaction(); EXPECT_TRUE(txn.isActive()); EXPECT_FALSE(txn2.isActive()); cr.open(txn); EXPECT_TRUE(cr.opened()); txn2 = std::move(txn); EXPECT_FALSE(txn.isActive()); EXPECT_TRUE(txn2.isActive()); EXPECT_TRUE(cr.opened()); } EXPECT_TRUE(txn2.isActive()); EXPECT_TRUE(cr.opened()); txn2.terminate(); EXPECT_FALSE(txn2.isActive()); EXPECT_FALSE(cr.opened()); }