diff --git a/CMakeLists.txt b/CMakeLists.txt index c53101c..4d9f0a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,14 +10,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) if(MSVC) add_compile_options(/W4 /WX) else() - add_compile_options(-Wall -Wpedantic) + add_compile_options(-W -Wall -Werror) endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -include(CTest) enable_testing() add_subdirectory(src) diff --git a/src/core/article.cpp b/src/core/article.cpp index 3270da7..4ba0b33 100644 --- a/src/core/article.cpp +++ b/src/core/article.cpp @@ -1,17 +1,24 @@ #include "article.h" -Article::Article() : Entity() {} +Article::Article() : Entity() +{} -Article::Article(std::shared_ptr sellerPtr) : Entity() { sellerPtr_ = sellerPtr; } +Article::Article(const std::shared_ptr sellerPtr) : Entity() +{ + this->sellerPtr = sellerPtr; +} -void Article::setArticleNo(int articleNo) { articleNo_ = articleNo; } +void Article::setArticleNo(int articleNo) +{ + this->articleNo = articleNo; +} -void Article::setPrice(int price) { price_ = price; } +void Article::setPrice(int price) +{ + this->price = price; +} -void Article::setDescription(const std::string& description) { description_ = description; } - -std::string Article::getDescription() { return description_; } - -void Article::setSale(std::shared_ptr salePtr) { salePtr_ = salePtr; } - -bool Article::isSold() { return salePtr_ ? true : false; } \ No newline at end of file +void Article::setDescription(const std::string& description) +{ + this->description = description; +} \ No newline at end of file diff --git a/src/core/article.h b/src/core/article.h index 1d0487b..cc25ffa 100644 --- a/src/core/article.h +++ b/src/core/article.h @@ -2,33 +2,26 @@ #define ARTICLE_H #include "entity.h" -#include "sale.h" #include "seller.h" -#include #include +#include class Seller; class Article : public Entity { - public: +public: Article(); Article(std::shared_ptr sellerPtr); void setArticleNo(int articleNo); void setPrice(int price); void setDescription(const std::string& description); - std::string getDescription(); - bool isSold(); - void setSale(std::shared_ptr salePtr); - void setSeller(std::shared_ptr sellerPtr); - - private: - std::shared_ptr sellerPtr_{}; - std::shared_ptr salePtr_{}; - int articleNo_{}; - int price_{}; - std::string description_{}; +private: + std::shared_ptr sellerPtr{}; + int articleNo{}; + int price{}; + std::string description{}; }; #endif \ No newline at end of file diff --git a/src/core/database.cpp b/src/core/database.cpp index fc1a1c8..42603ad 100644 --- a/src/core/database.cpp +++ b/src/core/database.cpp @@ -2,40 +2,28 @@ #include #include -#include Database::Database(const std::string& dbname) : db_(nullptr) { - dbname_ = dbname; - const int errCode = sqlite3_open(dbname_.c_str(), &db_); + const int errCode = sqlite3_open(dbname.c_str(), &db_); if (errCode) { throw std::runtime_error("Could not open database file."); } - sqlite3_db_config(db_, SQLITE_DBCONFIG_ENABLE_FKEY); + exec("PRAGMA foreign_key = 1"); } Database::~Database() { sqlite3_close(db_); } void Database::exec(const std::string& sql) { - char* errMsg; - const int errCode = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &errMsg); + const int errCode = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, nullptr); if (errCode) { - std::string errMsgString(errMsg); // Make a C++ string of the errMsg, so that we can call - // sqlite3_free() before throwing the exception - sqlite3_free(errMsg); - throw std::runtime_error("Error in SQL execution: " + errMsgString); + throw std::runtime_error("Error in SQL execution."); } } -void Database::createNew() +void Database::init() { - std::vector sqlStrings{}; - - std::string sqlCreateKima2{"CREATE TABLE IF NOT EXISTS kima2 (" - "version INTEGER NOT NULL);" - "INSERT INTO kima2 (version) VALUES (1);"}; - sqlStrings.push_back(sqlCreateKima2); std::string sqlCreateSellers{"CREATE TABLE IF NOT EXISTS sellers (" "id TEXT PRIMARY KEY NOT NULL, " "seller_no INTEGER, " @@ -44,7 +32,7 @@ void Database::createNew() "offered_articles INTEGER, " "UNIQUE (seller_no)" ");"}; - sqlStrings.push_back(sqlCreateSellers); + std::string sqlCreateArticles{ "CREATE TABLE IF NOT EXISTS articles (" "id TEXT PRIMARY KEY NOT NULL, " @@ -57,90 +45,13 @@ void Database::createNew() "FOREIGN KEY (seller_id) REFERENCES sellers(id) ON DELETE CASCADE, " "CHECK (article_no BETWEEN 0 AND 99999)" ");"}; - sqlStrings.push_back(sqlCreateArticles); - std::string sqlCreateSales{"CREATE TABLE IF NOT EXISTS sales (" - " id TEXT PRIMARY KEY NOT NULL," - " source_no INTEGER NOT NULL," - " sold_at TEXT" - ");"}; - sqlStrings.push_back(sqlCreateSales); - std::string sqlCreateSalesItems{ - "CREATE TABLE IF NOT EXISTS sales_items(" - " sale_id TEXT NOT NULL," - " article_id TEXT NOT NULL," - " FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE," - " FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE" - ");"}; - sqlStrings.push_back(sqlCreateSalesItems); beginTransaction(); - for (const auto& sql : sqlStrings) { - exec(sql); - } + exec(sqlCreateSellers); + exec(sqlCreateArticles); endTransaction(); } -void Database::init() -{ - int version = getVersion(); - - switch (version) { - case 0: - createNew(); - break; - // perhaps handle upgrades for db schema here... - default: - // Do nothing because we are up-to-date. - break; - } -} - -int Database::getVersion() -{ - int retCode{}; - sqlite3_stmt* stmt; - - // Check if there's already a kima2 table available. - // If not, return version == 0. - retCode = sqlite3_prepare_v2( - db_, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='kima2';", -1, &stmt, - nullptr); - if (retCode != SQLITE_OK) - throw std::string(sqlite3_errmsg(db_)); - retCode = sqlite3_step(stmt); - if (retCode != SQLITE_ROW && retCode != SQLITE_DONE) { - std::string errMsg(sqlite3_errmsg(db_)); - sqlite3_finalize(stmt); - throw errMsg; - } else if (retCode != SQLITE_DONE) { - int count = sqlite3_column_int(stmt, 0); - sqlite3_finalize(stmt); - if (count == 0) - return 0; // no kima2 table, so version is 0 - } - - // Now that we know that the kima2 table is present, read and return the schema version. - retCode = sqlite3_prepare_v2(db_, "SELECT version FROM kima2", -1, &stmt, nullptr); - if (retCode != SQLITE_OK) - throw std::string(sqlite3_errmsg(db_)); - - retCode = sqlite3_step(stmt); - - if (retCode != SQLITE_ROW && retCode != SQLITE_DONE) { - std::string errMsg(sqlite3_errmsg(db_)); - sqlite3_finalize(stmt); - throw errMsg; - } else if (retCode == SQLITE_DONE) { - sqlite3_finalize(stmt); - return 0; // no version entry, so version is 0 - } - - int version = sqlite3_column_int(stmt, 0); - sqlite3_finalize(stmt); - - return version; -} - void Database::beginTransaction() { exec("BEGIN TRANSACTION"); } void Database::endTransaction() { exec("END TRANSACTION"); } \ No newline at end of file diff --git a/src/core/database.h b/src/core/database.h index ff6f3d8..c0b4de4 100644 --- a/src/core/database.h +++ b/src/core/database.h @@ -16,11 +16,8 @@ public: void init(); private: sqlite3 *db_; - std::string dbname_; void beginTransaction(); void endTransaction(); - void createNew(); - int getVersion(); }; #endif // DATABASE_H \ No newline at end of file diff --git a/src/core/sale.h b/src/core/sale.h deleted file mode 100644 index 06f350d..0000000 --- a/src/core/sale.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SALE_H -#define SALE_H - -class Sale : public Entity { - -}; - -#endif \ No newline at end of file diff --git a/src/core/seller.cpp b/src/core/seller.cpp index 634e585..e4de084 100644 --- a/src/core/seller.cpp +++ b/src/core/seller.cpp @@ -1,40 +1,26 @@ #include "seller.h" -Seller::Seller() : Entity() {} +void Seller::setSellerNo(int seller_no) +{ + sellerNo_ = seller_no; +} -Seller::Seller(const std::string& firstName, const std::string& lastName, int sellerNo, - int numberOfArticles) - : Entity() +void Seller::setFirstName(const std::string& firstName) { firstName_ = firstName; - lastName_ = lastName; - sellerNo_ = sellerNo; - numberOfOfferedArticles_ = numberOfArticles; } -inline void Seller::setSellerNo(int seller_no) { sellerNo_ = seller_no; } - -inline void Seller::setFirstName(const std::string& firstName) { firstName_ = firstName; } - -inline void Seller::setLastName(const std::string& lastName) { lastName_ = lastName; } - -inline void Seller::setNumberOfOfferedArticles(int number) { numberOfOfferedArticles_ = number; } - -inline size_t Seller::getNumberOfOfferedArticles() { return articles_.size(); } - -void Seller::addArticle(Article article) { - articles_.push_back(article); -} - -std::vector Seller::getArticles(bool onlySold) +void Seller::setLastName(const std::string& lastName) { - std::vector articles; - for (auto& article : articles_) { - if (onlySold && article.isSold()) { - articles.push_back(&article); - } else if (!onlySold) { - articles.push_back(&article); - } - } - return articles; + lastName_ = lastName; +} + +void Seller::setNumberOfOfferedArticles(int number) +{ + numberOfOfferedArticles_ = number; +} + +size_t Seller::getNumberOfOfferedArticles() +{ + return articles_.size(); } \ No newline at end of file diff --git a/src/core/seller.h b/src/core/seller.h index 4ac6a98..2848579 100644 --- a/src/core/seller.h +++ b/src/core/seller.h @@ -1,8 +1,8 @@ #ifndef SELLER_H #define SELLER_H -#include "article.h" #include "entity.h" +#include "article.h" #include #include @@ -12,17 +12,11 @@ class Article; class Seller : public Entity { public: - Seller(); - Seller(const std::string& firstName, const std::string& lastName, int sellerNo = 0, - int numberOfArticles = 0); - void setSellerNo(int sellerNo); void setFirstName(const std::string& firstName); void setLastName(const std::string& lastName); void setNumberOfOfferedArticles(int number); - void addArticle(Article article); - std::vector getArticles(bool onlySold = false); size_t getNumberOfOfferedArticles(); private: diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 382580f..2c68a6d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,10 +4,6 @@ add_executable(test_seller test_seller.cpp) target_link_libraries(test_seller core Boost::unit_test_framework) add_test(NAME Seller COMMAND ${CMAKE_BINARY_DIR}/bin/test_seller) -add_executable(test_article test_article.cpp) -target_link_libraries(test_article core Boost::unit_test_framework) -add_test(NAME Article COMMAND ${CMAKE_BINARY_DIR}/bin/test_article) - add_executable(test_database test_database.cpp) target_link_libraries(test_database core Boost::unit_test_framework stdc++fs) add_test(NAME Database COMMAND ${CMAKE_BINARY_DIR}/bin/test_database) diff --git a/test/test_article.cpp b/test/test_article.cpp deleted file mode 100644 index e0792ad..0000000 --- a/test/test_article.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#define BOOST_TEST_MODULE article - -#include "../src/core/article.h" - -#include - -BOOST_AUTO_TEST_CASE(create_article) -{ - Article article{}; - BOOST_TEST(article.getUuid().is_nil() == true); -} - -BOOST_AUTO_TEST_CASE(check_is_sold) -{ - Article article{}; - BOOST_TEST(article.isSold() == false); - - auto salePtr = std::make_shared(); - article.setSale(salePtr); - BOOST_TEST(article.isSold() == true); -} \ No newline at end of file diff --git a/test/test_database.cpp b/test/test_database.cpp index de5c004..28d47dc 100644 --- a/test/test_database.cpp +++ b/test/test_database.cpp @@ -8,8 +8,18 @@ BOOST_AUTO_TEST_CASE(create_database) { + std::filesystem::path testPath = std::filesystem::temp_directory_path() / "kima2test.db"; + if (std::filesystem::exists(testPath)) { + std::filesystem::remove(testPath); + } - Database db(":memory:"); - BOOST_CHECK_NO_THROW(db.init()); + std::string filename = testPath.generic_string(); + Database db(filename); + db.init(); + + BOOST_TEST(std::filesystem::exists(testPath) == true); + if (std::filesystem::exists(testPath)) { + std::filesystem::remove(testPath); + } } \ No newline at end of file diff --git a/test/test_seller.cpp b/test/test_seller.cpp index 5de2ed2..d193340 100644 --- a/test/test_seller.cpp +++ b/test/test_seller.cpp @@ -2,37 +2,17 @@ #include "../src/core/seller.h" -#include - #include -BOOST_AUTO_TEST_CASE(create_uuid_nil) -{ +//using namespace boost::unit_test; + +BOOST_AUTO_TEST_CASE( create_uuid_nil ) { Seller seller{}; BOOST_TEST(seller.getUuid().is_nil() == true); } -BOOST_AUTO_TEST_CASE(create_uuid) -{ +BOOST_AUTO_TEST_CASE(create_uuid) { Seller seller{}; seller.createUuid(); BOOST_TEST(seller.getUuid().is_nil() == false); -} - -BOOST_AUTO_TEST_CASE(create_many) -{ - constexpr unsigned int QUANTITY{10000}; - std::array sellers; - for (unsigned i = 0; i < sellers.size(); i++) { - sellers[i] = Seller(); - sellers[i].createUuid(); - } -} - -BOOST_AUTO_TEST_CASE(with_article) { - Seller seller("Max", "Mustermann"); - Article article{}; - article.setDescription("Test article"); - seller.addArticle(article); - BOOST_TEST(seller.getArticles().at(0)->getDescription() == "Test article"); } \ No newline at end of file