From 1e926dc3e436cc2c83d8d4464842da7e0904bfd5 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Thu, 28 Mar 2024 00:49:15 +0300 Subject: [PATCH] add tree tests --- .gitmodules | 3 + CMakeLists.txt | 6 +- ext/testing | 1 + inc/Tree.hpp | 15 +++-- test/TestTree.cpp | 137 ++++++++++++++++++++++++++++++++++++++++++++++ test/Tests.cpp | 8 ++- 6 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 .gitmodules create mode 160000 ext/testing create mode 100644 test/TestTree.cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ee6e009 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext/testing"] + path = ext/testing + url = https://github.com/unittest-cpp/unittest-cpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d348db..04cf9b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,11 @@ cmake_minimum_required(VERSION 3.5) project(FileSystemEmulator) - set(CMAKE_CXX_STANDARD 20) +add_subdirectory(ext/testing) +target_compile_options(UnitTest++ PUBLIC -Wno-error) + file(GLOB SOURCES "src/*.cpp") file(GLOB HEADERS "inc/*.hpp") @@ -15,5 +17,5 @@ target_link_libraries(fse ${PROJECT_NAME}) file(GLOB TEST_SOURCES "./test/*.cpp") add_executable(Test${PROJECT_NAME} ${TEST_SOURCES}) -target_link_libraries(Test${PROJECT_NAME} ${PROJECT_NAME}) +target_link_libraries(Test${PROJECT_NAME} ${PROJECT_NAME} UnitTest++) add_test(NAME Test${PROJECT_NAME} COMMAND Test${PROJECT_NAME}) \ No newline at end of file diff --git a/ext/testing b/ext/testing new file mode 160000 index 0000000..10e50ad --- /dev/null +++ b/ext/testing @@ -0,0 +1 @@ +Subproject commit 10e50ad70c696002b1d5bbefd0ea04b3ea92a03b diff --git a/inc/Tree.hpp b/inc/Tree.hpp index cc0abfe..6859b7c 100644 --- a/inc/Tree.hpp +++ b/inc/Tree.hpp @@ -8,6 +8,11 @@ typedef unsigned long ui32; typedef long long i64; typedef long i32; +template +struct SelectValueOrReference { + using type = typename std::conditional::value, T, const T&>::type; +}; + template struct AvlNumericKey { @@ -21,9 +26,9 @@ struct AvlNumericKey { inline bool descentLeft(AvlNumericKey in) const { return in.val < val; } inline bool exactNode(AvlNumericKey in) const { return in.val == val; } - inline AvlNumericKey getFindKey(/**/) const { return *this; } - inline AvlNumericKey keyInRightSubtree(AvlNumericKey in) const { return in; } - inline AvlNumericKey keyInLeftSubtree(AvlNumericKey in) const { return in; } + inline const AvlNumericKey& getFindKey(/**/) const { return *this; } + inline const AvlNumericKey& keyInRightSubtree(const AvlNumericKey& in) const { return in; } + inline const AvlNumericKey& keyInLeftSubtree(const AvlNumericKey& in) const { return in; } template inline void updateTreeCacheCallBack(const NodeType&) {} @@ -31,8 +36,8 @@ struct AvlNumericKey { template class AvlTree { - typedef const Key& KeyArg; - typedef Data DataArg; + typedef SelectValueOrReference::type KeyArg; + typedef SelectValueOrReference::type DataArg; public: class Node { diff --git a/test/TestTree.cpp b/test/TestTree.cpp new file mode 100644 index 0000000..3011abf --- /dev/null +++ b/test/TestTree.cpp @@ -0,0 +1,137 @@ +#include "Tree.hpp" + +#include "UnitTest++/UnitTest++.h" + +static double randomFloat() { + return static_cast(std::rand()) / static_cast(RAND_MAX); +} + +const auto size = 10000; + +class TestClass { + ui64 val1 = 0; + +public: + TestClass() = default; + explicit TestClass(ui64 val) : val1(val) {} + [[nodiscard]] bool operator==(const TestClass& in) const { return in.val1 == val1; } + [[nodiscard]] ui64 getVal() const { return val1; } + void setVal(ui64 val) { val1 = val; } +}; + +SUITE(AvlTree) { + TEST(Simple) { + AvlTree, TestClass> tree; + + CHECK(tree.size() == 0); + CHECK(tree.getRoot() == nullptr); + + tree.insert(6, TestClass(6)); + CHECK(tree.isValid()); + CHECK(tree.size() == 1); + CHECK(tree.getRoot()->data == TestClass(6)); + + tree.remove(6); + CHECK(tree.isValid()); + CHECK(tree.size() == 0); + CHECK(tree.getRoot() == nullptr); + } + + TEST(Persistance) { + AvlTree, TestClass> tree; + + struct Item { + Item() : + data(0) {} + bool presents = false; + TestClass data; + }; + + Item buff[size]; + + for (auto i = 0; i < size; i++) { + buff[i].data.setVal(i); + } + + // random load + ui64 loadSize = 0; + while (loadSize < size / 2) { + auto idx = ui64(randomFloat() * (size - 1)); + assert(idx < size); + if (!buff[idx].presents) { + tree.insert((i64) buff[idx].data.getVal(), buff[idx].data); + loadSize++; + buff[idx].presents = true; + + CHECK(tree.isValid()); + CHECK(tree.size() == loadSize); + } + } + + for (auto& item : buff) { + if (item.presents) continue; + tree.insert((i64) item.data.getVal(), item.data); + loadSize++; + item.presents = true; + + CHECK(tree.isValid()); + CHECK(tree.size() == loadSize); + } + + CHECK(tree.size() == size); + CHECK(tree.maxNode(tree.getRoot())->data.getVal() == size - 1); + CHECK(tree.minNode(tree.getRoot())->data.getVal() == 0); + + // find + for (auto item : buff) { + auto node = tree.find((i64) item.data.getVal()); + CHECK(node); + if (!node) continue; + CHECK(node->data.getVal() == item.data.getVal()); + } + + CHECK(!tree.find(size + 1)); + CHECK(!tree.find(-1)); + + // random unload + ui64 unloadSize = 0; + while (unloadSize < size / 2) { + auto idx = ui64(randomFloat() * (size - 1)); + if (buff[idx].presents) { + + tree.remove((i64) buff[idx].data.getVal()); + + unloadSize++; + buff[idx].presents = false; + + // find + for (auto item : buff) { + if (!item.presents) continue; + auto node = tree.find((i64) item.data.getVal()); + CHECK(node); + if (!node) continue; + CHECK(node->data.getVal() == item.data.getVal()); + } + + CHECK(tree.isValid()); + CHECK(tree.size() == size - unloadSize); + } + } + + for (auto& item : buff) { + if (item.presents) { + tree.remove((i64) item.data.getVal()); + unloadSize++; + item.presents = false; + + CHECK(tree.isValid()); + CHECK(tree.size() == size - unloadSize); + } + } + + CHECK(tree.size() == 0); + CHECK(tree.getRoot() == nullptr); + CHECK(tree.maxNode(tree.getRoot()) == nullptr); + CHECK(tree.minNode(tree.getRoot()) == nullptr); + } +} \ No newline at end of file diff --git a/test/Tests.cpp b/test/Tests.cpp index a5a29a1..0345062 100644 --- a/test/Tests.cpp +++ b/test/Tests.cpp @@ -1,5 +1,6 @@ #include "Interpreter.hpp" +#include "UnitTest++/UnitTest++.h" int main() { Interpreter interpreter; @@ -11,7 +12,10 @@ int main() { interpreter.interpret("MD /A123"); interpreter.interpret("cd /A123"); interpreter.interpret("md asd"); + interpreter.interpret("md asd/asd"); + interpreter.interpret("md asd/asd/asd"); + interpreter.interpret("md asd/asd/asd/asd"); + interpreter.interpret("rd asd"); - - return 0; + return UnitTest::RunAllTests(); } \ No newline at end of file