diff --git a/source/Backend/DataBase/CMakeLists.txt b/source/Backend/DataBase/CMakeLists.txt index e7ed2cc..99727dc 100644 --- a/source/Backend/DataBase/CMakeLists.txt +++ b/source/Backend/DataBase/CMakeLists.txt @@ -1,3 +1,7 @@ project(PasswordManager) -target_sources(passwordManager PRIVATE DataBaseHandler.cpp) +target_include_directories(passwordManager PRIVATE DataBase/interface) +target_include_directories(passwordManager PRIVATE DataBase/common) + +target_sources(passwordManager PRIVATE + DataBaseConnection.cpp DataBaseManager.cpp QueryOperationBuilder.cpp) diff --git a/source/Backend/DataBase/DataBaseConnection.cpp b/source/Backend/DataBase/DataBaseConnection.cpp new file mode 100644 index 0000000..81b2df2 --- /dev/null +++ b/source/Backend/DataBase/DataBaseConnection.cpp @@ -0,0 +1,57 @@ +#include "DataBaseConnection.hpp" + +#include "sqlite3.h" + +namespace dataBase { +DataBaseConnection::DataBaseConnection(const char *dbName) + : database_(nullptr) { + int result = sqlite3_open(dbName, &database_); + if (result != SQLITE_OK) { + throw std::runtime_error("Failed to open database: " + + std::string(sqlite3_errmsg(database_))); + } +} + +DataBaseConnection::~DataBaseConnection() { + if (database_ != nullptr) { + sqlite3_close(database_); + } +} + +void DataBaseConnection::executeQuery(const std::string &query) { + char *errMsg = nullptr; + + int result = + sqlite3_exec(database_, query.c_str(), nullptr, nullptr, &errMsg); + checkResult(result, errMsg); +} + +std::vector DataBaseConnection::executeQueryAndGetData( + const std::string &query) { + char *errMsg = nullptr; + + auto callback = [](void *data, int argc, char **argv, + char **azColName) -> int { + auto records = reinterpret_cast *>(data); + for (int i = 0; i < argc; i++) { + records->push_back(argv[i] ? argv[i] : ""); + } + return 0; + }; + + std::vector records; + int result = + sqlite3_exec(database_, query.c_str(), callback, &records, &errMsg); + + checkResult(result, errMsg); + return records; +} + +void DataBaseConnection::checkResult(int result, char *errMsg) { + if (result != SQLITE_OK) { + std::string error_msg = errMsg ? errMsg : sqlite3_errmsg(database_); + sqlite3_free(errMsg); + throw std::runtime_error("Failed to execute query: " + error_msg); + } +} +} // namespace dataBase diff --git a/source/Backend/DataBase/DataBaseConnection.hpp b/source/Backend/DataBase/DataBaseConnection.hpp new file mode 100644 index 0000000..9a0c780 --- /dev/null +++ b/source/Backend/DataBase/DataBaseConnection.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "interface/IDataBaseConnection.hpp" +#include "sqlite3.h" + +namespace dataBase { +class DataBaseConnection : public interface::IDataBaseConnection { + public: + DataBaseConnection(const char *dbName); + + ~DataBaseConnection(); + + void executeQuery(const std::string &query) override; + std::vector executeQueryAndGetData( + const std::string &query) override; + + private: + void checkResult(int result, char *errMsg); + + private: + sqlite3 *database_; +}; + +} // namespace dataBase diff --git a/source/Backend/DataBase/DataBaseHandler.cpp b/source/Backend/DataBase/DataBaseHandler.cpp deleted file mode 100644 index 3f337c3..0000000 --- a/source/Backend/DataBase/DataBaseHandler.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "DataBaseHandler.hpp" - -#include -#include -#include -namespace dataBase { - -DataBaseHandler::DataBaseHandler(const char *dbName) : database_(nullptr) { - int result = sqlite3_open(dbName, &database_); - if (result != SQLITE_OK) { - throw std::runtime_error("Failed to open database: " + - std::string(sqlite3_errmsg(database_))); - } -} - -DataBaseHandler::~DataBaseHandler() { - if (database_ != nullptr) { - sqlite3_close(database_); - } -} - -void DataBaseHandler::executeQuery(const char *query) { - char *errMsg = nullptr; - int result = sqlite3_exec(database_, query, nullptr, nullptr, &errMsg); - if (result != SQLITE_OK) { - throw std::runtime_error("Query execution failed: " + std::string(errMsg)); - } -} - -void DataBaseHandler::createTable(const std::string &tableName, - const std::string &columns) { - std::string query = - "CREATE TABLE IF NOT EXISTS " + tableName + " (" + columns + ");"; - executeQuery(query.c_str()); -} - -void DataBaseHandler::insertData(const std::string &tableName, - const std::vector &columns, - const std::vector &values) { - if (columns.size() != values.size()) { - throw std::invalid_argument("Columns and values sizes do not match."); - } - - std::ostringstream queryStream; - queryStream << "INSERT INTO " << tableName << " ("; - for (size_t i = 0; i < columns.size(); ++i) { - queryStream << columns[i]; - if (i < columns.size() - 1) { - queryStream << ", "; - } - } - queryStream << ") VALUES ("; - for (size_t i = 0; i < values.size(); ++i) { - queryStream << "'" << values[i] << "'"; - if (i < values.size() - 1) { - queryStream << ", "; - } - } - queryStream << ");"; - - std::string query = queryStream.str(); - executeQuery(query.c_str()); -} - -void DataBaseHandler::deleteData(const std::string &tableName, - const std::string &columns, - const std::string &value) { - std::string query = - "DELETE FROM " + tableName + " WHERE " + columns + " = '" + value + "';"; - executeQuery(query.c_str()); -} - -void DataBaseHandler::updateData(const std::string &tableName, - const std::string &setRecord, - const std::string &setValue, - const std::string &findRecord, - const std::string &findValue) { - std::string query = "UPDATE " + tableName + " SET " + setRecord + " ='" + - setValue + "' WHERE " + findRecord + " = '" + findValue + - "';"; - executeQuery(query.c_str()); -} - -void DataBaseHandler::selectData(const std::string &tableName, - const std::string &findRecord, - const std::string &findValue) { - std::string query = - "SELECT " + findRecord + " FROM " + tableName + " WHERE " + findValue; - - executeQuery(query.c_str()); -} - -} // namespace dataBase diff --git a/source/Backend/DataBase/DataBaseHandler.hpp b/source/Backend/DataBase/DataBaseHandler.hpp deleted file mode 100644 index bb871da..0000000 --- a/source/Backend/DataBase/DataBaseHandler.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "sqlite3.h" - -namespace dataBase { - -class DataBaseHandler { - public: - DataBaseHandler(const char *dbName); - ~DataBaseHandler(); - - void createTable(const std::string &tableName, const std::string &columns); - void insertData(const std::string &tableName, - const std::vector &columns, - const std::vector &values); - void deleteData(const std::string &tableName, const std::string &columns, - const std::string &value); - - void updateData(const std::string &tableName, const std::string &setRecord, - const std::string &setValue, const std::string &findRecord, - const std::string &findValue); - - void selectData(const std::string &tableName, const std::string &findRecord, - const std::string &findValue); - - private: - void executeQuery(const char *query); - sqlite3 *database_; -}; - -} // namespace dataBase diff --git a/source/Backend/DataBase/DataBaseManager.cpp b/source/Backend/DataBase/DataBaseManager.cpp new file mode 100644 index 0000000..4a62ae7 --- /dev/null +++ b/source/Backend/DataBase/DataBaseManager.cpp @@ -0,0 +1,43 @@ + +#include "DataBaseManager.hpp" + +#include "QueryOperationBuilder.hpp" +namespace dataBase { +DataBaseManager::DataBaseManager( + std::shared_ptr dataBaseConnection, + std::shared_ptr queryOperationBuilder) + : dataBaseConnection_(std::move(dataBaseConnection)), + queryOperationBuilder_(std::move(queryOperationBuilder)) {} + +void DataBaseManager::executeOperation( + const common::DataBaseRequest &requestData) { + std::string query = queryOperationBuilder_->buildQuery(requestData); + + if (requestData.operationType_ != + common::DataBaseRequest::OperationType::Select && + !query.empty()) + + try { + dataBaseConnection_->executeQuery(query); + } catch (const std::runtime_error &e) { + std::cerr << "Error executing query: " << e.what() << std::endl; + } +} + +std::vector DataBaseManager::executeAndGetOperation( + const common::DataBaseRequest &requestData) { + std::string query = queryOperationBuilder_->buildQuery(requestData); + + try { + if (requestData.operationType_ == + common::DataBaseRequest::OperationType::Select && + !query.empty()) + return dataBaseConnection_->executeQueryAndGetData(query); + + return {}; + } catch (const std::runtime_error &e) { + std::cerr << "Error executing query: " << e.what() << std::endl; + return {}; + } +} +} // namespace dataBase diff --git a/source/Backend/DataBase/DataBaseManager.hpp b/source/Backend/DataBase/DataBaseManager.hpp new file mode 100644 index 0000000..7bf2b26 --- /dev/null +++ b/source/Backend/DataBase/DataBaseManager.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include + +#include "common/DataBaseRequest.hpp" +#include "interface/IDataBaseConnection.hpp" +#include "interface/IDataBaseManager.hpp" +#include "interface/IQueryOperationBuilder.hpp" + +namespace dataBase { +class DataBaseManager : public interface::IDataBaseManager { + public: + DataBaseManager( + std::shared_ptr dataBaseConnection, + std::shared_ptr queryOperationBuilder); + ~DataBaseManager() = default; + + void executeOperation(const common::DataBaseRequest &requestData) override; + std::vector executeAndGetOperation( + const common::DataBaseRequest &requestData) override; + + private: + std::shared_ptr dataBaseConnection_; + std::shared_ptr queryOperationBuilder_; +}; +} // namespace dataBase diff --git a/source/Backend/DataBase/QueryOperationBuilder.cpp b/source/Backend/DataBase/QueryOperationBuilder.cpp new file mode 100644 index 0000000..1bd18d1 --- /dev/null +++ b/source/Backend/DataBase/QueryOperationBuilder.cpp @@ -0,0 +1,120 @@ + +#include "QueryOperationBuilder.hpp" + +#include + +#include "common/DataBaseCommon.hpp" +namespace dataBase { +namespace { +bool isPrimaryKeyEmpty(const common::PrimaryKey &primaryKey) { + return (primaryKey.first.empty() || primaryKey.second.empty()); +} + +std::string buildInsertQuery(const common::DataBaseRequest &requestData, + const std::string &tableName) { + std::string columns; + std::string values; + for (auto it = requestData.data_.begin(); it != requestData.data_.end(); + ++it) { + columns += it->first; + values += std::format("'{}'", it->second); + if (std::next(it) != requestData.data_.end()) { + columns += ", "; + values += ", "; + } + } + + return std::format("INSERT INTO {} ({}) VALUES ({});", tableName, columns, + values); +} + +std::string buildUpdateQuery(const common::DataBaseRequest &requestData, + const std::string &tableName) { + std::string values; + + for (auto it = requestData.data_.begin(); it != requestData.data_.end(); + ++it) { + values += std::format("{}='{}'", it->first, it->second); + if (std::next(it) != requestData.data_.end()) { + values += ", "; + } + } + + return std::format("UPDATE {} SET {} WHERE {}='{}';", tableName, values, + requestData.primaryKey_.first, + requestData.primaryKey_.second); +} + +std::string buildDeleteQuery(const common::DataBaseRequest &requestData, + const std::string &tableName) { + return std::format("DELETE FROM {} WHERE {}='{}';", tableName, + requestData.primaryKey_.first, + requestData.primaryKey_.second); +} + +std::string buildSelectQuery(const common::DataBaseRequest &requestData, + const std::string &tableName) { + return std::format("SELECT * FROM {} WHERE {}='{}';", tableName, + requestData.primaryKey_.first, + requestData.primaryKey_.second); +} +std::unordered_map tableNames = + {{common::DataBaseRequest::TableType::Users, common::users}, + {common::DataBaseRequest::TableType::Passwords, common::passwords}, + {common::DataBaseRequest::TableType::PasswordHistory, + common::passwordHistory}, + {common::DataBaseRequest::TableType::Categories, common::categories}}; + +std::string getTableName(common::DataBaseRequest::TableType table) { + if (auto it = tableNames.find(table); it != tableNames.end()) + return it->second; + + return {}; +} + +auto insertCallback = [](const auto &requestData, const auto &tableName) { + return buildInsertQuery(requestData, tableName); +}; +auto updateCallback = [](const auto &requestData, const auto &tableName) { + return buildUpdateQuery(requestData, tableName); +}; +auto deleteCallback = [](const auto &requestData, const auto &tableName) { + return buildDeleteQuery(requestData, tableName); +}; +auto selectCallback = [](const auto &requestData, const auto &tableName) { + return buildSelectQuery(requestData, tableName); +}; + +QueryOperationBuilder::QueryBuilders queryBuilders = { + {QueryOperationBuilder::OperationType::Insert, insertCallback}, + {QueryOperationBuilder::OperationType::Update, updateCallback}, + {QueryOperationBuilder::OperationType::Delete, deleteCallback}, + {QueryOperationBuilder::OperationType::Select, selectCallback}}; + +std::string getOperationQuery(const common::DataBaseRequest &requestData, + const std::string &tableName) { + if (auto it = queryBuilders.find(requestData.operationType_); + it != queryBuilders.end()) + return it->second(requestData, tableName); + + return {}; +} +} // namespace + +std::string QueryOperationBuilder::buildQuery( + const common::DataBaseRequest &requestData) { + if (requestData.operationType_ != OperationType::Insert && + isPrimaryKeyEmpty(requestData.primaryKey_)) + return {}; + + if (requestData.operationType_ != OperationType::Select && + requestData.data_.empty()) + return {}; + + auto tableName = getTableName(requestData.tableType_); + if (tableName.empty()) return {}; + + return getOperationQuery(requestData, tableName); +} + +} // namespace dataBase diff --git a/source/Backend/DataBase/QueryOperationBuilder.hpp b/source/Backend/DataBase/QueryOperationBuilder.hpp new file mode 100644 index 0000000..457e5a2 --- /dev/null +++ b/source/Backend/DataBase/QueryOperationBuilder.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "common/DataBaseCommon.hpp" +#include "common/DataBaseRequest.hpp" +#include "interface/IQueryOperationBuilder.hpp" + +namespace dataBase { + +class QueryOperationBuilder : public interface::IQueryOperationBuilder { + public: + using QueryBuilders = std::unordered_map< + common::DataBaseRequest::OperationType, + std::function>; + using OperationType = common::DataBaseRequest::OperationType; + + QueryOperationBuilder() = default; + ~QueryOperationBuilder() = default; + std::string buildQuery(const common::DataBaseRequest &requestData) override; + + private: + std::string buildInsertQuery(const common::DataBaseRequest &requestData, + const std::string &tableName); + std::string buildUpdateQuery(const common::DataBaseRequest &requestData, + const std::string &tableName); + std::string buildDeleteQuery(const common::DataBaseRequest &requestData, + const std::string &tableName); + std::string buildSelectQuery(const common::DataBaseRequest &requestData, + const std::string &tableName); + + private: + QueryBuilders queryBuilders_; +}; + +} // namespace dataBase diff --git a/source/Backend/DataBase/common/DataBaseCommon.hpp b/source/Backend/DataBase/common/DataBaseCommon.hpp index ef8ced3..cc67ac7 100644 --- a/source/Backend/DataBase/common/DataBaseCommon.hpp +++ b/source/Backend/DataBase/common/DataBaseCommon.hpp @@ -6,17 +6,10 @@ namespace dataBase::common { static constexpr char dataBasePath[] = - "../../../source/dataBase/password-manager.db"; + "../../source/dataBase/password-manager.db"; static constexpr char users[] = "Users"; static constexpr char passwords[] = "Passwords"; static constexpr char passwordHistory[] = "PasswordHistory"; static constexpr char categories[] = "Categories"; -static const std::vector userRecordsRecords{"Username", - "Password"}; -static const std::vector categoriesRecords{"Category"}; -static const std::vector passwordHistoryRecords{ - "Creation_Time", "Modify_Time", "Expiry_Time"}; -static const std::vector passwordRecords{ - "User_Id", "Category_Id", "Title", "Username", "Password", "Note", "Url"}; }; // namespace dataBase::common diff --git a/source/Backend/DataBase/common/DataBaseRequest.hpp b/source/Backend/DataBase/common/DataBaseRequest.hpp new file mode 100644 index 0000000..8fe081f --- /dev/null +++ b/source/Backend/DataBase/common/DataBaseRequest.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace dataBase::common { +using RequestData = std::map; +using PrimaryKey = std::pair; + +struct DataBaseRequest { + enum class TableType { Users, Passwords, PasswordHistory, Categories }; + + enum class OperationType { Insert, Delete, Update, Select }; + + OperationType operationType_; + TableType tableType_; + RequestData data_; + PrimaryKey primaryKey_; +}; + +} // namespace dataBase::common diff --git a/source/Backend/DataBase/interface/IDataBaseConnection.hpp b/source/Backend/DataBase/interface/IDataBaseConnection.hpp new file mode 100644 index 0000000..1e791bf --- /dev/null +++ b/source/Backend/DataBase/interface/IDataBaseConnection.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "sqlite3.h" + +namespace dataBase::interface { +class IDataBaseConnection { + public: + virtual ~IDataBaseConnection() = default; + + virtual void executeQuery(const std::string &query) = 0; + virtual std::vector executeQueryAndGetData( + const std::string &query) = 0; +}; +}; // namespace dataBase::interface diff --git a/source/Backend/DataBase/interface/IDataBaseManager.hpp b/source/Backend/DataBase/interface/IDataBaseManager.hpp new file mode 100644 index 0000000..3586e33 --- /dev/null +++ b/source/Backend/DataBase/interface/IDataBaseManager.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +#include "../common/DataBaseRequest.hpp" + +namespace dataBase::interface { +class IDataBaseManager { + public: + virtual ~IDataBaseManager() = default; + + virtual void executeOperation(const common::DataBaseRequest &requestData) = 0; + virtual std::vector executeAndGetOperation( + const common::DataBaseRequest &requestData) = 0; +}; +} // namespace dataBase::interface diff --git a/source/Backend/DataBase/interface/IQueryOperationBuilder.hpp b/source/Backend/DataBase/interface/IQueryOperationBuilder.hpp new file mode 100644 index 0000000..f00d8ee --- /dev/null +++ b/source/Backend/DataBase/interface/IQueryOperationBuilder.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "../common/DataBaseCommon.hpp" +#include "../common/DataBaseRequest.hpp" + +namespace dataBase::interface { +class IQueryOperationBuilder { + public: + using Data = const std::map &; + + virtual ~IQueryOperationBuilder() = default; + + virtual std::string buildQuery( + const common::DataBaseRequest &requestData) = 0; +}; +} // namespace dataBase::interface diff --git a/source/Backend/DataBase/password-manager.db b/source/Backend/DataBase/password-manager.db index f8d1dcd..0cf04fb 100644 Binary files a/source/Backend/DataBase/password-manager.db and b/source/Backend/DataBase/password-manager.db differ diff --git a/source/Backend/main.cpp b/source/Backend/main.cpp index c360017..bdb9de2 100644 --- a/source/Backend/main.cpp +++ b/source/Backend/main.cpp @@ -1,24 +1,15 @@ +#include #include -#include "DataBase/DataBaseHandler.hpp" +#include "DataBase/DataBaseConnection.hpp" +#include "DataBase/DataBaseManager.hpp" +#include "DataBase/QueryOperationBuilder.hpp" #include "DataBase/common/DataBaseCommon.hpp" +#include "DataBase/common/DataBaseRequest.hpp" #include "PasswordManager.h" int main() { std::string password = "haslo"; PasswordManager passwordManager(password); - const std::vector passwordValues{"1", "test", "test", "test", - "test", "test", "test"}; - try { - dataBase::DataBaseHandler dataBaseHandler(dataBase::common::dataBasePath); - dataBaseHandler.insertData(dataBase::common::passwords, - dataBase::common::passwordRecords, - passwordValues); - std::cout << "dataBase is working" << std::endl; - } catch (const std::exception &e) { - std::cout << "Error occured" << std::endl; - std::cerr << "Error: " << e.what() << std::endl; - } - return 0; } diff --git a/source/Test/CMakeLists.txt b/source/Test/CMakeLists.txt index e52fd2a..c64f470 100644 --- a/source/Test/CMakeLists.txt +++ b/source/Test/CMakeLists.txt @@ -10,9 +10,12 @@ FetchContent_Declare( FetchContent_MakeAvailable(googletest) -add_executable(${TEST_NAME} test.cpp) +add_executable(${TEST_NAME} test.cpp QueryOperationBuilderTests.cpp DataBaseManagerTests.cpp) target_link_libraries(${TEST_NAME} gtest_main) -set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Test") +target_link_libraries(${TEST_NAME} gmock_main) + +set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test") +target_sources(PasswordManager-UT PRIVATE ../Backend/DataBase/QueryOperationBuilder.cpp ../Backend/DataBase/DataBaseManager.cpp) include(GoogleTest) gtest_discover_tests(${TEST_NAME}) diff --git a/source/Test/DataBaseManagerTests.cpp b/source/Test/DataBaseManagerTests.cpp new file mode 100644 index 0000000..2b739ff --- /dev/null +++ b/source/Test/DataBaseManagerTests.cpp @@ -0,0 +1,100 @@ +#include "../Backend/DataBase/DataBaseManager.hpp" +#include "../Backend/DataBase/common/DataBaseRequest.hpp" +#include "gtest/gtest.h" +#include "mocks/DataBaseConnectionMock.hpp" +#include "mocks/QueryOperationBuilderMock.hpp" + +namespace dataBase::ut { +using namespace dataBase::mock; +using namespace dataBase::common; +using namespace testing; + +class DataBaseManagerTest : public Test { + protected: + void SetUp() override { + dataBaseConnectionMock_ = std::make_shared(); + queryOperationBuilderMock_ = std::make_shared(); + + sut_ = std::make_shared(dataBaseConnectionMock_, + queryOperationBuilderMock_); + } + + protected: + std::shared_ptr dataBaseConnectionMock_; + std::shared_ptr queryOperationBuilderMock_; + std::shared_ptr sut_; +}; + +TEST_F(DataBaseManagerTest, shouldExecuteOperation) { + DataBaseRequest request{DataBaseRequest::OperationType::Insert}; + + EXPECT_CALL(*queryOperationBuilderMock_, buildQuery(_)) + .WillOnce(Return("expected_query")); + EXPECT_CALL(*dataBaseConnectionMock_, executeQuery("expected_query")) + .Times(1); + + sut_->executeOperation(request); +} + +TEST_F(DataBaseManagerTest, shouldNotExecuteOperationWhenSelectOperationType) { + DataBaseRequest request{DataBaseRequest::OperationType::Select}; + + EXPECT_CALL(*queryOperationBuilderMock_, buildQuery(_)) + .WillOnce(Return("expected_query")); + EXPECT_CALL(*dataBaseConnectionMock_, executeQuery(_)).Times(0); + + sut_->executeOperation(request); +} + +TEST_F(DataBaseManagerTest, shouldNotExecuteOperationWhenQueryIsEmpty) { + DataBaseRequest request{DataBaseRequest::OperationType::Insert}; + + EXPECT_CALL(*queryOperationBuilderMock_, buildQuery(_)).WillOnce(Return("")); + EXPECT_CALL(*dataBaseConnectionMock_, executeQuery(_)).Times(0); + + sut_->executeOperation(request); +} + +TEST_F(DataBaseManagerTest, shouldExecuteAndGetOperation) { + DataBaseRequest request{DataBaseRequest::OperationType::Select}; + std::vector expectedResult{"UserName", "UserPassword"}; + EXPECT_CALL(*queryOperationBuilderMock_, buildQuery(_)) + .WillOnce(Return("expected_query")); + EXPECT_CALL(*dataBaseConnectionMock_, + executeQueryAndGetData("expected_query")) + .WillOnce(Return(expectedResult)); + + auto result = sut_->executeAndGetOperation(request); + + EXPECT_EQ(result, expectedResult); +} + +TEST_F(DataBaseManagerTest, + shouldNotExecuteAndGetOperationWhenOperationTypeIsNotEquelSelect) { + DataBaseRequest request{DataBaseRequest::OperationType::Insert}; + + EXPECT_CALL(*queryOperationBuilderMock_, buildQuery(_)) + .WillOnce(Return("expected_query")); + EXPECT_CALL(*dataBaseConnectionMock_, + executeQueryAndGetData("expected_query")) + .Times(0); + + auto result = sut_->executeAndGetOperation(request); + + EXPECT_TRUE(result.empty()); +} + +TEST_F(DataBaseManagerTest, shouldNotExecuteAndGetOperationWhenQueryIsEmpty) { + DataBaseRequest request{DataBaseRequest::OperationType::Select}; + + EXPECT_CALL(*queryOperationBuilderMock_, buildQuery(_)).WillOnce(Return("")); + EXPECT_CALL(*dataBaseConnectionMock_, + executeQueryAndGetData("expected_query")) + .Times(0); + + auto result = sut_->executeAndGetOperation(request); + + EXPECT_TRUE(result.empty()); +} + +} // namespace dataBase::ut diff --git a/source/Test/QueryOperationBuilderTests.cpp b/source/Test/QueryOperationBuilderTests.cpp new file mode 100644 index 0000000..a89b2fc --- /dev/null +++ b/source/Test/QueryOperationBuilderTests.cpp @@ -0,0 +1,121 @@ +#include + +#include "../Backend/DataBase/QueryOperationBuilder.hpp" +#include "../Backend/DataBase/common/DataBaseRequest.hpp" +#include "gtest/gtest.h" +namespace dataBase::ut { +TEST(QueryOperationBuilderTest, shouldBuildInsertQuery) { + auto sut = std::make_shared(); + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + std::string expectedResult{ + "INSERT INTO Users (Password, Username) VALUES ('examplePassword', " + "'exampleLogin');"}; + dataBase::common::DataBaseRequest request{ + dataBase::common::DataBaseRequest::OperationType::Insert, + dataBase::common::DataBaseRequest::TableType::Users, data}; + + ASSERT_EQ(sut->buildQuery(request), expectedResult); +} + +TEST(QueryOperationBuilderTest, shouldBuildUpdateQuery) { + auto sut = std::make_shared(); + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + std::pair primaryKey{"User_Id", "1"}; + std::string expectedResult{ + "UPDATE Users SET Password='examplePassword', Username='exampleLogin' " + "WHERE User_Id='1';"}; + dataBase::common::DataBaseRequest request{ + dataBase::common::DataBaseRequest::OperationType::Update, + dataBase::common::DataBaseRequest::TableType::Users, data, primaryKey}; + + ASSERT_EQ(sut->buildQuery(request), expectedResult); +} + +TEST(QueryOperationBuilderTest, shouldBuildDeleteQuery) { + auto sut = std::make_shared(); + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + std::pair primaryKey{"User_Id", "1"}; + + std::string expectedResult{"DELETE FROM Users WHERE User_Id='1';"}; + dataBase::common::DataBaseRequest request{ + dataBase::common::DataBaseRequest::OperationType::Delete, + dataBase::common::DataBaseRequest::TableType::Users, data, primaryKey}; + + ASSERT_EQ(sut->buildQuery(request), expectedResult); +} + +TEST(QueryOperationBuilderTest, shouldBuildSelectQuery) { + auto sut = std::make_shared(); + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + std::pair primaryKey{"User_Id", "1"}; + std::string expectedResult{"SELECT * FROM Users WHERE User_Id='1';"}; + dataBase::common::DataBaseRequest request{ + dataBase::common::DataBaseRequest::OperationType::Select, + dataBase::common::DataBaseRequest::TableType::Users, data, primaryKey}; + + ASSERT_EQ(sut->buildQuery(request), expectedResult); +} + +TEST(QueryOperationBuilderTest, + shouldNotBuildQueryWhenInvalidPrimaryKeyIsInvalid) { + auto sut = std::make_shared(); + + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + dataBase::common::DataBaseRequest request{ + dataBase::common::DataBaseRequest::OperationType::Select, + dataBase::common::DataBaseRequest::TableType::Users, data}; + + ASSERT_EQ(sut->buildQuery(request), ""); +} + +TEST(QueryOperationBuilderTest, shouldNotBuildQueryWhenDataIsEmpty) { + auto sut = std::make_shared(); + + std::pair primaryKey{"User_Id", "1"}; + + dataBase::common::DataBaseRequest request; + request.operationType_ = + dataBase::common::DataBaseRequest::OperationType::Insert, + request.tableType_ = dataBase::common::DataBaseRequest::TableType::Users; + request.primaryKey_ = primaryKey; + + ASSERT_EQ(sut->buildQuery(request), ""); +} + +TEST(QueryOperationBuilderTest, shouldNotBuildQueryWhenTableNameIsInvalid) { + auto sut = std::make_shared(); + + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + std::pair primaryKey{"User_Id", "1"}; + + dataBase::common::DataBaseRequest request; + request.operationType_ = + dataBase::common::DataBaseRequest::OperationType::Select; + request.data_ = data; + request.primaryKey_ = primaryKey; + + ASSERT_EQ(sut->buildQuery(request), ""); +} + +TEST(QueryOperationBuilderTest, shouldNotBuildQueryWhenOperationTypeIsInvalid) { + auto sut = std::make_shared(); + + std::map data{{"Username", "exampleLogin"}, + {"Password", "examplePassword"}}; + std::pair primaryKey{"User_Id", "1"}; + + dataBase::common::DataBaseRequest request; + request.tableType_ = dataBase::common::DataBaseRequest::TableType::Users; + request.data_ = data; + request.primaryKey_ = primaryKey; + + ASSERT_EQ(sut->buildQuery(request), ""); +} + +} // namespace dataBase::ut diff --git a/source/Test/mocks/DataBaseConnectionMock.hpp b/source/Test/mocks/DataBaseConnectionMock.hpp new file mode 100644 index 0000000..3893655 --- /dev/null +++ b/source/Test/mocks/DataBaseConnectionMock.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "../../Backend/DataBase/interface/IDataBaseConnection.hpp" +#include "gmock/gmock.h" + +namespace dataBase::mock { +class DataBaseConnectionMock : public interface::IDataBaseConnection { + public: + MOCK_METHOD(void, executeQuery, (const std::string &), (override)); + MOCK_METHOD(std::vector, executeQueryAndGetData, + (const std::string &), (override)); +}; +} // namespace dataBase::mock diff --git a/source/Test/mocks/DataBaseManagerMock.hpp b/source/Test/mocks/DataBaseManagerMock.hpp new file mode 100644 index 0000000..83ef1a9 --- /dev/null +++ b/source/Test/mocks/DataBaseManagerMock.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "../../Backend/DataBase/interface/IDataBaseManager.hpp" +#include "gmock/gmock.h" + +namespace dataBase::mock { +class DataBaseManagerMock : public interface::IDataBaseManager { + public: + MOCK_METHOD(void, executeOperation, (const common::DataBaseRequest &), + (override)); + MOCK_METHOD(std::vector, executeAndGetOperation, + (const common::DataBaseRequest &), (override)); +}; +} // namespace dataBase::mock diff --git a/source/Test/mocks/QueryOperationBuilderMock.hpp b/source/Test/mocks/QueryOperationBuilderMock.hpp new file mode 100644 index 0000000..f3ce45f --- /dev/null +++ b/source/Test/mocks/QueryOperationBuilderMock.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "../../Backend/DataBase/interface/IQueryOperationBuilder.hpp" +#include "gmock/gmock.h" + +namespace dataBase::mock { +class QueryOperationBuilderMock : public interface::IQueryOperationBuilder { + public: + MOCK_METHOD(std::string, buildQuery, + (const common::DataBaseRequest &requestData), (override)); +}; +} // namespace dataBase::mock