5 Commits
Author SHA1 Message Date
Dmitriy a6676997d4 Merge pull request 'Base implementation' (#1) from base-impl into master
Reviewed-on: #1
2026-09-29 14:25:03 +00:00
Samsonium 160e932f2e feat: add engine test 2026-09-29 15:19:18 +03:00
Samsonium 62f844a582 feat: implement db provider 2026-09-29 14:46:44 +03:00
Samsonium e756bb1d73 feat: implement module access in engine API
- Add implementation for `getModule`
- Add implementation for `getLoadedModules`
2026-09-29 13:25:49 +03:00
Samsonium ff0453e81d feat: add event bus to engine public API 2026-09-29 13:10:54 +03:00
8 changed files with 382 additions and 13 deletions
+28
View File
@@ -3,12 +3,15 @@ project(magic_scrolls)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(SQLite3 REQUIRED)
file(GLOB_RECURSE sources file(GLOB_RECURSE sources
"${CMAKE_SOURCE_DIR}/src/*.cpp") "${CMAKE_SOURCE_DIR}/src/*.cpp")
add_executable(magic_scrolls ${sources}) add_executable(magic_scrolls ${sources})
target_include_directories(magic_scrolls PUBLIC "${CMAKE_SOURCE_DIR}/include") target_include_directories(magic_scrolls PUBLIC "${CMAKE_SOURCE_DIR}/include")
target_link_libraries(magic_scrolls PRIVATE SQLite::SQLite3)
# ------- # -------
enable_testing() enable_testing()
@@ -17,10 +20,35 @@ add_executable(event_bus_test
tests/engine/event_bus_test.cpp tests/engine/event_bus_test.cpp
src/engine/core/event_bus.cpp src/engine/core/event_bus.cpp
) )
add_executable(db_provider_test
tests/engine/db_provider_test.cpp
src/engine/core/engine.cpp
src/engine/core/engine_db_provider.cpp
)
add_executable(engine_test
tests/engine/engine_test.cpp
src/engine/core/engine.cpp
src/engine/core/engine_db_provider.cpp
)
target_include_directories(event_bus_test PUBLIC "${CMAKE_SOURCE_DIR}/include") target_include_directories(event_bus_test PUBLIC "${CMAKE_SOURCE_DIR}/include")
target_link_libraries(event_bus_test PRIVATE SQLite::SQLite3)
target_include_directories(db_provider_test PUBLIC "${CMAKE_SOURCE_DIR}/include")
target_link_libraries(db_provider_test PRIVATE SQLite::SQLite3)
target_include_directories(engine_test PUBLIC "${CMAKE_SOURCE_DIR}/include")
target_link_libraries(engine_test PRIVATE SQLite::SQLite3)
add_test( add_test(
NAME "Event Bus" NAME "Event Bus"
COMMAND event_bus_test COMMAND event_bus_test
) )
add_test(
NAME "Database Provider"
COMMAND db_provider_test
)
add_test(
NAME "Engine"
COMMAND engine_test
)
+9 -4
View File
@@ -1,8 +1,9 @@
#ifndef __MCS_ENGINE_HPP__ #ifndef __MCS_ENGINE_HPP__
#define __MCS_ENGINE_HPP__ #define __MCS_ENGINE_HPP__
#include "engine/core/engine_module.hpp" #include <engine/core/engine_module.hpp>
#include "engine/core/engine_module_api.hpp" #include <engine/core/engine_module_api.hpp>
#include <engine/core/engine_db_provider.hpp>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <vector> #include <vector>
@@ -13,6 +14,7 @@ class MscEngine : public IMscEngineModuleAPI
private: private:
/// Loaded modules list /// Loaded modules list
std::vector<std::shared_ptr<MscEngineModule>> _modules; std::vector<std::shared_ptr<MscEngineModule>> _modules;
MscEventBus _bus;
public: public:
/// Actual version /// Actual version
@@ -20,8 +22,11 @@ public:
MscEngine(std::vector<std::shared_ptr<MscEngineModule>> modules); MscEngine(std::vector<std::shared_ptr<MscEngineModule>> modules);
UNIMPL getBus() const override; MscEventBus &getBus() override;
UNIMPL getLoadedModules() const override; std::unordered_map<std::string, std::uint16_t> getLoadedModules() const override;
MscEngineModule &getModule(const std::string &name) override;
std::unique_ptr<MscEngineDBProvider> createDBProvider() override;
std::unique_ptr<MscEngineDBProvider> createDBProvider(const std::string &filepath) override;
}; };
#endif // __MCS_ENGINE_HPP__ #endif // __MCS_ENGINE_HPP__
@@ -0,0 +1,30 @@
#ifndef __MSC_ENGINE_DB_PROVIDER_HPP__
#define __MSC_ENGINE_DB_PROVIDER_HPP__
#include <sqlite3.h>
#include <string>
/// @brief Engine database provider
class MscEngineDBProvider
{
public:
~MscEngineDBProvider();
/// @brief Create inmemory database
MscEngineDBProvider();
/// @brief Create file database
explicit MscEngineDBProvider(const std::string &filepath);
/// @brief Execute SQL statement
/// @param sql statement
void execute(const std::string &sql);
MscEngineDBProvider(const MscEngineDBProvider &) = delete;
MscEngineDBProvider &operator=(const MscEngineDBProvider &) = delete;
private:
sqlite3 *_db = nullptr;
};
#endif // __MSC_ENGINE_DB_PROVIDER_HPP__
+21 -5
View File
@@ -1,18 +1,34 @@
#ifndef __MSC_ENGINE_MODULE_API_HPP__ #ifndef __MSC_ENGINE_MODULE_API_HPP__
#define __MSC_ENGINE_MODULE_API_HPP__ #define __MSC_ENGINE_MODULE_API_HPP__
typedef void UNIMPL; #include <engine/core/engine_bus.hpp>
#include <engine/core/engine_db_provider.hpp>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <memory>
class MscEngineModule;
class IMscEngineModuleAPI class IMscEngineModuleAPI
{ {
public: public:
virtual ~IMscEngineModuleAPI() = default; virtual ~IMscEngineModuleAPI() = default;
/// Get access to engine event bus /// @brief Get access to engine event bus
virtual UNIMPL getBus() const = 0; virtual MscEventBus &getBus() = 0;
/// Get access to loaded module list /// @brief Get access to loaded module list
virtual UNIMPL getLoadedModules() const = 0; virtual std::unordered_map<std::string, std::uint16_t> getLoadedModules() const = 0;
/// @brief Access module by its name
virtual MscEngineModule &getModule(const std::string &name) = 0;
/// @brief Create database provider with in-memory database
virtual std::unique_ptr<MscEngineDBProvider> createDBProvider() = 0;
/// @brief Create database provider with file database
virtual std::unique_ptr<MscEngineDBProvider> createDBProvider(const std::string &filepath) = 0;
}; };
#endif // __MSC_ENGINE_MODULE_API_HPP__ #endif // __MSC_ENGINE_MODULE_API_HPP__
+38 -4
View File
@@ -54,9 +54,43 @@ MscEngine::MscEngine(std::vector<std::shared_ptr<MscEngineModule>> modules)
_modules = std::move(modules); _modules = std::move(modules);
} }
UNIMPL MscEngine::getBus() const { throw std::runtime_error("Unimplemented"); } MscEventBus &MscEngine::getBus()
UNIMPL MscEngine::getLoadedModules() const
{ {
throw std::runtime_error("Unimplemented"); return _bus;
}
std::unordered_map<std::string, std::uint16_t> MscEngine::getLoadedModules() const
{
std::unordered_map<std::string, std::uint16_t> result;
for (const auto &module : _modules)
{
if (!module)
continue;
auto mod = module.get();
result[mod->getName()] = mod->getRev();
}
return result;
}
MscEngineModule &MscEngine::getModule(const std::string &name)
{
for (auto &module : _modules)
{
if (module.get()->getName() == name)
return *module.get();
}
throw std::runtime_error("Module not found: " + name);
}
std::unique_ptr<MscEngineDBProvider> MscEngine::createDBProvider()
{
return std::make_unique<MscEngineDBProvider>();
}
std::unique_ptr<MscEngineDBProvider> MscEngine::createDBProvider(const std::string &filepath)
{
return std::make_unique<MscEngineDBProvider>(filepath);
} }
+45
View File
@@ -0,0 +1,45 @@
#include <engine/core/engine_db_provider.hpp>
#include <stdexcept>
MscEngineDBProvider::MscEngineDBProvider() : MscEngineDBProvider(":memory:")
{
}
MscEngineDBProvider::MscEngineDBProvider(const std::string &filepath)
{
const int result = sqlite3_open(filepath.c_str(), &_db);
if (result != SQLITE_OK)
{
const std::string message = _db != nullptr
? sqlite3_errmsg(_db)
: "unknown SQLite error";
if (_db != nullptr)
{
sqlite3_close(_db);
_db = nullptr;
}
throw std::runtime_error("Failed to open SQLite database: " + message);
}
}
MscEngineDBProvider::~MscEngineDBProvider()
{
if (_db != nullptr)
sqlite3_close(_db);
}
void MscEngineDBProvider::execute(const std::string &sql)
{
char *errorMessage = nullptr;
const int result = sqlite3_exec(_db, sql.c_str(), nullptr, nullptr, &errorMessage);
if (result == SQLITE_OK)
return;
std::string message(errorMessage);
sqlite3_free(errorMessage);
throw std::runtime_error("Failed to execute SQL: " + message);
}
+62
View File
@@ -0,0 +1,62 @@
#include <cassert>
#include <vector>
#include <stdexcept>
#include <engine/core/engine.hpp>
#include <engine/core/engine_db_provider.hpp>
/// @brief Проверка на создание экземпляра
void testProviderCreation()
{
MscEngine engine({});
auto dbp1 = engine.createDBProvider();
assert(dbp1.get() != nullptr);
}
/// @brief Проверка на создание экземпляра с некорректным путём файла
void testIncorrectFilePath()
{
MscEngine engine({});
try
{
engine.createDBProvider("/i/am/an/incorrect/path/to/file.txt");
assert(false);
}
catch (const std::runtime_error &error)
{
}
}
/// @brief Проверка на успешное выполнение корректного выражения
void testValidStatement()
{
MscEngine engine({});
auto dbp = engine.createDBProvider();
dbp.get()->execute("SELECT 'hello, world' AS message;");
}
void testInvalidStatement()
{
MscEngine engine({});
auto dbp = engine.createDBProvider();
try
{
dbp.get()->execute("SELECT * FROM nonexistentdatabase ABC");
assert(false);
}
catch (const std::runtime_error &error)
{
}
}
int main()
{
testProviderCreation();
testIncorrectFilePath();
testValidStatement();
testInvalidStatement();
return 0;
}
+149
View File
@@ -0,0 +1,149 @@
#include <cassert>
#include <string>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <unordered_map>
#include <engine/utils/rev_range.hpp>
#include <engine/core/engine.hpp>
#include <engine/core/engine_module.hpp>
class FirstTestModuleR1 : public MscEngineModule
{
public:
std::string getName() const override
{
return "first_tmod";
};
std::uint16_t getRev() const override
{
return 1;
}
const std::unordered_map<std::string, MscRevisionRange> &getDependencies() const override
{
static const std::unordered_map<std::string, MscRevisionRange> deps{};
return deps;
}
void onInitialize(IMscEngineModuleAPI &engine) override {}
};
class FirstTestModuleR2 : public MscEngineModule
{
public:
std::string getName() const override
{
return "first_tmod";
};
std::uint16_t getRev() const override
{
return 2;
}
const std::unordered_map<std::string, MscRevisionRange> &getDependencies() const override
{
static const std::unordered_map<std::string, MscRevisionRange> deps{};
return deps;
}
void onInitialize(IMscEngineModuleAPI &engine) override {}
};
class SecondTestModuleE1 : public MscEngineModule
{
public:
std::string getName() const override
{
return "second_tmod";
}
std::uint16_t getRev() const override
{
return 1;
}
const std::unordered_map<std::string, MscRevisionRange> &getDependencies() const override
{
static const std::unordered_map<std::string, MscRevisionRange> deps{
{"first_tmod", MscRevisionRange{1, 1}}};
return deps;
}
void onInitialize(IMscEngineModuleAPI &engine) override {}
};
class SecondTestModuleE2 : public MscEngineModule
{
public:
std::string getName() const override
{
return "second_tmod";
}
std::uint16_t getRev() const override
{
return 1;
}
const std::unordered_map<std::string, MscRevisionRange> &getDependencies() const override
{
static const std::unordered_map<std::string, MscRevisionRange> deps{
{"first_tmod", MscRevisionRange{1, 2}}};
return deps;
}
void onInitialize(IMscEngineModuleAPI &engine) override {}
};
void testSatisfiedModules()
{
MscEngine engine({std::make_shared<FirstTestModuleR1>(),
std::make_shared<SecondTestModuleE1>()});
}
void testDuplicatedModules()
{
try
{
MscEngine engine({
std::make_shared<FirstTestModuleR1>(),
std::make_shared<FirstTestModuleR2>(),
});
assert(false);
}
catch (const std::runtime_error &error)
{
}
}
void testUnsatisfiedModules()
{
try
{
MscEngine engine({std::make_shared<FirstTestModuleR2>(),
std::make_shared<SecondTestModuleE1>()});
assert(false);
}
catch (const std::runtime_error &error)
{
}
}
void testSatisfiedMultiversionModule()
{
MscEngine engine({std::make_shared<FirstTestModuleR2>(),
std::make_shared<SecondTestModuleE2>()});
}
int main()
{
testSatisfiedModules();
testDuplicatedModules();
testUnsatisfiedModules();
testSatisfiedMultiversionModule();
return 0;
}