From 047f96b54a56159ed9628803cfae0cb0cd257869 Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 16 Sep 2022 00:34:39 +0300 Subject: [PATCH] some tuning, specializations, basic testing --- CMakeLists.txt | 40 +++++++- database.cpp | 20 ++++ database.h | 22 ++-- exception.cpp | 33 ------ exception.h | 40 -------- exceptions.cpp | 12 +++ exceptions.h | 26 +++-- main.cpp | 34 ------- serializer.h | 3 + serializer_uint16.hpp | 52 ++++++++++ serializer_uint64.hpp | 51 ++++++++++ serializer_uint8.hpp | 53 ++++++++++ storage.h | 158 ----------------------------- storage.hpp | 226 ------------------------------------------ table.hpp | 20 ++++ test/CMakeLists.txt | 22 ++++ test/basic.cpp | 66 ++++++++++++ 17 files changed, 370 insertions(+), 508 deletions(-) delete mode 100644 exception.cpp delete mode 100644 exception.h delete mode 100644 main.cpp create mode 100644 serializer_uint16.hpp create mode 100644 serializer_uint64.hpp create mode 100644 serializer_uint8.hpp delete mode 100644 storage.h delete mode 100644 storage.hpp create mode 100644 test/CMakeLists.txt create mode 100644 test/basic.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1dcaa..d9702c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project(storage VERSION 0.0.1 LANGUAGES CXX) cmake_policy(SET CMP0076 NEW) cmake_policy(SET CMP0079 NEW) + +option(BUILD_STATIC "Builds library as static library" ON) +option(BUILD_TESTS "Builds tests" ON) +include(GNUInstallDirs) + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") @@ -22,14 +27,36 @@ if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif () -add_executable(storage - main.cpp - exception.cpp +set(SOURCES exceptions.cpp table.cpp database.cpp ) +set(HEADERS + database.h + exceptions.h + table.h + table.hpp + serializer.h + serializer.hpp + serializer_uint8.hpp + serializer_uint16.hpp + serializer_uint32.hpp + serializer_uint64.hpp +) + +if (BUILD_STATIC) + add_library(storage STATIC ${SOURCES}) +else () + add_library(storage SHARED ${SOURCES}) +endif() + +if (BUILD_TESTS) + add_subdirectory(test) +endif () + +set_target_properties(storage PROPERTIES PUBLIC_HEADER "${HEADERS}") target_include_directories(storage PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories(storage PRIVATE ${Qt${QT_VERSION_MAJOR}_INCLUDE_DIRS}) @@ -41,4 +68,9 @@ target_link_libraries(storage ) target_link_libraries(storage PRIVATE lmdb) -install(TARGETS storage RUNTIME DESTINATION bin) +install(TARGETS storage + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/storage + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/storage +) + diff --git a/database.cpp b/database.cpp index 2c2791a..78351a2 100644 --- a/database.cpp +++ b/database.cpp @@ -82,9 +82,29 @@ void DataBase::open() } } +bool DataBase::removeDirectory() +{ + if (opened) { + throw Opened(name, ""); + } + QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); + path += "/" + getName(); + QDir cache(path); + + if (cache.exists()) { + return cache.removeRecursively(); + } else { + return true; + } +} + QString DataBase::getName() const { return QString::fromStdString(name); } +bool DataBase::ready() const +{ + return opened; +} diff --git a/database.h b/database.h index 815ae61..9872ecb 100644 --- a/database.h +++ b/database.h @@ -39,13 +39,19 @@ public: void open(); void close(); + bool ready() const; + bool removeDirectory(); QString getName() const; template - Table* addTable(const QString& name); + Table* addTable(const std::string& name); + + template + Table* getTable(const std::string& name); public: //exceptions + class Exception; class Directory; class Closed; class Opened; @@ -64,14 +70,18 @@ private: #include "exceptions.h" template -DataBase::Table* DataBase::addTable(const QString& p_name) { - std::string nm = p_name.toStdString(); +DataBase::Table* DataBase::addTable(const std::string& p_name) { if (opened) { - throw Opened(name, nm); + throw Opened(name, p_name); } - DataBase::Table* table = new DataBase::Table(nm, this); - tables.insert(std::make_pair(nm, (_Table*)table)); + DataBase::Table* table = new DataBase::Table(p_name, this); + tables.insert(std::make_pair(p_name, (_Table*)table)); return table; } +template +DataBase::Table* DataBase::getTable(const std::string& p_name) { + return static_cast*>(tables.at(p_name)); +} + #endif // CORE_DATABASE_H diff --git a/exception.cpp b/exception.cpp deleted file mode 100644 index 3dee9b3..0000000 --- a/exception.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Squawk messenger. - * Copyright (C) 2019 Yury Gubich - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "exception.h" - -Utils::Exception::Exception() -{ -} - -Utils::Exception::~Exception() -{ -} - -const char* Utils::Exception::what() const noexcept( true ) -{ - std::string* msg = new std::string(getMessage()); - return msg->c_str(); -} diff --git a/exception.h b/exception.h deleted file mode 100644 index 4c66c2d..0000000 --- a/exception.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Squawk messenger. - * Copyright (C) 2019 Yury Gubich - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef EXCEPTION_H -#define EXCEPTION_H - -#include -#include - -namespace Utils -{ - class Exception: - public std::exception - { - public: - Exception(); - virtual ~Exception(); - - virtual std::string getMessage() const = 0; - - const char* what() const noexcept( true ); - }; -} - -#endif // EXCEPTION_H diff --git a/exceptions.cpp b/exceptions.cpp index ac607aa..a210372 100644 --- a/exceptions.cpp +++ b/exceptions.cpp @@ -16,6 +16,18 @@ #include "exceptions.h" +DataBase::Exception::Exception(): +std::exception() +{} + +DataBase::Exception::~Exception() {} + +const char* DataBase::Exception::what() const noexcept( true ) +{ + std::string* msg = new std::string(getMessage()); + return msg->c_str(); +} + DataBase::Directory::Directory(const std::string& p_path): Exception(), path(p_path) {} diff --git a/exceptions.h b/exceptions.h index e77f681..bdfd62a 100644 --- a/exceptions.h +++ b/exceptions.h @@ -17,10 +17,22 @@ #ifndef CORE_DATABASE_EXCEPTIONS_H #define CORE_DATABASE_EXCEPTIONS_H -#include "exception.h" +#include +#include #include "database.h" -class DataBase::Directory: public Utils::Exception { +class DataBase::Exception : public std::exception +{ +public: + Exception(); + virtual ~Exception(); + + virtual std::string getMessage() const = 0; + + const char* what() const noexcept( true ); +}; + +class DataBase::Directory: public DataBase::Exception { public: Directory(const std::string& path); @@ -29,7 +41,7 @@ private: std::string path; }; -class DataBase::Closed : public Utils::Exception { +class DataBase::Closed : public DataBase::Exception { public: Closed(const std::string& p_operation, const std::string& dbName, const std::string& tableName); @@ -40,7 +52,7 @@ private: std::string tableName; }; -class DataBase::Opened : public Utils::Exception { +class DataBase::Opened : public DataBase::Exception { public: Opened(const std::string& dbName, const std::string& tableName); @@ -50,7 +62,7 @@ private: std::string tableName; }; -class DataBase::NotFound : public Utils::Exception { +class DataBase::NotFound : public DataBase::Exception { public: NotFound(const std::string& key, const std::string& dbName, const std::string& tableName); @@ -61,7 +73,7 @@ private: std::string tableName; }; -class DataBase::Exist : public Utils::Exception { +class DataBase::Exist : public DataBase::Exception { public: Exist(const std::string& key, const std::string& dbName, const std::string& tableName); @@ -72,7 +84,7 @@ private: std::string tableName; }; -class DataBase::Unknown : public Utils::Exception { +class DataBase::Unknown : public DataBase::Exception { public: Unknown(const std::string& dbName, const std::string& message, const std::optional& tableName = std::nullopt); diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 3b2104a..0000000 --- a/main.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include - -#include "database.h" -#include "table.h" - - -int main(int argc, char **argv) { - - DataBase base("test1"); - DataBase::Table* table1 = base.addTable("table1"); - DataBase::Table* table2 = base.addTable("table2"); - - base.open(); - - try { - table1->addRecord(1, 2); - } catch (const DataBase::Exist& error) { - std::cout << error.getMessage() << std::endl; - } - - uint32_t rec1 = table1->getRecord(1); - std::cout << "table1 record under 1 is " << rec1 << std::endl; - - try { - table2->addRecord("hello", "world"); - } catch (const DataBase::Exist& error) { - std::cout << error.getMessage() << std::endl; - } - - QString rec2 = table2->getRecord("hello"); - std::cout << "table2 record under hello is " << rec2.toStdString() << std::endl; - - return 0; -} diff --git a/serializer.h b/serializer.h index 992f3f4..1adbabc 100644 --- a/serializer.h +++ b/serializer.h @@ -47,6 +47,9 @@ private: }; #include "serializer.hpp" +#include "serializer_uint64.hpp" #include "serializer_uint32.hpp" +#include "serializer_uint16.hpp" +#include "serializer_uint8.hpp" #endif // CORE_DATABASE_SERIALIZER_H diff --git a/serializer_uint16.hpp b/serializer_uint16.hpp new file mode 100644 index 0000000..3551de2 --- /dev/null +++ b/serializer_uint16.hpp @@ -0,0 +1,52 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef CORE_DATABASE_SERIALIZER_UINT16_HPP +#define CORE_DATABASE_SERIALIZER_UINT16_HPP + +template<> +class DataBase::Serializer +{ +public: + Serializer():value(0) {}; + Serializer(const uint16_t& p_value):value(p_value) {}; + ~Serializer() {}; + + uint16_t deserialize(const MDB_val& data) { + std::memcpy(&value, data.mv_data, 2); + return value; + }; + MDB_val setData(const uint16_t& data) { + value = data; + return getData(); + }; + MDB_val getData() { + MDB_val result; + result.mv_data = &value, + result.mv_size = 2; + return result; + }; + void clear() {}; //not possible; + +private: + uint16_t value; +}; + + +#endif //CORE_DATABASE_SERIALIZER_UINT16_HPP + + diff --git a/serializer_uint64.hpp b/serializer_uint64.hpp new file mode 100644 index 0000000..2b19b9d --- /dev/null +++ b/serializer_uint64.hpp @@ -0,0 +1,51 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef CORE_DATABASE_SERIALIZER_UINT64_HPP +#define CORE_DATABASE_SERIALIZER_UINT64_HPP + +template<> +class DataBase::Serializer +{ +public: + Serializer():value(0) {}; + Serializer(const uint64_t& p_value):value(p_value) {}; + ~Serializer() {}; + + uint64_t deserialize(const MDB_val& data) { + std::memcpy(&value, data.mv_data, 8); + return value; + }; + MDB_val setData(const uint64_t& data) { + value = data; + return getData(); + }; + MDB_val getData() { + MDB_val result; + result.mv_data = &value, + result.mv_size = 8; + return result; + }; + void clear() {}; //not possible; + +private: + uint64_t value; +}; + + +#endif //CORE_DATABASE_SERIALIZER_UINT64_HPP + diff --git a/serializer_uint8.hpp b/serializer_uint8.hpp new file mode 100644 index 0000000..97f76b0 --- /dev/null +++ b/serializer_uint8.hpp @@ -0,0 +1,53 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#ifndef CORE_DATABASE_SERIALIZER_UINT8_HPP +#define CORE_DATABASE_SERIALIZER_UINT8_HPP + +template<> +class DataBase::Serializer +{ +public: + Serializer():value(0) {}; + Serializer(const uint8_t& p_value):value(p_value) {}; + ~Serializer() {}; + + uint8_t deserialize(const MDB_val& data) { + std::memcpy(&value, data.mv_data, 1); + return value; + }; + MDB_val setData(const uint8_t& data) { + value = data; + return getData(); + }; + MDB_val getData() { + MDB_val result; + result.mv_data = &value, + result.mv_size = 1; + return result; + }; + void clear() {}; //not possible; + +private: + uint8_t value; +}; + + +#endif //CORE_DATABASE_SERIALIZER_UINT8_HPP + + + diff --git a/storage.h b/storage.h deleted file mode 100644 index 6670f6a..0000000 --- a/storage.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Squawk messenger. - * Copyright (C) 2019 Yury Gubich - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef CORE_STORAGE_H -#define CORE_STORAGE_H - -#include -#include - - -#include "exception.h" - -namespace Core { - -/** - * @todo write docs - */ -template -class Storage -{ -public: - Storage(const QString& name); - ~Storage(); - - void open(); - void close(); - - void addRecord(const K& key, const V& value); - void changeRecord(const K& key, const V& value); - void removeRecord(const K& key); - V getRecord(const K& key) const; - QString getName() const; - - -private: - QString name; - bool opened; - MDB_env* environment; - MDB_dbi base; - -public: - class Directory: - public Utils::Exception - { - public: - Directory(const std::string& p_path):Exception(), path(p_path){} - - std::string getMessage() const{return "Can't create directory for database at " + path;} - private: - std::string path; - }; - - class Closed: - public Utils::Exception - { - public: - Closed(const std::string& op, const std::string& acc):Exception(), operation(op), account(acc){} - - std::string getMessage() const{return "An attempt to perform operation " + operation + " on closed archive for " + account;} - private: - std::string operation; - std::string account; - }; - - class NotFound: - public Utils::Exception - { - public: - NotFound(const std::string& k, const std::string& acc):Exception(), key(k), account(acc){} - - std::string getMessage() const{return "Element for id " + key + " wasn't found in database " + account;} - private: - std::string key; - std::string account; - }; - - class Empty: - public Utils::Exception - { - public: - Empty(const std::string& acc):Exception(), account(acc){} - - std::string getMessage() const{return "An attempt to read ordered elements from database " + account + " but it's empty";} - private: - std::string account; - }; - - class Exist: - public Utils::Exception - { - public: - Exist(const std::string& acc, const std::string& p_key):Exception(), account(acc), key(p_key){} - - std::string getMessage() const{return "An attempt to insert element " + key + " to database " + account + " but it already has an element with given id";} - private: - std::string account; - std::string key; - }; - - class NoAvatar: - public Utils::Exception - { - public: - NoAvatar(const std::string& el, const std::string& res):Exception(), element(el), resource(res){ - if (resource.size() == 0) { - resource = "for himself"; - } - } - - std::string getMessage() const{return "Element " + element + " has no avatar for " + resource ;} - private: - std::string element; - std::string resource; - }; - - class Unknown: - public Utils::Exception - { - public: - Unknown(const std::string& acc, const std::string& message):Exception(), account(acc), msg(message){} - - std::string getMessage() const{return "Unknown error on database " + account + ": " + msg;} - private: - std::string account; - std::string msg; - }; -}; - -} - -MDB_val& operator << (MDB_val& data, QString& value); -MDB_val& operator >> (MDB_val& data, QString& value); - -MDB_val& operator << (MDB_val& data, uint32_t& value); -MDB_val& operator >> (MDB_val& data, uint32_t& value); - -namespace std { - std::string to_string(const QString& str); -} - -#include "storage.hpp" - -#endif // CORE_STORAGE_H diff --git a/storage.hpp b/storage.hpp deleted file mode 100644 index 477d70e..0000000 --- a/storage.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Squawk messenger. - * Copyright (C) 2019 Yury Gubich - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef CORE_STORAGE_HPP -#define CORE_STORAGE_HPP - -#include -#include - -#include "storage.h" -#include - -template -Core::Storage::Storage(const QString& p_name): - name(p_name), - opened(false), - environment(), - base() -{ -} - -template -Core::Storage::~Storage() -{ - close(); -} - -template -void Core::Storage::open() -{ - if (!opened) { - mdb_env_create(&environment); - QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - path += "/" + name; - QDir cache(path); - - if (!cache.exists()) { - bool res = cache.mkpath(path); - if (!res) { - throw Directory(path.toStdString()); - } - } - - mdb_env_set_maxdbs(environment, 1); - mdb_env_set_mapsize(environment, 10UL * 1024UL * 1024UL); - mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - mdb_dbi_open(txn, "base", MDB_CREATE, &base); - mdb_txn_commit(txn); - opened = true; - } -} - -template -void Core::Storage::close() -{ - if (opened) { - mdb_dbi_close(environment, base); - mdb_env_close(environment); - opened = false; - } -} - -template -void Core::Storage::addRecord(const K& key, const V& value) -{ - if (!opened) { - throw Closed("addRecord", name.toStdString()); - } - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - ds << value; - - MDB_val lmdbKey, lmdbData; - lmdbKey << key; - - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - int rc; - rc = mdb_put(txn, base, &lmdbKey, &lmdbData, MDB_NOOVERWRITE); - if (rc != 0) { - mdb_txn_abort(txn); - if (rc == MDB_KEYEXIST) { - throw Exist(name.toStdString(), std::to_string(key)); - } else { - throw Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - mdb_txn_commit(txn); - } -} - -template -void Core::Storage::changeRecord(const K& key, const V& value) -{ - if (!opened) { - throw Closed("changeRecord", name.toStdString()); - } - - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - ds << value; - - MDB_val lmdbKey, lmdbData; - lmdbKey << key; - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - int rc; - rc = mdb_put(txn, base, &lmdbKey, &lmdbData, 0); - if (rc != 0) { - mdb_txn_abort(txn); - if (rc) { - throw Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - mdb_txn_commit(txn); - } -} - -template -V Core::Storage::getRecord(const K& key) const -{ - if (!opened) { - throw Closed("addElement", name.toStdString()); - } - - MDB_val lmdbKey, lmdbData; - lmdbKey << key; - - MDB_txn *txn; - int rc; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - rc = mdb_get(txn, base, &lmdbKey, &lmdbData); - if (rc) { - mdb_txn_abort(txn); - if (rc == MDB_NOTFOUND) { - throw NotFound(std::to_string(key), name.toStdString()); - } else { - throw Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - QByteArray ba((char*)lmdbData.mv_data, lmdbData.mv_size); - QDataStream ds(&ba, QIODevice::ReadOnly); - V value; - ds >> value; - mdb_txn_abort(txn); - - return value; - } -} - -template -void Core::Storage::removeRecord(const K& key) -{ - if (!opened) { - throw Closed("addElement", name.toStdString()); - } - - MDB_val lmdbKey; - lmdbKey << key; - - MDB_txn *txn; - int rc; - mdb_txn_begin(environment, NULL, 0, &txn); - rc = mdb_del(txn, base, &lmdbKey, NULL); - if (rc) { - mdb_txn_abort(txn); - if (rc == MDB_NOTFOUND) { - throw NotFound(std::to_string(key), name.toStdString()); - } else { - throw Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - mdb_txn_commit(txn); - } -} - -template -QString Core::Storage::getName() const { - return name;} - -MDB_val& operator << (MDB_val& data, const QString& value) { - QByteArray ba = value.toUtf8(); - data.mv_size = ba.size(); - data.mv_data = ba.data(); - return data; -} -MDB_val& operator >> (MDB_val& data, QString& value) { - value = QString::fromUtf8((const char*)data.mv_data, data.mv_size); - return data; -} - -MDB_val& operator << (MDB_val& data, uint32_t& value) { - data.mv_size = 4; - data.mv_data = &value; - return data; -} -MDB_val& operator >> (MDB_val& data, uint32_t& value) { - std::memcpy(&value, data.mv_data, data.mv_size); - return data; -} - -std::string std::to_string(const QString& str) { - return str.toStdString(); -} -#endif //CORE_STORAGE_HPP diff --git a/table.hpp b/table.hpp index 9365ec5..47b135c 100644 --- a/table.hpp +++ b/table.hpp @@ -144,11 +144,26 @@ inline int DataBase::_Table::makeTable(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE, &dbi); } +template<> +inline int DataBase::_Table::makeTable(MDB_txn* transaction) { + return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); +} + template<> inline int DataBase::_Table::makeTable(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } +template<> +inline int DataBase::_Table::makeTable(MDB_txn* transaction) { + return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); +} + +template<> +inline int DataBase::_Table::makeTable(MDB_txn* transaction) { + return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); +} + template inline std::string DataBase::_Table::toString(const T& value) { return std::to_string(value); @@ -159,4 +174,9 @@ inline std::string DataBase::_Table::toString(const QString& value) { return value.toStdString(); } +template<> +inline std::string DataBase::_Table::toString(const std::string& value) { + return value; +} + #endif //CORE_TABLE_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..d35802f --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,22 @@ +enable_testing() +find_package(GTest REQUIRED) +include_directories(${GTEST_INCLUDE_DIR}) + +add_executable(runUnitTests + basic.cpp +) + +target_compile_options(runUnitTests PRIVATE -fPIC) + +target_include_directories(runUnitTests PRIVATE ${CMAKE_SOURCE_DIR}) +target_include_directories(runUnitTests PRIVATE ${Qt${QT_VERSION_MAJOR}_INCLUDE_DIRS}) +target_include_directories(runUnitTests PRIVATE ${Qt${QT_VERSION_MAJOR}Core_INCLUDE_DIRS}) + +target_link_libraries( + runUnitTests + GTest::gtest_main + storage +) + +include(GoogleTest) +gtest_discover_tests(runUnitTests) diff --git a/test/basic.cpp b/test/basic.cpp new file mode 100644 index 0000000..affbd4e --- /dev/null +++ b/test/basic.cpp @@ -0,0 +1,66 @@ +#include + +#include "database.h" +#include "table.h" + +#include + +class DataBaseTest : public ::testing::Test { +protected: + DataBaseTest(): + ::testing::Test(), + t1(db->getTable("table1")), + t2(db->getTable("table2")) {} + + ~DataBaseTest() { + } + + static void SetUpTestSuite() { + if (db == nullptr) { + db = new DataBase("testBase"); + db->addTable("table1"); + db->addTable("table2"); + } + } + + static void TearDownTestSuite() { + db->close(); + db->removeDirectory(); + delete db; + db = nullptr; + } + + static DataBase* db; + + DataBase::Table* t1; + DataBase::Table* t2; +}; + + +DataBase* DataBaseTest::db = nullptr; + +TEST_F(DataBaseTest, RemovingDirectory) { + EXPECT_EQ(db->removeDirectory(), true); +} + +TEST_F(DataBaseTest, OpeningDatabase) { + db->open(); + EXPECT_EQ(db->ready(), true); +} + +TEST_F(DataBaseTest, AddingIntegerKey) { + EXPECT_EQ(db->ready(), true); + t1->addRecord(1, 2); + EXPECT_EQ(t1->getRecord(1), 2); +} + +TEST_F(DataBaseTest, AddingQStringKey) { + EXPECT_EQ(db->ready(), true); + t2->addRecord("hello", "world"); + EXPECT_EQ(t2->getRecord("hello"), "world"); +} + +TEST_F(DataBaseTest, ClosingDatabase) { + db->close(); + EXPECT_EQ(db->ready(), false); +}