diff --git a/.github/workflows/analysis-reviewdog-cppcheck.yml b/.github/workflows/analysis-reviewdog-cppcheck.yml index bca1d0578bb..33a6ff4adeb 100644 --- a/.github/workflows/analysis-reviewdog-cppcheck.yml +++ b/.github/workflows/analysis-reviewdog-cppcheck.yml @@ -5,9 +5,11 @@ on: pull_request: paths: - "src/**" + - "tests/**/*.cpp" push: paths: - "src/**" + - "tests/**/*.cpp" jobs: cppcheck: diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index b91216e62ad..ec708a22944 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -7,10 +7,12 @@ on: types: [opened, synchronize, reopened, ready_for_review] paths: - "src/**" + - "tests/**/*.cpp" merge_group: push: paths: - "src/**" + - "tests/**/*.cpp" branches: - main diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index ff9b1bd1cdf..b8080ff8395 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -7,10 +7,12 @@ on: types: [opened, synchronize, reopened, ready_for_review] paths: - "src/**" + - "tests/**/*.cpp" merge_group: push: paths: - "src/**" + - "tests/**/*.cpp" branches: - main diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 692bafc331c..900f89335ff 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -7,10 +7,12 @@ on: types: [opened, synchronize, reopened, ready_for_review] paths: - "src/**" + - "tests/**/*.cpp" merge_group: push: paths: - "src/**" + - "tests/**/*.cpp" branches: - main diff --git a/.github/workflows/build-windows-cmake.yml b/.github/workflows/build-windows-cmake.yml index ab0accc857b..7f2e5f4f815 100644 --- a/.github/workflows/build-windows-cmake.yml +++ b/.github/workflows/build-windows-cmake.yml @@ -6,10 +6,12 @@ on: types: [opened, synchronize, reopened, ready_for_review] paths: - "src/**" + - "tests/**/*.cpp" merge_group: push: paths: - "src/**" + - "tests/**/*.cpp" branches: - main env: diff --git a/.github/workflows/build-windows-solution.yml b/.github/workflows/build-windows-solution.yml index f662fa91607..0a12f78341e 100644 --- a/.github/workflows/build-windows-solution.yml +++ b/.github/workflows/build-windows-solution.yml @@ -7,10 +7,12 @@ on: types: [opened, synchronize, reopened, ready_for_review] paths: - "src/**" + - "tests/**/*.cpp" merge_group: push: paths: - "src/**" + - "tests/**/*.cpp" branches: - main diff --git a/.github/workflows/clang-lint.yml b/.github/workflows/clang-lint.yml index b57e407cbb9..7dd7ca1aea1 100644 --- a/.github/workflows/clang-lint.yml +++ b/.github/workflows/clang-lint.yml @@ -4,10 +4,12 @@ on: pull_request: paths: - "src/**" + - "tests/**/*.cpp" merge_group: push: paths: - "src/**" + - "tests/**/*.cpp" jobs: cancel-runs: if: github.event_name == 'pull_request' && github.ref != 'refs/heads/main' @@ -39,7 +41,7 @@ jobs: if: ${{ github.ref != 'refs/heads/main' }} uses: DoozyX/clang-format-lint-action@v0.17 with: - source: "src" + source: "src tests" exclude: "src/protobuf" extensions: "cpp,hpp,h" clangFormatVersion: 17 diff --git a/CMakeLists.txt b/CMakeLists.txt index d7fb88e1fd8..dcb9b6a1879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,5 +106,9 @@ option(RUN_TESTS_AFTER_BUILD "Run tests when building" OFF) # By default, tests add_subdirectory(src) if(BUILD_TESTS OR PACKAGE_TESTS) + log_option_enabled("tests") add_subdirectory(tests) + add_compile_definitions(BUILD_TESTS) +else() + log_option_disabled("tests") endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d35631ff2fa..70f14d61356 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,26 +5,33 @@ enable_testing() function(setup_test TARGET_NAME DIR) add_executable(${TARGET_NAME} main.cpp) - target_compile_definitions(${TARGET_NAME} PUBLIC -DDEBUG_LOG) + target_compile_definitions(${TARGET_NAME} PUBLIC -DDEBUG_LOG -DBUILD_TESTS) target_link_libraries(${TARGET_NAME} PRIVATE Boost::ut ${PROJECT_NAME}_lib) target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/tests/fixture PRIVATE ${CMAKE_SOURCE_DIR}/tests/${DIR}) - if(SPEED_UP_BUILD_UNITY AND (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR CMAKE_BUILD_TYPE STREQUAL "Release")) - set_target_properties(${TARGET_NAME} PROPERTIES UNITY_BUILD ON) - log_option_enabled("Build unity for speed up compilation for target ${TARGET_NAME}") - else() - log_option_disabled("Build unity") - endif() + setup_target(${TARGET_NAME}) + + set_target_properties(${TARGET_NAME} PROPERTIES + UNITY_BUILD OFF + INTERPROCEDURAL_OPTIMIZATION OFF + ) + log_option_disabled("Build unity") configure_linking(${TARGET_NAME}) - add_test(NAME ${DIR} COMMAND ${TARGET_NAME}) + add_test(NAME ${DIR} COMMAND ${TARGET_NAME} --reporter console --success) + set_tests_properties(${DIR} PROPERTIES + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests/${DIR} + ENVIRONMENT "CATCH_CONFIG_CONSOLE_WIDTH=160" + TIMEOUT 120 + ) + if(RUN_TESTS_AFTER_BUILD) add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_CTEST_COMMAND} --verbose + COMMAND ${CMAKE_CTEST_COMMAND} -C $ --output-on-failure --tests-regex "^${DIR}$" COMMENT "Running ctest ${DIR} after building ${TARGET_NAME}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests/${DIR} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) endif (RUN_TESTS_AFTER_BUILD) endfunction() diff --git a/tests/fixture/account/in_memory_account_repository.hpp b/tests/fixture/account/in_memory_account_repository.hpp index d86d6a483be..458b5bdaeb1 100644 --- a/tests/fixture/account/in_memory_account_repository.hpp +++ b/tests/fixture/account/in_memory_account_repository.hpp @@ -30,6 +30,9 @@ namespace tests { } void addAccount(const std::string &descriptor, const AccountInfo &acc) { + phmap::erase_if(accounts, [&](const auto &entry) { + return entry.second.id == acc.id; + }); accounts[descriptor] = acc; } diff --git a/tests/integration/main.cpp b/tests/integration/main.cpp index 019c385243d..502b2ac544f 100644 --- a/tests/integration/main.cpp +++ b/tests/integration/main.cpp @@ -56,9 +56,9 @@ int main() { std::string database = "otservbr-global"; uint32_t port = 3306; std::string sock; - }; - Database db{}; - DbConfig dbConfig{}; + }; + Database db {}; + DbConfig dbConfig {}; db.connect( &dbConfig.host, @@ -70,8 +70,8 @@ int main() { ); test("AccountRepositoryDB::loadByID") = databaseTest(db, [&db] { - InMemoryLogger logger{}; - AccountRepositoryDB accRepo{}; + InMemoryLogger logger {}; + AccountRepositoryDB accRepo {}; createAccount(db); auto acc = std::make_unique(); @@ -104,8 +104,8 @@ int main() { }); test("AccountRepositoryDB load sets premium day purchased = remaining days, if needed") = databaseTest(db, [&db] { - InMemoryLogger logger{}; - AccountRepositoryDB accRepo{}; + InMemoryLogger logger {}; + AccountRepositoryDB accRepo {}; auto acc = std::make_unique(); accRepo.loadByID(1, acc); diff --git a/tests/unit/account/account_test.cpp b/tests/unit/account/account_test.cpp index 00c8f301ed3..aacb661a3d1 100644 --- a/tests/unit/account/account_test.cpp +++ b/tests/unit/account/account_test.cpp @@ -17,7 +17,6 @@ #include "enums/account_type.hpp" #include "enums/account_errors.hpp" #include "enums/account_group_type.hpp" -#include "utils/tools.hpp" using namespace boost::ut; using namespace std; @@ -36,7 +35,23 @@ bool eqEnum(const T &lhs, const U &rhs) { } suite<"account"> accountTest = [] { - InjectionFixture injectionFixture {}; + // DI setup once + static di::extension::injector<> injector {}; + tests::InMemoryAccountRepository::install(injector); + InMemoryLogger::install(injector); + DI::setTestContainer(&injector); + + auto &repo_if = injector.create(); + auto* accountRepository = &dynamic_cast(repo_if); + auto* logger = &dynamic_cast(injector.create()); + + auto withFresh = [accountRepository, logger](const char* name, auto fn) { + test(name) = [fn, accountRepository, logger] { + accountRepository->reset(); + logger->logs.clear(); + fn(); + }; + }; test("Account::Account default constructors") = [] { shared_ptr byId = make_shared(1); @@ -56,193 +71,168 @@ suite<"account"> accountTest = [] { }; struct AccountLoadTestCase { - string description; + const char* description; shared_ptr account; AccountErrors_t expectedError; }; - vector accountLoadTestCases { + static vector accountLoadTestCases { { "returns by id if exists", make_shared(1), AccountErrors_t::Ok }, { "returns by descriptor if exists", make_shared("canary@test.com"), AccountErrors_t::Ok }, { "returns error if id is not valid", make_shared(2), AccountErrors_t::LoadingAccount }, { "returns error if descriptor is not valid", make_shared("not@valid.com"), AccountErrors_t::LoadingAccount } }; - for (auto &testCase : accountLoadTestCases) { - test(testCase.description) = [&injectionFixture, &testCase] { - auto [accountRepository] = injectionFixture.get(); - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + for (const auto &testCase : accountLoadTestCases) { + withFresh(testCase.description, [testCase, accountRepository] { + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(testCase.account->load(), testCase.expectedError)) << testCase.description; - }; + }); } test("Account::reload returns error if not yet loaded") = [] { expect(eqEnum(Account { 1 }.reload(), AccountErrors_t::NotInitialized)); }; - test("Account::reload reloads account info") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); - + withFresh("Account::reload reloads account info", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.getAccountType(), AccountType::ACCOUNT_TYPE_GOD)); - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GAMEMASTER }); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GAMEMASTER }); expect(eqEnum(acc.reload(), AccountErrors_t::Ok)); expect(eqEnum(acc.getAccountType(), AccountType::ACCOUNT_TYPE_GAMEMASTER)); - }; + }); test("Account::save returns error if not yet loaded") = [] { expect(eqEnum(Account { 1 }.save(), AccountErrors_t::NotInitialized)); }; - test("Account::save returns error if it fails") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); - + withFresh("Account::save returns error if it fails", [accountRepository] { Account acc { 1 }; - accountRepository.failSave = true; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->failSave = true; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.save(), AccountErrors_t::Storage)); - }; - - test("Account::save saves account info") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::save saves account info", [accountRepository] { Account acc { 1 }; - accountRepository.failSave = false; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->failSave = false; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.save(), AccountErrors_t::Ok)); - }; + }); - test("Account::getCoins returns error if not yet loaded") = [&injectionFixture] { + withFresh("Account::getCoins returns error if not yet loaded", [accountRepository] { expect(eqEnum(std::get<1>(Account { 1 }.getCoins(CoinType::Normal)), AccountErrors_t::NotInitialized)); - }; - - test("Account::getCoins returns error if it fails") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getCoins returns error if it fails", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Storage)); - }; - - test("Account::getCoins returns coins") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getCoins returns coins", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 100)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); - }; - - test("Account::getCoins returns coins for specified account only") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getCoins returns coins for specified account only", [accountRepository] { Account acc { 2 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); - accountRepository.addAccount("canary2@test.com", AccountInfo { 2, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(2, CoinType::Normal, 33); + accountRepository->addAccount("canary2@test.com", AccountInfo { 2, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(2, CoinType::Normal, 33); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 33)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); - }; - - test("Account::getCoins returns coins for specified coin type only") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getCoins returns coins for specified coin type only", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); - accountRepository.setCoins(1, CoinType::Tournament, 100); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); + accountRepository->setCoins(1, CoinType::Tournament, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 100)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Tournament)), 100)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Tournament)), AccountErrors_t::Ok)); - }; + }); test("Account::addCoins returns error if not yet loaded") = [] { expect(eqEnum(Account { 1 }.addCoins(CoinType::Normal, 100), AccountErrors_t::NotInitialized)); }; - test("Account::addCoins returns error if it fails") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); - + withFresh("Account::addCoins returns error if it fails", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = true; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->failAddCoins = true; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.addCoins(CoinType::Normal, 100), AccountErrors_t::Storage)); - }; - - test("Account::addCoins returns error if get coins fail") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::addCoins returns error if get coins fail", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.addCoins(CoinType::Tournament, 100), AccountErrors_t::Storage)); - }; - - test("Account::addCoins adds coins") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::addCoins adds coins", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = false; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->failAddCoins = false; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.addCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 200)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); - }; - - test("Account::addCoins adds coins for specified account only") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::addCoins adds coins for specified account only", [accountRepository] { Account acc { 2 }; - accountRepository.failAddCoins = false; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->failAddCoins = false; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); - accountRepository.addAccount("canary2@test.com", AccountInfo { 2, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(2, CoinType::Normal, 33); + accountRepository->addAccount("canary2@test.com", AccountInfo { 2, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(2, CoinType::Normal, 33); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.addCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 133)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); - }; - - test("Account::addCoins adds coins for specified coin type only") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::addCoins adds coins for specified coin type only", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = false; - accountRepository.setCoins(1, CoinType::Normal, 100); - accountRepository.setCoins(1, CoinType::Tournament, 57); - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->failAddCoins = false; + accountRepository->setCoins(1, CoinType::Normal, 100); + accountRepository->setCoins(1, CoinType::Tournament, 57); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.addCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); @@ -251,82 +241,72 @@ suite<"account"> accountTest = [] { expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Tournament)), 57)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Tournament)), AccountErrors_t::Ok)); - expect(eq(accountRepository.coinsTransactions_.size(), 1) >> fatal); - expect(eq(accountRepository.coinsTransactions_[1].size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_.size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_[1].size(), 1) >> fatal); - auto [type, coins, coinType, description] = accountRepository.coinsTransactions_[1][0]; + auto [type, coins, coinType, description] = accountRepository->coinsTransactions_[1][0]; expect(eq(coins, 100)); expect(eqEnum(coinType, CoinType::Normal)); expect(eqEnum(type, CoinTransactionType::Add)); expect(eq(description, std::string { "ADD Coins" })); - }; + }); test("Account::removeCoins returns error if not yet loaded") = [] { expect(eqEnum(Account { 1 }.removeCoins(CoinType::Normal, 100), AccountErrors_t::NotInitialized)); }; - test("Account::removeCoins returns error if it fails") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); - + withFresh("Account::removeCoins returns error if it fails", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = true; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->failAddCoins = true; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::Storage)); - }; - - test("Account::removeCoins returns error if get coins fail") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::removeCoins returns error if get coins fail", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Tournament, 100), AccountErrors_t::Storage)); - }; - - test("Account::removeCoins removes coins") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::removeCoins removes coins", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = false; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->failAddCoins = false; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 0)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); - }; - - test("Account::removeCoins removes coins for specified account only") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::removeCoins removes coins for specified account only", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = false; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->failAddCoins = false; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); - accountRepository.addAccount("canary2@test.com", AccountInfo { 2, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(2, CoinType::Normal, 33); + accountRepository->addAccount("canary2@test.com", AccountInfo { 2, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(2, CoinType::Normal, 33); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Normal)), 0)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Normal)), AccountErrors_t::Ok)); - }; - - test("Account::removeCoins removes coins for specified coin type only") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::removeCoins removes coins for specified coin type only", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = false; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); - accountRepository.setCoins(1, CoinType::Normal, 100); - accountRepository.setCoins(1, CoinType::Tournament, 57); + accountRepository->failAddCoins = false; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->setCoins(1, CoinType::Normal, 100); + accountRepository->setCoins(1, CoinType::Tournament, 57); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); @@ -335,38 +315,36 @@ suite<"account"> accountTest = [] { expect(eqEnum(std::get<0>(acc.getCoins(CoinType::Tournament)), 57)); expect(eqEnum(std::get<1>(acc.getCoins(CoinType::Tournament)), AccountErrors_t::Ok)); - expect(eq(accountRepository.coinsTransactions_.size(), 1) >> fatal); - expect(eq(accountRepository.coinsTransactions_[1].size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_.size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_[1].size(), 1) >> fatal); - auto [type, coins, coinType, description] = accountRepository.coinsTransactions_[1][0]; + auto [type, coins, coinType, description] = accountRepository->coinsTransactions_[1][0]; expect(eq(coins, 100)); expect(eqEnum(coinType, CoinType::Normal)); expect(eqEnum(type, CoinTransactionType::Remove)); expect(eq(description, std::string { "REMOVE Coins" })); - }; - - test("Account::removeCoins returns error if account doesn't have enough coins") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::removeCoins returns error if account doesn't have enough coins", [accountRepository] { Account acc { 1 }; - accountRepository.failAddCoins = false; - accountRepository.setCoins(1, CoinType::Normal, 1); - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->failAddCoins = false; + accountRepository->setCoins(1, CoinType::Normal, 1); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::RemoveCoins)); - accountRepository.setCoins(1, CoinType::Normal, 50); + accountRepository->setCoins(1, CoinType::Normal, 50); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::RemoveCoins)); - accountRepository.setCoins(1, CoinType::Normal, 100); + accountRepository->setCoins(1, CoinType::Normal, 100); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::Ok)); - expect(eq(accountRepository.coinsTransactions_.size(), 1) >> fatal); - expect(eq(accountRepository.coinsTransactions_[1].size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_.size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_[1].size(), 1) >> fatal); - auto [type, coins, coinType, description] = accountRepository.coinsTransactions_[1][0]; + auto [type, coins, coinType, description] = accountRepository->coinsTransactions_[1][0]; expect(eq(coins, 100)); expect(eqEnum(coinType, CoinType::Normal)); expect(eqEnum(type, CoinTransactionType::Remove)); @@ -375,17 +353,15 @@ suite<"account"> accountTest = [] { expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 100), AccountErrors_t::RemoveCoins)); - expect(eq(accountRepository.coinsTransactions_.size(), 1) >> fatal); - expect(eq(accountRepository.coinsTransactions_[1].size(), 1) >> fatal); - }; - - test("Account::registerCoinTransaction does nothing if detail is empty") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + expect(eq(accountRepository->coinsTransactions_.size(), 1) >> fatal); + expect(eq(accountRepository->coinsTransactions_[1].size(), 1) >> fatal); + }); + withFresh("Account::registerCoinTransaction does nothing if detail is empty", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); - accountRepository.setCoins(1, CoinType::Normal, 1); + accountRepository->setCoins(1, CoinType::Normal, 1); expect(eqEnum(acc.addCoins(CoinType::Normal, 100, ""), AccountErrors_t::Ok)); expect(eqEnum(acc.removeCoins(CoinType::Normal, 80, ""), AccountErrors_t::Ok)); @@ -396,35 +372,31 @@ suite<"account"> accountTest = [] { acc.registerCoinTransaction(CoinTransactionType::Add, CoinType::Normal, 100, ""); acc.registerCoinTransaction(CoinTransactionType::Remove, CoinType::Normal, 100, ""); - expect(eq(accountRepository.coinsTransactions_.size(), 0)); - }; + expect(eq(accountRepository->coinsTransactions_.size(), 0)); + }); test("Account::getPassword returns empty string if not yet loaded") = [] { expect(eqEnum(Account { 1 }.getPassword(), std::string { "" })); }; - test("Account::getPassword returns password") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); - + withFresh("Account::getPassword returns password", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eq(acc.getPassword(), std::string { "123456" })); - }; - - test("Account::getPassword returns logs error if it fails") = [&injectionFixture] { - auto [logger, accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getPassword returns logs error if it fails", [accountRepository, logger] { Account acc { 1 }; - accountRepository.failGetPassword = true; - accountRepository.addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); + accountRepository->failGetPassword = true; + accountRepository->addAccount("canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD }); expect(eqEnum(acc.load(), AccountErrors_t::Ok)); expect(eq(std::string {}, acc.getPassword())); - expect(eq(std::string { "error" }, logger.logs[0].level)); - expect(eq(std::string { "Failed to get password for account[1]!" }, logger.logs[0].message)); - }; + expect(eq(std::string { "error" }, logger->logs[0].level)); + expect(eq(std::string { "Failed to get password for account[1]!" }, logger->logs[0].message)); + }); test("Account::addPremiumDays sets premium remaining days") = [] { Account acc { 1 }; @@ -508,11 +480,9 @@ suite<"account"> accountTest = [] { expect(eqEnum(std::get<1>(Account { 1 }.getAccountPlayers()), AccountErrors_t::NotInitialized)); }; - test("Account::getAccountPlayer returns players") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); - + withFresh("Account::getAccountPlayer returns players", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount( + accountRepository->addAccount( "canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD, { { "Canary", 1 }, { "Canary2", 2 } } } ); @@ -524,60 +494,52 @@ suite<"account"> accountTest = [] { expect(eq(players.size(), 2)); expect(eq(players["Canary"], 1)); expect(eq(players["Canary2"], 2)); - }; - - test("Account::authenticate password using sha1") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::authenticate password using sha1", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount( + accountRepository->addAccount( "canary@test.com", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD, { { "Canary", 1 }, { "Canary2", 2 } } } ); expect(acc.load() == AccountErrors_t::Ok); - accountRepository.password_ = "7c4a8d09ca3762af61e59520943dc26494f8941b"; + accountRepository->password_ = "7c4a8d09ca3762af61e59520943dc26494f8941b"; expect(acc.authenticate("123456")); - }; - - test("Account::authenticate using sessions") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::authenticate using sessions", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount( + accountRepository->addAccount( "session-key", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD, { { "Canary", 1 }, { "Canary2", 2 } }, false, getTimeNow() + 24 * 60 * 60 * 1000 } ); expect(acc.load() == AccountErrors_t::Ok); expect(acc.authenticate()); - }; - - test("Account::getCharacterByAccountIdAndName using an account with the given character.") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getCharacterByAccountIdAndName using an account with the given character.", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount( + accountRepository->addAccount( "session-key", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD, { { "Canary", 1 }, { "Canary2", 2 } }, false, getTimeNow() + 24 * 60 * 60 * 1000 } ); - const auto hasCharacter = accountRepository.getCharacterByAccountIdAndName(1, "Canary"); + const auto hasCharacter = accountRepository->getCharacterByAccountIdAndName(1, "Canary"); expect(hasCharacter); - }; - - test("Account::getCharacterByAccountIdAndName using an account without the given character.") = [&injectionFixture] { - auto [accountRepository] = injectionFixture.get(); + }); + withFresh("Account::getCharacterByAccountIdAndName using an account without the given character.", [accountRepository] { Account acc { 1 }; - accountRepository.addAccount( + accountRepository->addAccount( "session-key", AccountInfo { 1, 1, 1, AccountType::ACCOUNT_TYPE_GOD, { { "Canary", 1 }, { "Canary2", 2 } }, false, getTimeNow() + 24 * 60 * 60 * 1000 } ); - const auto hasCharacter = accountRepository.getCharacterByAccountIdAndName(1, "Invalid"); + const auto hasCharacter = accountRepository->getCharacterByAccountIdAndName(1, "Invalid"); expect(!hasCharacter); - }; + }); }; diff --git a/tests/unit/server/network/message/networkmessage_test.cpp b/tests/unit/server/network/message/networkmessage_test.cpp index f1ec904a3bf..6901fbeb984 100644 --- a/tests/unit/server/network/message/networkmessage_test.cpp +++ b/tests/unit/server/network/message/networkmessage_test.cpp @@ -13,8 +13,8 @@ using namespace boost::ut; suite<"networkmessage"> networkMessageTest = [] { di::extension::injector<> injector {}; DI::setTestContainer(&InMemoryLogger::install(injector)); - auto& logger = dynamic_cast(injector.create()); - + auto &logger = dynamic_cast(injector.create()); + test("NetworkMessage::addByte and getByte") = [&]() { NetworkMessage msg; uint8_t byteToAdd = 100; @@ -84,11 +84,11 @@ suite<"networkmessage"> networkMessageTest = [] { NetworkMessage msg1, msg2; // Adding initial byte and string to msg1 - msg1.addByte(1); // Byte value 1 - msg1.addString("Hello"); // String value "Hello" + msg1.addByte(1); // Byte value 1 + msg1.addString("Hello"); // String value "Hello" // Adding initial byte and string to msg2 - msg2.addByte(2); // Byte value 2 - msg2.addString("World"); // String value "World" + msg2.addByte(2); // Byte value 2 + msg2.addString("World"); // String value "World" // Append msg2 to msg1 msg1.append(msg2); msg1.setBufferPosition(NetworkMessage::INITIAL_BUFFER_POSITION); // Reset read position to start @@ -136,8 +136,7 @@ suite<"networkmessage"> networkMessageTest = [] { msg.setBufferPosition(NetworkMessage::INITIAL_BUFFER_POSITION); // Verify the content of the buffer before extracting the data auto buffer = msg.getBuffer(); - std::string extractedData(buffer + NetworkMessage::INITIAL_BUFFER_POSITION, - buffer + NetworkMessage::INITIAL_BUFFER_POSITION + testData.size()); + std::string extractedData(buffer + NetworkMessage::INITIAL_BUFFER_POSITION, buffer + NetworkMessage::INITIAL_BUFFER_POSITION + testData.size()); // Check if the extracted data matches the added data expect(eq(extractedData, testData)) << "Expected the same bytes added"; }; diff --git a/tests/unit/utils/position_functions_test.cpp b/tests/unit/utils/position_functions_test.cpp index be382080434..c8064f0c7a9 100644 --- a/tests/unit/utils/position_functions_test.cpp +++ b/tests/unit/utils/position_functions_test.cpp @@ -40,8 +40,13 @@ suite<"utils"> getDirectionToTest = [] { GetDirectionToTestCase { Position { 122, 0, 0 }, Position { 0, 123, 0 }, DIRECTION_SOUTHWEST, DIRECTION_SOUTH }, }; + static std::vector test_names; + test_names.reserve(getDirectionToTestCases.size()); + for (auto getDirectionToTestCase : getDirectionToTestCases) { - test("getDirectionTo " + getDirectionToTestCase.toString()) = [getDirectionToTestCase] { + test_names.push_back("getDirectionTo " + getDirectionToTestCase.toString()); + auto &name = test_names.back(); + test(std::string_view { name }) = [getDirectionToTestCase] { auto [from, to, expected, expectedForExactDiagonal] = getDirectionToTestCase; auto result = getDirectionTo(from, to); diff --git a/tests/unit/utils/string_functions_test.cpp b/tests/unit/utils/string_functions_test.cpp index aa4860b2696..5edeb842852 100644 --- a/tests/unit/utils/string_functions_test.cpp +++ b/tests/unit/utils/string_functions_test.cpp @@ -11,24 +11,24 @@ suite<"utils"> replaceStringTest = [] { std::string subject, search, replace, expected; [[nodiscard]] std::string toString() const { - return fmt::format("replace {} in {} by {}", search, subject, replace); + return fmt::format("replace '{}' in '{}' by '{}'", search, subject, replace); } }; - std::vector replaceStringTestCases { - ReplaceStringTestCase { "", "", "", "" }, - ReplaceStringTestCase { "all together", " ", "_", "all_together" }, - ReplaceStringTestCase { "beautiful", "u", "", "beatifl" }, - ReplaceStringTestCase { "empty_empty_empty_", "empty_", "", "" }, - ReplaceStringTestCase { "I am someone", "someone", "Lucas", "I am Lucas" }, - ReplaceStringTestCase { "[[123[[[[[[124[[asf[[ccc[[[", "[[", "\\[[", "\\[[123\\[[\\[[\\[[124\\[[asf\\[[ccc\\[[[" }, + static const std::vector replaceStringTestCases { + { "", "", "", "" }, + { "all together", " ", "_", "all_together" }, + { "beautiful", "u", "", "beatifl" }, + { "empty_empty_empty_", "empty_", "", "" }, + { "I am someone", "someone", "Lucas", "I am Lucas" }, + { "[[123[[[[[[124[[asf[[ccc[[[", "[[", "\\[[", "\\[[123\\[[\\[[\\[[124\\[[asf\\[[ccc\\[[[" }, }; for (const auto &replaceStringTestCase : replaceStringTestCases) { - test(replaceStringTestCase.toString()) = [&replaceStringTestCase] { + test("replaceString") = [replaceStringTestCase] { auto [subject, search, replace, expected] = replaceStringTestCase; replaceString(subject, search, replace); - expect(eq(expected, subject)) << fmt::format("{} != {}", expected, subject); + expect(eq(expected, subject)) << fmt::format("FAILED: {}", replaceStringTestCase.toString()); }; } };