From 2c3d736d5f8971747572b0184610ed26075cafc3 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Mon, 4 Mar 2024 17:25:11 +0100 Subject: [PATCH] Conversion to JSON. --- Unit testing/CMakeLists.txt | 12 ++- Unit testing/billy_objects_tests.cpp | 107 +++++++++++++++++++++++++++ include/billy_objects.hpp | 26 +++++-- src/billy_objects.cpp | 46 ++++++++++++ 4 files changed, 179 insertions(+), 12 deletions(-) create mode 100644 Unit testing/billy_objects_tests.cpp 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..cfa875e --- /dev/null +++ b/Unit testing/billy_objects_tests.cpp @@ -0,0 +1,107 @@ +// +// 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); +} diff --git a/include/billy_objects.hpp b/include/billy_objects.hpp index 3cc3698..fcf8c3b 100644 --- a/include/billy_objects.hpp +++ b/include/billy_objects.hpp @@ -30,17 +30,17 @@ 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 { @@ -49,6 +49,8 @@ namespace character { using billyObject = std::variant; 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" }; static constexpr std::string_view morgenstern{ "Morgenstern" }; @@ -66,6 +68,14 @@ 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; diff --git a/src/billy_objects.cpp b/src/billy_objects.cpp index 45293ec..4017f58 100644 --- a/src/billy_objects.cpp +++ b/src/billy_objects.cpp @@ -2,9 +2,18 @@ // 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; @@ -205,4 +214,41 @@ 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; + default: + SPDLOG_CRITICAL("Deserialize billy objects error, wrong hash."); + throw std::runtime_error("Deserialize billy objects error, wrong hash."); + } + } + } + + 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