From 161a8500884d3bcae1630c945388b4517f3d5b24 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 13 Aug 2023 13:30:17 -0300 Subject: [PATCH] Some more tests over cache cursor operations --- CHANGELOG.md | 9 ++ test/CMakeLists.txt | 1 + test/basic.cpp | 15 ++ test/cachecursor.cpp | 326 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 351 insertions(+) create mode 100644 test/cachecursor.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index a0c3db7..cf30d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## LMDBAL 0.4.0 (August 13, 2023) +### Bug fixes +- possible cache unsync + +### Improvements +- read only cursors +- some more documentation +- more tests + ## LMDBAL 0.3.1 (April 14, 2023) ### Bug fixes - build with qt5 now is possible again diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8e51951..b2b1eba 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable(runUnitTests storagetransaction.cpp cachetransaction.cpp storagecursor.cpp + cachecursor.cpp ) target_compile_options(runUnitTests PRIVATE -fPIC) diff --git a/test/basic.cpp b/test/basic.cpp index 143e2c7..7369de6 100644 --- a/test/basic.cpp +++ b/test/basic.cpp @@ -106,6 +106,10 @@ TEST_F(BaseTest, GettingNotExistingKeys) { TEST_F(BaseTest, Persistence) { EXPECT_EQ(db->ready(), true); + uint32_t t1Size = t1->count(); + uint32_t t2Size = t2->count(); + uint32_t c1Size = c1->count(); + db->close(); delete db; @@ -115,20 +119,31 @@ TEST_F(BaseTest, Persistence) { c1 = db->addCache("cache1"); db->open(); + EXPECT_EQ(t1->count(), t1Size); EXPECT_EQ(t1->getRecord(3), 15); EXPECT_EQ(t1->getRecord(1), 2); EXPECT_EQ(t1->getRecord(2), 2); + EXPECT_EQ(t1->count(), t1Size); + + EXPECT_EQ(t2->count(), t2Size); EXPECT_EQ(t2->getRecord("hello"), "world"); EXPECT_EQ(t2->getRecord("aaa"), "gagdfsdf"); EXPECT_EQ(t2->getRecord("sdfhga"), "DSFFDG"); EXPECT_EQ(t2->getRecord("sdfsda"), "shgsdgfa"); + EXPECT_EQ(t2->count(), t2Size); + EXPECT_EQ(c1->count(), c1Size); + EXPECT_EQ(c1->checkRecord(-116), true); EXPECT_EQ(c1->getRecord(-116), "whatever"); + EXPECT_EQ(c1->checkRecord(-4), true); EXPECT_EQ(c1->getRecord(-4), "testing goes brrr"); EXPECT_EQ(c1->getRecord(-4), "testing goes brrr"); + EXPECT_EQ(c1->checkRecord(-4), true); + EXPECT_EQ(c1->count(), c1Size); EXPECT_EQ(c1->getRecord(-37), "aaaaa tss tsss tsss tsss aaaaaaa"); EXPECT_EQ(c1->getRecord(2), "blah balah"); + EXPECT_EQ(c1->count(), c1Size); EXPECT_THROW(t2->getRecord("cats"), LMDBAL::NotFound); EXPECT_THROW(t1->getRecord(7893), LMDBAL::NotFound); diff --git a/test/cachecursor.cpp b/test/cachecursor.cpp new file mode 100644 index 0000000..d1afa3e --- /dev/null +++ b/test/cachecursor.cpp @@ -0,0 +1,326 @@ +#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(); + } + } + + static void TearDownTestSuite() { + db->close(); + db->removeDirectory(); + delete db; + db = nullptr; + cursor = nullptr; + emptyCursor = nullptr; + } + + static LMDBAL::Base* db; + static LMDBAL::Cursor* cursor; + static LMDBAL::Cursor* emptyCursor; + static LMDBAL::TransactionID transaction; + + LMDBAL::Cache* cache; + LMDBAL::Cache* emptyCache; +}; + +LMDBAL::Base* CacheCursorTest::db = nullptr; +LMDBAL::Cursor* CacheCursorTest::cursor = nullptr; +LMDBAL::Cursor* CacheCursorTest::emptyCursor = nullptr; +LMDBAL::TransactionID CacheCursorTest::transaction = nullptr; + +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) { + cursor = cache->createCursor(); + emptyCursor = emptyCache->createCursor(); + + 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(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) { + 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(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) { + 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) { + 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, Destruction) { + cursor->close(); + + 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); + + EXPECT_THROW(emptyCache->destroyCursor(cursor), LMDBAL::Unknown); + cache->destroyCursor(cursor); + + cursor = cache->createCursor(); +} + +TEST_F(CacheCursorTest, FirstPublic) { + 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) { + 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) { + 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) { + 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) { + 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, CornerCases) { + db->abortTransaction(transaction); + EXPECT_THROW(cursor->current(), LMDBAL::Unknown); + cursor->close(); + + 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); +} +