diff --git a/Unit testing/CMakeLists.txt b/Unit testing/CMakeLists.txt index 1e65af5..a32419e 100644 --- a/Unit testing/CMakeLists.txt +++ b/Unit testing/CMakeLists.txt @@ -4,20 +4,24 @@ project(UnitTest CXX) include(../external/catch2/extras/Catch.cmake) -add_executable(UnitTest adummy.cpp characteristics_tests.cpp) +add_executable(UnitTest adummy.cpp + characteristics_tests.cpp + ../src/billy_objects.cpp + billy_objects_tests.cpp +) -set_target_properties(Catch2 UnitTest PROPERTIES +set_target_properties(Catch2 UnitTest svector PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF - INTERPROCEDURAL_OPTIMIZATION ON + INTERPROCEDURAL_OPTIMIZATION_RELEASE ON # UNITY_BUILD ON ) target_include_directories(UnitTest PRIVATE ${CMAKE_SOURCE_DIR}/include) target_compile_definitions(UnitTest PRIVATE ${DEF_COMP}) target_compile_options(UnitTest PRIVATE ${COMPILE_FLAGS}) target_link_options(UnitTest PRIVATE ${LINKER_OPTIONS}) -target_link_libraries(UnitTest ${LINKER_FLAGS} Catch2::Catch2WithMain nlohmann_json::nlohmann_json) +target_link_libraries(UnitTest ${LINKER_FLAGS} spdlog::spdlog_header_only Catch2::Catch2WithMain nlohmann_json::nlohmann_json svector::svector) enable_testing() catch_discover_tests(UnitTest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} REPORTER junit OUTPUT_DIR ${CMAKE_SOURCE_DIR} OUTPUT_PREFIX cppspec- OUTPUT_SUFFIX .xml) diff --git a/Unit testing/billy_objects_tests.cpp b/Unit testing/billy_objects_tests.cpp new file mode 100644 index 0000000..e91159b --- /dev/null +++ b/Unit testing/billy_objects_tests.cpp @@ -0,0 +1,168 @@ +// +// Created by postaron on 29/02/24. +// +#include +#include +#include +#include "billy_objects.hpp" +#include "character_sheet.hpp" + +using namespace character; + +namespace character::test { + struct DummyObject { + BillyObjects::container objects; + }; + + void to_json(json &j, const DummyObject &a) { + j.emplace(std::pair{ BillyObjects::json_key, json::array() }); + BillyObjects::to_json(j.at(BillyObjects::json_key), a.objects); + } + + void from_json(const json &j, DummyObject &dummy) { + BillyObjects::from_json(j, dummy.objects); + } +} + +TEST_CASE("[C] Serialize empty BillyObjects", "[serialize][0]") { + CharacterSheet sheet; + json serializer; + + REQUIRE_NOTHROW(serializer.emplace("sheet", sheet)); + + const auto tester = serializer.at("sheet").at(BillyObjects::json_key); + serializer.clear(); + + REQUIRE_NOTHROW(tester.empty() == true); + REQUIRE(tester.empty()); + + { + std::ofstream file{ "billy_objects_empty.json" }; + file << tester << std::flush; + } +} + +TEST_CASE("[C] Serialize full BillyObjects", "[serialize][1]") { + BillyObjects gestionnaire{}; + test::DummyObject dummy_object; + { + CharacterSheet sheet; + gestionnaire.push_object(weapons::Sword, sheet); + gestionnaire.push_object(tools::Fourche, sheet); + gestionnaire.push_object(equipments::MedicKit, sheet); + dummy_object.objects = sheet.get_objects(); + } + + json serializer; + REQUIRE_NOTHROW(serializer.emplace("sheet", dummy_object)); + + const auto &tester = serializer.at("sheet").at(BillyObjects::json_key); + + REQUIRE_FALSE(tester.empty()); + + { + std::ofstream file{ "billy_objects_full.json" }; + file << tester << std::flush; + } +} + +TEST_CASE("[D] Deserialize empty BillyObjects", "[deserialize][0]") { + BillyObjects gestionnaire{}; + test::DummyObject dummy_object; + + const auto deserializer = []() -> json { + std::ifstream file{ "billy_objects_empty.json" }; + return json::parse(file); + }(); + + REQUIRE_NOTHROW(deserializer.get_to(dummy_object)); + + REQUIRE_FALSE(!dummy_object.objects.empty()); +} + +TEST_CASE("[D] Deserialize full BillyObjects", "[deserialize][1]") { + BillyObjects gestionnaire{}; + test::DummyObject dummy_object; + + const auto deserializer = []() -> json { + std::ifstream file{ "billy_objects_full.json" }; + return json::parse(file); + }(); + + REQUIRE_NOTHROW(deserializer.get_to(dummy_object)); + + REQUIRE_FALSE(dummy_object.objects.empty()); + + REQUIRE_FALSE(std::holds_alternative(dummy_object.objects[0])); + REQUIRE(std::holds_alternative(dummy_object.objects[0])); + REQUIRE(std::get(dummy_object.objects[0]) == weapons::Sword); + + REQUIRE_FALSE(std::holds_alternative(dummy_object.objects[1])); + REQUIRE(std::holds_alternative(dummy_object.objects[1])); + REQUIRE(std::get(dummy_object.objects[1]) == tools::Fourche); + + REQUIRE_FALSE(std::holds_alternative(dummy_object.objects[2])); + REQUIRE(std::holds_alternative(dummy_object.objects[2])); + REQUIRE(std::get(dummy_object.objects[2]) == equipments::MedicKit); +} + +TEST_CASE("[D] Pushing popping BillyObjects", "[pushpop][0]") { + constexpr std::array all_objects{ + weapons::Sword, + weapons::Lance, + weapons::Morgenstern, + weapons::Bow, + equipments::Chainmail, + equipments::CookingPot, + equipments::PamphletTourist, + equipments::MedicKit, + tools::Fourche, + tools::Dagger, + tools::RockClimbingKit, + tools::SackOfGrain, + }; + + BillyObjects gestionnaire{}; + CharacterSheet sheet; + REQUIRE(sheet.get_objects().empty()); + + REQUIRE_NOTHROW(gestionnaire.push_object(weapons::Sword, sheet)); + REQUIRE_FALSE(sheet.get_objects().empty()); + REQUIRE(std::holds_alternative(sheet.get_objects().back())); + REQUIRE(std::get(sheet.get_objects().back()) == weapons::Sword); + + REQUIRE_NOTHROW(gestionnaire.pop_object(sheet)); + REQUIRE(sheet.get_objects().empty()); + + for (std::size_t j = 0; j < all_objects.size(); j += 3) { + for (std::size_t i = 0; i < 3; ++i) { + REQUIRE_NOTHROW(gestionnaire.push_object(all_objects[i + j], sheet)); + } + REQUIRE_FALSE(sheet.get_objects().empty()); + + for (std::size_t i = 0; i < 3; ++i) { + REQUIRE_NOTHROW(gestionnaire.pop_object(sheet)); + } + REQUIRE(sheet.get_objects().empty()); + } +} + +TEST_CASE("[D] Printing Billy's objects", "[printing]") { + constexpr std::array all_objects{ + weapons::Sword, + weapons::Lance, + weapons::Morgenstern, + weapons::Bow, + equipments::Chainmail, + equipments::CookingPot, + equipments::PamphletTourist, + equipments::MedicKit, + tools::Fourche, + tools::Dagger, + tools::RockClimbingKit, + tools::SackOfGrain, + }; + for (const auto &object: all_objects) { + REQUIRE_NOTHROW(BillyObjects::billy_object_to_string(object)); + } +} diff --git a/include/billy_objects.hpp b/include/billy_objects.hpp index 5b9b9c7..fcf8c3b 100644 --- a/include/billy_objects.hpp +++ b/include/billy_objects.hpp @@ -30,23 +30,26 @@ namespace character { }; enum class equipments : std::uint8_t { - Chainmail = 0, - CookingPot = 1, - PamphletTourist = 2, - MedicKit = 3, + Chainmail = 4, + CookingPot = 5, + PamphletTourist = 6, + MedicKit = 7 }; enum class tools : std::uint8_t { - Fourche = 0, - Dagger = 1, - RockClimbingKit = 2, - SackOfGrain = 3 + Fourche = 8, + Dagger = 9, + RockClimbingKit = 10, + SackOfGrain = 11 }; class BillyObjects final { public: + static constexpr std::size_t max_num_obj{ 3 }; using billyObject = std::variant; - using container = ankerl::svector; + using container = ankerl::svector; + + static constexpr std::string_view json_key{ "billy_objects" }; static constexpr std::string_view sword{ "Sword" }; static constexpr std::string_view lance{ "Lance" }; @@ -65,16 +68,21 @@ namespace character { static std::string_view billy_object_to_string(const billyObject &object) noexcept; + static void to_json(json &j, const BillyObjects::container &billy); + + static void from_json(const json &j, BillyObjects::container &billy); + + BillyObjects() noexcept = default; + + ~BillyObjects() noexcept = default; + void push_object(const billyObject &object, CharacterSheet &sheet) noexcept; void pop_object(CharacterSheet &sheet) noexcept; - [[nodiscard]] const container &get_objects() const noexcept { return objects; } - // void insert_weapon(weapons weapon, CharacterSheet &sheet) noexcept; private: - container objects; std::plus plus; std::minus minus; diff --git a/include/gui/gui_data.hpp b/include/gui/gui_data.hpp index 7ed06cf..ff3e2cf 100644 --- a/include/gui/gui_data.hpp +++ b/include/gui/gui_data.hpp @@ -12,28 +12,12 @@ using namespace std::string_view_literals; namespace gui { - enum class characChanged { - None, - Adresse, - Endurance, - Chance, - Habilete - }; - class GuiData final { private: friend class Gui; character::CharacterSheet &billy; - std::pair base{ characChanged::None, 0 }; - - std::pair carac{ characChanged::None, 0 }; - - std::pair materiel{ characChanged::None, 0 }; - - std::pair additional{ characChanged::None, 0 }; - public: static constexpr std::array classes{ "Guerrier"sv, @@ -47,14 +31,6 @@ namespace gui { explicit GuiData(character::CharacterSheet &billy) noexcept: billy(billy) { SPDLOG_DEBUG("Creating GUI Data"); } ~GuiData() noexcept = default; - - [[nodiscard]] const std::pair &get_base() const { return base; } - - [[nodiscard]] const std::pair &get_carac() const { return carac; } - - [[nodiscard]] const std::pair &get_materiel() const { return materiel; } - - [[nodiscard]] const std::pair &get_additional() const { return additional; } }; } diff --git a/src/billy_objects.cpp b/src/billy_objects.cpp index ad4146e..872649a 100644 --- a/src/billy_objects.cpp +++ b/src/billy_objects.cpp @@ -2,15 +2,24 @@ // Created by postaron on 23/02/24. // #include "billy_objects.hpp" +#include #include "characteristic/characteristic.hpp" #include "character_sheet.hpp" +std::uint32_t constexpr const_hash(const char *input) { + return *input ? static_cast(*input) + 33 * const_hash(input + 1) : 5381; +} + +constexpr std::uint32_t weaponsHash = const_hash("weapons"); +constexpr std::uint32_t equipmentHash = const_hash("equipments"); +constexpr std::uint32_t toolsHash = const_hash("tools"); + namespace character { using characteristic::Characteristic; void BillyObjects::push_object(const billyObject &object, CharacterSheet &sheet) noexcept { - if (objects.size() < 3) { - objects.emplace_back(object); + if (sheet.objects.size() < 3) { + sheet.objects.emplace_back(object); auto &local_habilete = static_cast(sheet.habilete); auto &local_adresse = static_cast(sheet.adresse); @@ -48,9 +57,9 @@ namespace character { } void BillyObjects::pop_object(CharacterSheet &sheet) noexcept { - if (!objects.empty()) { - const billyObject obj = objects.back(); - objects.pop_back(); + if (!sheet.objects.empty()) { + const billyObject obj = sheet.objects.back(); + sheet.objects.pop_back(); auto &local_habilete = static_cast(sheet.habilete); auto &local_adresse = static_cast(sheet.adresse); @@ -205,4 +214,38 @@ namespace character { } }, object); } + + void BillyObjects::from_json(const json &j, BillyObjects::container &billy) { + for (const auto &element: j) { + const std::uint32_t key = element[0].get(); + const std::uint8_t value = element[1].get(); + switch (key) { + case weaponsHash: + billy.push_back(static_cast(value)); + break; + case equipmentHash: + billy.push_back(static_cast(value)); + break; + case toolsHash: + billy.push_back(static_cast(value)); + break; + } + } + } + + void BillyObjects::to_json(json &j, const BillyObjects::container &billy) { + for (const auto &object: billy) { + std::visit(overloaded{ + [&j](const weapons weapon) { + j.emplace_back(std::pair{ weaponsHash, static_cast(weapon) }); + }, + [&j](const equipments equipment) { + j.emplace_back(std::pair{ equipmentHash, static_cast(equipment) }); + }, + [&j](const tools tool) { + j.emplace_back(std::pair{ toolsHash, static_cast(tool) }); + } + }, object); + } + } } \ No newline at end of file