From c9138d591dc1251ea37cde87a60f5194815ca014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Fri, 10 Feb 2023 11:31:17 +0100 Subject: [PATCH 1/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b33b59b..09c382a 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,7 @@ REXSapi uses the following thirdparty open source software - [miniz 2.2.0](https://github.com/richgel999/miniz) - [pugixml 1.12.1](https://github.com/zeux/pugixml) - [valijson 0.6](https://github.com/tristanpenman/valijson) -- [doctest 2.4.8](https://github.com/doctest/doctest) +- [doctest 2.4.9](https://github.com/doctest/doctest) # License REXsapi is licensed under the Apache-2.0 license. From 7871cf099a090cc3192e05ee42204c209eac6fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Mon, 13 Feb 2023 11:22:53 +0100 Subject: [PATCH 2/9] Feature encoding matrix values (#13) closes #9 * Switched matrix encoding from row-major to column-major * Fixed matrix encoding bug. Added more tests. --- CHANGELOG.md | 6 +++ CMakeLists.txt | 2 +- include/rexsapi/CodedValue.hxx | 37 +++++++++++------- include/rexsapi/JsonValueDecoder.hxx | 12 +++--- include/rexsapi/XMLValueDecoder.hxx | 19 ++++----- test/CodedValuesTest.cxx | 58 ++++++++++++++++++++++++---- 6 files changed, 95 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a5d855..42c7ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.0] + +### Changed + +- Switched matrix encoding from row-major to column-major order (#9) + ## [1.0.0] - 2022-11-09 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index ba34f85..bb65b0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(rexsapi VERSION 1.0.0 LANGUAGES CXX) +project(rexsapi VERSION 1.1.0 LANGUAGES CXX) include(FetchContent) diff --git a/include/rexsapi/CodedValue.hxx b/include/rexsapi/CodedValue.hxx index 172be9b..a418f40 100644 --- a/include/rexsapi/CodedValue.hxx +++ b/include/rexsapi/CodedValue.hxx @@ -33,7 +33,7 @@ namespace rexsapi::detail static std::string toCodedValueString(TCodedValueType type); - template::value || std::is_floating_point::value>* = nullptr> + template || std::is_floating_point_v>* = nullptr> class TCodedValueArray { public: @@ -59,18 +59,19 @@ namespace rexsapi::detail } }; - template::value || std::is_floating_point::value>* = nullptr> + template || std::is_floating_point_v>* = nullptr> class TCodedValueMatrix { public: static std::string encode(const TMatrix& matrix) { - const auto count = matrix.m_Values.size() * matrix.m_Values.size() * sizeof(T); + const auto count = matrix.m_Values.size() * matrix.m_Values[0].size(); std::vector array; array.reserve(count); - for (const auto& row : matrix.m_Values) { - for (const auto& column : row) { - array.emplace_back(column); + + for (size_t c = 0; c < matrix.m_Values[0].size(); ++c) { + for (size_t r = 0; r < matrix.m_Values.size(); ++r) { + array.emplace_back(matrix.m_Values[r][c]); } } const auto* data = reinterpret_cast(array.data()); @@ -78,19 +79,25 @@ namespace rexsapi::detail return base64Encode(data, len); } - static TMatrix decode(std::string_view value) + static TMatrix decode(std::string_view value, size_t columns, size_t rows) { TMatrix matrix; const auto data = base64Decode(value); const auto count = data.size() / sizeof(T); - const auto elementCount = static_cast(::sqrt(static_cast(count))); const auto values = reinterpret_cast(data.data()); - matrix.m_Values.reserve(elementCount); - for (size_t row = 0; row < elementCount; ++row) { + if (count != columns * rows) { + throw TException{ + fmt::format("matrix does not have the correct element count: {} rows: {} columns: {}", count, rows, columns)}; + } + if (count == 0) { + throw TException{"matrix does not have any elements"}; + } + matrix.m_Values.reserve(rows); + for (size_t row = 0; row < rows; ++row) { std::vector col; - col.reserve(elementCount); - for (size_t column = 0; column < elementCount; ++column) { - col.emplace_back(values[(row * elementCount) + column]); + col.reserve(columns); + for (size_t column = 0; column < columns; ++column) { + col.emplace_back(values[row + (rows * column)]); } matrix.m_Values.emplace_back(std::move(col)); } @@ -222,12 +229,12 @@ namespace rexsapi::detail template struct TCodedValueMatrixDecoder { - static TValue decode(std::string_view value) + static TValue decode(std::string_view value, size_t columns, size_t rows) { if (!std::is_same_v::Type>) { throw TException{"coded value type does not correspond to attribute value type"}; } - auto result = TCodedValueMatrix::Type>::decode(value); + auto result = TCodedValueMatrix::Type>::decode(value, columns, rows); TValue val{TMatrix{result}}; val.coded(getCodedType(TCodedValueType{T2::value})); return val; diff --git a/include/rexsapi/JsonValueDecoder.hxx b/include/rexsapi/JsonValueDecoder.hxx index 5121b30..eb97ee9 100644 --- a/include/rexsapi/JsonValueDecoder.hxx +++ b/include/rexsapi/JsonValueDecoder.hxx @@ -402,23 +402,23 @@ namespace rexsapi::detail case detail::TCodedValueType::None: throw TException{"unknown code"}; case detail::TCodedValueType::Int32: { - value = - detail::TCodedValueMatrixDecoder>::decode(val); + value = detail::TCodedValueMatrixDecoder< + Type, Enum2type>::decode(val, columns, rows); break; } case detail::TCodedValueType::Float32: { value = detail::TCodedValueMatrixDecoder< - Type, Enum2type>::decode(val); + Type, Enum2type>::decode(val, columns, rows); break; } case detail::TCodedValueType::Float64: { value = detail::TCodedValueMatrixDecoder< - Type, Enum2type>::decode(val); + Type, Enum2type>::decode(val, columns, rows); break; } } - if (value.getValue>().m_Values.size() != rows) { + if (value.getValue>().m_Values.size() != rows || + value.getValue>().m_Values[0].size() != columns) { throw TException{"decoded matrix size does not correspond to configured size"}; } return std::make_pair(std::move(value), TDecoderResult::SUCCESS); diff --git a/include/rexsapi/XMLValueDecoder.hxx b/include/rexsapi/XMLValueDecoder.hxx index f2829e2..1c0e28b 100644 --- a/include/rexsapi/XMLValueDecoder.hxx +++ b/include/rexsapi/XMLValueDecoder.hxx @@ -264,38 +264,39 @@ namespace rexsapi::detail std::pair onDecode(const std::optional& enumValue, const pugi::xml_node& node) const override { + size_t rows = 0; + size_t columns = 0; const auto child = node.first_child(); TValue value; const auto codedType = rexsapi::detail::codedValueFromString(detail::getStringAttribute(child, "code")); + if (codedType != detail::TCodedValueType::None) { + rows = convertToUint64(detail::getStringAttribute(child, "rows")); + columns = convertToUint64(detail::getStringAttribute(child, "columns")); + } switch (codedType) { case detail::TCodedValueType::None: return TMatrixDecoder::onDecode(enumValue, node); case detail::TCodedValueType::Int32: { value = detail::TCodedValueMatrixDecoder< typename TMatrixDecoder::type, - detail::Enum2type>::decode(child.child_value()); + detail::Enum2type>::decode(child.child_value(), columns, rows); break; } case detail::TCodedValueType::Float32: { value = detail::TCodedValueMatrixDecoder< typename TMatrixDecoder::type, - detail::Enum2type>::decode(child.child_value()); + detail::Enum2type>::decode(child.child_value(), columns, rows); break; } case detail::TCodedValueType::Float64: { value = detail::TCodedValueMatrixDecoder< typename TMatrixDecoder::type, - detail::Enum2type>::decode(child.child_value()); + detail::Enum2type>::decode(child.child_value(), columns, rows); break; } } if (codedType != detail::TCodedValueType::None) { - const auto rows = convertToUint64(detail::getStringAttribute(child, "rows")); - const auto columns = convertToUint64(detail::getStringAttribute(child, "columns")); - if (rows != columns) { - throw TException{"matrix rows != columns"}; - } - if (value.getValue::type>>().m_Values.size() != rows) { + if (value.getValue::type>>().m_Values.size() != rows || value.getValue::type>>().m_Values[0].size() != columns) { throw TException{"decoded matrix size does not correspond to configured size"}; } } diff --git a/test/CodedValuesTest.cxx b/test/CodedValuesTest.cxx index 281c40c..be92c50 100644 --- a/test/CodedValuesTest.cxx +++ b/test/CodedValuesTest.cxx @@ -50,7 +50,7 @@ TEST_CASE("Coded values test") { rexsapi::TMatrix matrix{{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}}}; const auto encoded = rexsapi::detail::TCodedValueMatrix::encode(matrix); - const auto decoded = rexsapi::detail::TCodedValueMatrix::decode(encoded); + const auto decoded = rexsapi::detail::TCodedValueMatrix::decode(encoded, 3, 3); REQUIRE(decoded.m_Values.size() == 3); REQUIRE(decoded.m_Values[0].size() == 3); CHECK(decoded.m_Values[0][0] == doctest::Approx{1.0}); @@ -65,7 +65,26 @@ TEST_CASE("Coded values test") CHECK(decoded.m_Values[2][1] == doctest::Approx{8.0}); CHECK(decoded.m_Values[2][2] == doctest::Approx{9.0}); CHECK(encoded == - "AAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAABhAAAAAAAAAHEAAAAAAAAAgQAAAAAAAACJA"); + "AAAAAAAA8D8AAAAAAAAQQAAAAAAAABxAAAAAAAAAAEAAAAAAAAAUQAAAAAAAACBAAAAAAAAACEAAAAAAAAAYQAAAAAAAACJA"); + } + + SUBCASE("int64 matrix") + { + rexsapi::TMatrix matrix{{{1, 2, 3, 4}, {5, 6, 7, 8}}}; + const auto encoded = rexsapi::detail::TCodedValueMatrix::encode(matrix); + const auto decoded = rexsapi::detail::TCodedValueMatrix::decode(encoded, 4, 2); + REQUIRE(decoded.m_Values.size() == 2); + REQUIRE(decoded.m_Values[0].size() == 4); + CHECK(decoded.m_Values[0][0] == 1); + CHECK(decoded.m_Values[0][1] == 2); + CHECK(decoded.m_Values[0][2] == 3); + CHECK(decoded.m_Values[0][3] == 4); + REQUIRE(decoded.m_Values[1].size() == 4); + CHECK(decoded.m_Values[1][0] == 5); + CHECK(decoded.m_Values[1][1] == 6); + CHECK(decoded.m_Values[1][2] == 7); + CHECK(decoded.m_Values[1][3] == 8); + CHECK(encoded == "AQAAAAAAAAAFAAAAAAAAAAIAAAAAAAAABgAAAAAAAAADAAAAAAAAAAcAAAAAAAAABAAAAAAAAAAIAAAAAAAAAA=="); } SUBCASE("Encode int64 array") @@ -99,10 +118,32 @@ TEST_CASE("Coded values test") SUBCASE("Encode double matrix") { - const auto [value, type] = rexsapi::detail::encodeMatrix( - rexsapi::TMatrix{{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}}}, rexsapi::TCodeType::Default); - CHECK(type == rexsapi::detail::TCodedValueType::Float64); - CHECK(value == "AAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAABhAAAAAAAAAHEAAAAAAAAAgQAAAAAAAACJA"); + { + const auto [value, type] = rexsapi::detail::encodeMatrix( + rexsapi::TMatrix{{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}}}, rexsapi::TCodeType::Default); + CHECK(type == rexsapi::detail::TCodedValueType::Float64); + CHECK(value == + "AAAAAAAA8D8AAAAAAAAQQAAAAAAAABxAAAAAAAAAAEAAAAAAAAAUQAAAAAAAACBAAAAAAAAACEAAAAAAAAAYQAAAAAAAACJA"); + } + + { + const auto [value, type] = rexsapi::detail::encodeMatrix( + rexsapi::TMatrix{{{1.0, 5.0, 54.125738867291}, {4.0, 3.0, 0.0}, {2.0, 6.0, -259.10672159143496}}}, + rexsapi::TCodeType::Default); + CHECK(type == rexsapi::detail::TCodedValueType::Float64); + CHECK(value == + "AAAAAAAA8D8AAAAAAAAQQAAAAAAAAABAAAAAAAAAFEAAAAAAAAAIQAAAAAAAABhA62wRNhgQS0AAAAAAAAAAANgPsyG1MXDA"); + } + } + + SUBCASE("Encode integer matrix") + { + { + const auto [value, type] = rexsapi::detail::encodeMatrix( + rexsapi::TMatrix{{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}}, rexsapi::TCodeType::Default); + CHECK(type == rexsapi::detail::TCodedValueType::Int32); + CHECK(value == "AQAAAAQAAAAHAAAAAgAAAAUAAAAIAAAAAwAAAAYAAAAJAAAA"); + } } SUBCASE("Encode double matrix optimized") @@ -110,13 +151,14 @@ TEST_CASE("Coded values test") const auto [value, type] = rexsapi::detail::encodeMatrix( rexsapi::TMatrix{{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}}}, rexsapi::TCodeType::Optimized); CHECK(type == rexsapi::detail::TCodedValueType::Float32); - CHECK(value == "AACAPwAAAEAAAEBAAACAQAAAoEAAAMBAAADgQAAAAEEAABBB"); + CHECK(value == "AACAPwAAgEAAAOBAAAAAQAAAoEAAAABBAABAQAAAwEAAABBB"); } SUBCASE("Encode matrix failure") { CHECK_THROWS(rexsapi::detail::encodeMatrix( rexsapi::TMatrix{{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}}}, rexsapi::TCodeType::None)); + CHECK_THROWS(rexsapi::detail::encodeMatrix(rexsapi::TMatrix{{}}, rexsapi::TCodeType::None)); } } @@ -153,7 +195,7 @@ TEST_CASE("Coded value decoder test") { auto val = rexsapi::detail::TCodedValueMatrixDecoder< double, rexsapi::detail::Enum2type>:: - decode("AAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAABhAAAAAAAAAHEAAAAAAAAAgQAAAAAAAACJA"); + decode("AAAAAAAA8D8AAAAAAAAQQAAAAAAAABxAAAAAAAAAAEAAAAAAAAAUQAAAAAAAACBAAAAAAAAACEAAAAAAAAAYQAAAAAAAACJA", 3, 3); CHECK(val.coded() == rexsapi::TCodeType::Default); CHECK_NOTHROW(val.getValue()); } From fe3aaeb4e2ba99c6693e893895fb7c7341212bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Wed, 15 Feb 2023 13:38:54 +0100 Subject: [PATCH 3/9] Added utf-8 bom to json model files (#14) closes #11 * Added utf-8 bom to json model files * Updated changelog --- CHANGELOG.md | 1 + include/rexsapi/JsonSerializer.hxx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c7ca0..e856e68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Switched matrix encoding from row-major to column-major order (#9) +- JSON model files will now be written with a UTF-8 BOM (#11) ## [1.0.0] - 2022-11-09 diff --git a/include/rexsapi/JsonSerializer.hxx b/include/rexsapi/JsonSerializer.hxx index e7cb1be..8da5e77 100644 --- a/include/rexsapi/JsonSerializer.hxx +++ b/include/rexsapi/JsonSerializer.hxx @@ -83,7 +83,9 @@ namespace rexsapi */ void serialize(const ordered_json& doc) { + constexpr static uint8_t bom[] = {0xEF, 0xBB, 0xBF}; std::ofstream stream{m_File}; + stream.write(reinterpret_cast(bom), sizeof(bom)); stream << doc.dump(m_Indent); stream.flush(); if (!stream) { From da8062ed0852b901724426b4e6d1e023c9abff51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Fri, 10 Mar 2023 14:03:46 +0100 Subject: [PATCH 4/9] Feature fallback strategy for newer rexs versions (#15) closes #8 * Refactoring * Load latest model version if requested is unknown * Fixed model registry problem --- CHANGELOG.md | 3 ++ include/rexsapi/CodedValue.hxx | 4 +- include/rexsapi/JsonModelLoader.hxx | 20 ++++++---- include/rexsapi/JsonSerializer.hxx | 2 +- include/rexsapi/XMLModelLoader.hxx | 26 ++++++++----- include/rexsapi/database/ModelRegistry.hxx | 38 +++++++++++++++---- include/rexsapi/database/XMLModelLoader.hxx | 11 +++--- test/JsonModelLoaderTest.cxx | 39 +++++++++++++------ test/TestModelHelper.hxx | 10 +++++ test/XMLModelLoaderTest.cxx | 42 +++++++++++++++------ test/database/ModelRegistryTest.cxx | 24 +++++++++--- 11 files changed, 158 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e856e68..a72ecc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Switched matrix encoding from row-major to column-major order (#9) - JSON model files will now be written with a UTF-8 BOM (#11) +- The model registry can be configured to load the latest available model version, if the requested version is not + known. If no appropriate language can be found, english will be chosen. (#8) +- In relaxed mode latest available model version loading will be active (#8) ## [1.0.0] - 2022-11-09 diff --git a/include/rexsapi/CodedValue.hxx b/include/rexsapi/CodedValue.hxx index a418f40..d644d25 100644 --- a/include/rexsapi/CodedValue.hxx +++ b/include/rexsapi/CodedValue.hxx @@ -148,7 +148,7 @@ namespace rexsapi::detail return std::make_pair(TCodedValueMatrix::encode(matrix), TCodedValueType::Float64); } if (type == TCodeType::Optimized) { - TMatrix tmp{matrix}; + const TMatrix tmp{matrix}; return std::make_pair(TCodedValueMatrix::encode(tmp), TCodedValueType::Float32); } throw TException{"should never reach this"}; @@ -157,7 +157,7 @@ namespace rexsapi::detail template<> inline std::pair encodeMatrix(const TMatrix& matrix, TCodeType) { - TMatrix tmp{matrix}; + const TMatrix tmp{matrix}; return std::make_pair(TCodedValueMatrix::encode(tmp), TCodedValueType::Int32); } diff --git a/include/rexsapi/JsonModelLoader.hxx b/include/rexsapi/JsonModelLoader.hxx index 2636b4e..e643497 100644 --- a/include/rexsapi/JsonModelLoader.hxx +++ b/include/rexsapi/JsonModelLoader.hxx @@ -105,8 +105,7 @@ namespace rexsapi { try { const json j = json::parse(buffer); - std::vector errors; - if (!m_Validator.validate(j, errors)) { + if (std::vector errors; !m_Validator.validate(j, errors)) { for (const auto& error : errors) { result.addError(TError{TErrorLevel::CRIT, error}); } @@ -118,12 +117,19 @@ namespace rexsapi language = j["/model/applicationLanguage"_json_pointer].get(); } - TModelInfo info{j["/model/applicationId"_json_pointer].get(), - j["/model/applicationVersion"_json_pointer].get(), - j["/model/date"_json_pointer].get(), - TRexsVersion{j["/model/version"_json_pointer].get()}, language}; + const TModelInfo info{j["/model/applicationId"_json_pointer].get(), + j["/model/applicationVersion"_json_pointer].get(), + j["/model/date"_json_pointer].get(), + TRexsVersion{j["/model/version"_json_pointer].get()}, language}; - const auto& dbModel = registry.getModel(info.getVersion(), language.has_value() ? *language : "en"); + const auto& dbModel = + registry.getModel(info.getVersion(), language.value_or("en"), m_Mode.getMode() == TMode::STRICT_MODE); + + if (dbModel.getVersion() != info.getVersion()) { + result.addError( + TError{TErrorLevel::WARN, fmt::format("exact database model for version not available, using {}", + dbModel.getVersion().asString())}); + } detail::ComponentMapping componentMapping; TComponents components = getComponents(result, componentMapping, dbModel, j); diff --git a/include/rexsapi/JsonSerializer.hxx b/include/rexsapi/JsonSerializer.hxx index 8da5e77..c65c01d 100644 --- a/include/rexsapi/JsonSerializer.hxx +++ b/include/rexsapi/JsonSerializer.hxx @@ -81,7 +81,7 @@ namespace rexsapi * @param doc The json obejct containing the REXS json model * @throws TException if the file cannot be written */ - void serialize(const ordered_json& doc) + void serialize(const ordered_json& doc) const { constexpr static uint8_t bom[] = {0xEF, 0xBB, 0xBF}; std::ofstream stream{m_File}; diff --git a/include/rexsapi/XMLModelLoader.hxx b/include/rexsapi/XMLModelLoader.hxx index 2b44b9c..b670b53 100644 --- a/include/rexsapi/XMLModelLoader.hxx +++ b/include/rexsapi/XMLModelLoader.hxx @@ -96,22 +96,28 @@ namespace rexsapi } const auto rexsModel = *doc.select_nodes("/model").begin(); - auto language = detail::getStringAttribute(rexsModel, "applicationLanguage", ""); - TModelInfo info{detail::getStringAttribute(rexsModel, "applicationId"), - detail::getStringAttribute(rexsModel, "applicationVersion"), - detail::getStringAttribute(rexsModel, "date"), - TRexsVersion{detail::getStringAttribute(rexsModel, "version")}, - language.empty() ? std::optional{} : language}; - - const auto& dbModel = registry.getModel(info.getVersion(), language.empty() ? "en" : language); - detail::ComponentMapping componentsMapping; + const auto language = detail::getStringAttribute(rexsModel, "applicationLanguage", ""); + const TModelInfo info{detail::getStringAttribute(rexsModel, "applicationId"), + detail::getStringAttribute(rexsModel, "applicationVersion"), + detail::getStringAttribute(rexsModel, "date"), + TRexsVersion{detail::getStringAttribute(rexsModel, "version")}, + language.empty() ? std::optional{} : language}; + + const auto& dbModel = + registry.getModel(info.getVersion(), language.empty() ? "en" : language, m_Mode.getMode() == TMode::STRICT_MODE); + + if (dbModel.getVersion() != info.getVersion()) { + result.addError(TError{TErrorLevel::WARN, fmt::format("exact database model for version not available, using {}", + dbModel.getVersion().asString())}); + } + detail::ComponentMapping componentsMapping; TComponents components; components.reserve(10); std::set usedComponents; for (const auto& component : doc.select_nodes("/model/components/component")) { - auto componentId = detail::getStringAttribute(component, "id"); + const auto componentId = detail::getStringAttribute(component, "id"); std::string componentName = detail::getStringAttribute(component, "name", ""); try { const auto& componentType = dbModel.findComponentById(detail::getStringAttribute(component, "type")); diff --git a/include/rexsapi/database/ModelRegistry.hxx b/include/rexsapi/database/ModelRegistry.hxx index 4c9cf98..08e407f 100644 --- a/include/rexsapi/database/ModelRegistry.hxx +++ b/include/rexsapi/database/ModelRegistry.hxx @@ -19,6 +19,7 @@ #include + /** @file */ namespace rexsapi::database @@ -45,10 +46,13 @@ namespace rexsapi::database * * @param version The database model version to retrieve * @param language The language of the database model to retrieve + * @param strict Determines if the latest available model version shall be returned if an exact one was not found. + * If set to true, will throw an exception if the exact version could not be found. * @return const TModel& to the found database model - * @throws TException if the specific version or language is not available + * @throws TException if the specific version or language is not available and strict mode was set to true */ - [[nodiscard]] const TModel& getModel(const TRexsVersion& version, const std::string& language) const; + [[nodiscard]] const TModel& getModel(const TRexsVersion& version, const std::string& language, + bool strict = true) const; /** * @brief Creates a model registry @@ -78,18 +82,38 @@ namespace rexsapi::database // Implementation ///////////////////////////////////////////////////////////////////////////// - inline const TModel& TModelRegistry::getModel(const TRexsVersion& version, const std::string& language) const + inline const TModel& TModelRegistry::getModel(const TRexsVersion& version, const std::string& language, + bool strict) const { const auto it = std::find_if(m_Models.begin(), m_Models.end(), [&version, &language](const auto& model) { return model.getVersion() == version && model.getLanguage() == language; }); - if (it == m_Models.end()) { - throw TException{ - fmt::format("cannot find a database model for version '{}' and locale '{}'", version.asString(), language)}; + if (it != m_Models.end()) { + return *it; + } + + if (!strict) { + // no exact model was found, find the latest model for the given language + // otherwise choose english + const TRexsVersion baseVersion{1, 0}; + const TModel* baseModel{nullptr}; + std::for_each(m_Models.begin(), m_Models.end(), [&baseModel, &baseVersion, &language](const auto& model) mutable { + if (model.getLanguage() == language && model.getVersion() >= (baseModel ? baseModel->getVersion() : baseVersion)) { + baseModel = &model; + } + if (model.getLanguage() == "en" && model.getVersion() > (baseModel ? baseModel->getVersion() : baseVersion)) { + baseModel = &model; + } + }); + + if (baseModel) { + return *baseModel; + } } - return *it; + throw TException{ + fmt::format("cannot find a database model for version '{}' and locale '{}'", version.asString(), language)}; } template diff --git a/include/rexsapi/database/XMLModelLoader.hxx b/include/rexsapi/database/XMLModelLoader.hxx index bfd6383..bc17ab3 100644 --- a/include/rexsapi/database/XMLModelLoader.hxx +++ b/include/rexsapi/database/XMLModelLoader.hxx @@ -85,7 +85,8 @@ namespace rexsapi::database TXmlModelLoader::load(const std::function& callback) const { return m_ResourceLoader.load([this, &callback](TResult& result, std::vector& buffer) { - pugi::xml_document doc = rexsapi::detail::loadXMLDocument(result, buffer, TXSDSchemaValidator{m_SchemaLoader}); + const pugi::xml_document doc = + rexsapi::detail::loadXMLDocument(result, buffer, TXSDSchemaValidator{m_SchemaLoader}); if (!result) { return; } @@ -163,12 +164,12 @@ namespace rexsapi::database TIntervalEndpoint min; TIntervalEndpoint max; - if (auto att = node.node().attribute("rangeMin"); !att.empty()) { - auto open = rexsapi::detail::getBoolAttribute(node, "rangeMinIntervalOpen", true); + if (const auto att = node.node().attribute("rangeMin"); !att.empty()) { + const auto open = rexsapi::detail::getBoolAttribute(node, "rangeMinIntervalOpen", true); min = TIntervalEndpoint{convertToDouble(att.value()), open ? TIntervalType::OPEN : TIntervalType::CLOSED}; } - if (auto att = node.node().attribute("rangeMax"); !att.empty()) { - auto open = rexsapi::detail::getBoolAttribute(node, "rangeMaxIntervalOpen", true); + if (const auto att = node.node().attribute("rangeMax"); !att.empty()) { + const auto open = rexsapi::detail::getBoolAttribute(node, "rangeMaxIntervalOpen", true); max = TIntervalEndpoint{convertToDouble(att.value()), open ? TIntervalType::OPEN : TIntervalType::CLOSED}; } diff --git a/test/JsonModelLoaderTest.cxx b/test/JsonModelLoaderTest.cxx index 9686fcc..9b24f54 100644 --- a/test/JsonModelLoaderTest.cxx +++ b/test/JsonModelLoaderTest.cxx @@ -35,18 +35,8 @@ namespace path}; return loader.load(mode, result, registry); } -} - -TEST_CASE("Json model loader test") -{ - rexsapi::TFileJsonSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.json"}; - rexsapi::TJsonSchemaValidator validator{schemaLoader}; - rexsapi::TResult result; - const auto registry = createModelRegistry(); - SUBCASE("Load valid document from buffer") - { - std::string buffer = R"({ + const std::string MemModel = R"({ "model":{ "applicationId":"Bearinx", "applicationVersion":"12.0.8823", @@ -211,9 +201,19 @@ TEST_CASE("Json model loader test") } } })"; +} + +TEST_CASE("Json model loader test") +{ + rexsapi::TFileJsonSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.json"}; + rexsapi::TJsonSchemaValidator validator{schemaLoader}; + rexsapi::TResult result; + const auto registry = createModelRegistry(); + SUBCASE("Load valid document from buffer") + { rexsapi::detail::TBufferModelLoader loader{validator, - buffer}; + MemModel}; auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK_FALSE(result); REQUIRE(result.getErrors().size() == 4); @@ -503,4 +503,19 @@ TEST_CASE("Json model loader test") CHECK(result.isCritical()); CHECK_FALSE(model); } + + SUBCASE("Load valid document with unkown version") + { + std::string buffer{MemModel}; + replace(buffer, R"("version":"1.4")", R"("version":"1.99")"); + rexsapi::detail::TBufferModelLoader loader{validator, + buffer}; + auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + CHECK_FALSE(result); + CHECK_FALSE(result.isCritical()); + REQUIRE(model); + result.reset(); + + CHECK_THROWS((void)loader.load(rexsapi::TMode::STRICT_MODE, result, registry)); + } } diff --git a/test/TestModelHelper.hxx b/test/TestModelHelper.hxx index 19b3458..9e37ae6 100644 --- a/test/TestModelHelper.hxx +++ b/test/TestModelHelper.hxx @@ -67,3 +67,13 @@ public: private: const rexsapi::TComponent& m_Component; }; + +static inline bool replace(std::string& str, std::string_view from, std::string_view to) +{ + size_t startPos = str.find(from); + if (startPos == std::string::npos) { + return false; + } + str.replace(startPos, from.length(), to); + return true; +} diff --git a/test/XMLModelLoaderTest.cxx b/test/XMLModelLoaderTest.cxx index 7de59b9..fd2a53b 100644 --- a/test/XMLModelLoaderTest.cxx +++ b/test/XMLModelLoaderTest.cxx @@ -35,18 +35,8 @@ namespace rexsapi::detail::TFileModelLoader loader{validator, path}; return loader.load(mode, result, registry); } -} - -TEST_CASE("XML model loader test") -{ - const auto registry = createModelRegistry(); - rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; - rexsapi::TXSDSchemaValidator validator{schemaLoader}; - rexsapi::TResult result; - SUBCASE("Load model from buffer") - { - std::string buffer = R"( + const std::string MemModel = R"( @@ -132,9 +122,19 @@ TEST_CASE("XML model loader test") )"; +} + +TEST_CASE("XML model loader test") +{ + const auto registry = createModelRegistry(); + rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; + rexsapi::TXSDSchemaValidator validator{schemaLoader}; + rexsapi::TResult result; + SUBCASE("Load model from buffer") + { rexsapi::detail::TBufferModelLoader loader{validator, - buffer}; + MemModel}; auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); REQUIRE(result.getErrors().size() == 1); @@ -459,4 +459,22 @@ TEST_CASE("XML model loader test") CHECK(result.hasIssues()); CHECK(model); } + + SUBCASE("Load valid document with unkown version") + { + std::string buffer{MemModel}; + replace(buffer, R"(version="1.4")", R"(version="1.99")"); + { + rexsapi::detail::TBufferModelLoader loader{validator, + buffer}; + auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + CHECK(result); + REQUIRE(model); + } + result.reset(); + + rexsapi::detail::TBufferModelLoader loader{validator, + buffer}; + CHECK_THROWS((void)loader.load(rexsapi::TMode::STRICT_MODE, result, registry)); + } } diff --git a/test/database/ModelRegistryTest.cxx b/test/database/ModelRegistryTest.cxx index 25b8e88..ad673fe 100644 --- a/test/database/ModelRegistryTest.cxx +++ b/test/database/ModelRegistryTest.cxx @@ -22,9 +22,9 @@ TEST_CASE("Test rexs model registry") { - rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-dbmodel.xsd"}; - rexsapi::database::TFileResourceLoader resourceLoader{projectDir() / "models"}; - rexsapi::database::TXmlModelLoader modelLoader{resourceLoader, schemaLoader}; + const rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-dbmodel.xsd"}; + const rexsapi::database::TFileResourceLoader resourceLoader{projectDir() / "models"}; + const rexsapi::database::TXmlModelLoader modelLoader{resourceLoader, schemaLoader}; const auto [registry, success] = rexsapi::database::TModelRegistry::createModelRegistry(modelLoader); REQUIRE(success); @@ -47,7 +47,21 @@ TEST_CASE("Test rexs model registry") { CHECK_THROWS_WITH((void)registry.getModel(rexsapi::TRexsVersion{"1.4"}, "es"), "cannot find a database model for version '1.4' and locale 'es'"); - CHECK_THROWS_WITH((void)registry.getModel(rexsapi::TRexsVersion{"1.99"}, "en"), - "cannot find a database model for version '1.99' and locale 'en'"); + CHECK_THROWS_WITH((void)registry.getModel(rexsapi::TRexsVersion{"1.99"}, "es"), + "cannot find a database model for version '1.99' and locale 'es'"); + } + + SUBCASE("Get non existing model non-strict mode") + { + const auto& model = registry.getModel(rexsapi::TRexsVersion{"1.99"}, "de", false); + CHECK(model.getVersion() == rexsapi::TRexsVersion{"1.4"}); + CHECK(model.getLanguage() == "de"); + } + + SUBCASE("Get non existing model non-strict mode with unknown language") + { + const auto& model = registry.getModel(rexsapi::TRexsVersion{"1.99"}, "es", false); + CHECK(model.getVersion() == rexsapi::TRexsVersion{"1.4"}); + CHECK(model.getLanguage() == "en"); } } From 7c7a1cd7187c05b1e8a7d3ba444541eb7e90f742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Wed, 15 Mar 2023 16:59:04 +0100 Subject: [PATCH 5/9] Feature update thirdparty components (#18) closes #7 * Updated all thirdparty components * Update README.md --- CHANGELOG.md | 1 + README.md | 14 +++++++------- cmake/fetch_cli11.cmake | 2 +- cmake/fetch_doctest.cmake | 2 +- cmake/fetch_fmt.cmake | 2 +- cmake/fetch_json.cmake | 2 +- cmake/fetch_miniz.cmake | 5 ++++- cmake/fetch_pugixml.cmake | 2 +- cmake/fetch_valijson.cmake | 2 +- test/JsonSchemaValidatorTest.cxx | 2 +- test/main.cpp | 4 ++-- 11 files changed, 21 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a72ecc6..cbec2b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The model registry can be configured to load the latest available model version, if the requested version is not known. If no appropriate language can be found, english will be chosen. (#8) - In relaxed mode latest available model version loading will be active (#8) +- Updated all thirdparty components (#7) ## [1.0.0] - 2022-11-09 diff --git a/README.md b/README.md index 09c382a..1e985f4 100644 --- a/README.md +++ b/README.md @@ -277,13 +277,13 @@ The library is header only. A build is only necessary if you want to run the tes REXSapi uses the following thirdparty open source software -- [cli11 2.2.0](https://github.com/CLIUtils/CLI11) -- [fmt 8.1.1](https://github.com/fmtlib/fmt) -- [nlohmann json 3.10.5](https://github.com/nlohmann/json) -- [miniz 2.2.0](https://github.com/richgel999/miniz) -- [pugixml 1.12.1](https://github.com/zeux/pugixml) -- [valijson 0.6](https://github.com/tristanpenman/valijson) -- [doctest 2.4.9](https://github.com/doctest/doctest) +- [cli11 2.3.2](https://github.com/CLIUtils/CLI11) +- [fmt 9.1.0](https://github.com/fmtlib/fmt) +- [nlohmann json 3.11.2](https://github.com/nlohmann/json) +- [miniz 3.0.2](https://github.com/richgel999/miniz) +- [pugixml 1.13](https://github.com/zeux/pugixml) +- [valijson 1.0](https://github.com/tristanpenman/valijson) +- [doctest 2.4.10](https://github.com/doctest/doctest) # License REXsapi is licensed under the Apache-2.0 license. diff --git a/cmake/fetch_cli11.cmake b/cmake/fetch_cli11.cmake index b1088a9..31257a1 100644 --- a/cmake/fetch_cli11.cmake +++ b/cmake/fetch_cli11.cmake @@ -1,6 +1,6 @@ FetchContent_Declare( cli11 - URL https://github.com/CLIUtils/CLI11/archive/refs/tags/v2.2.0.tar.gz + URL https://github.com/CLIUtils/CLI11/archive/refs/tags/v2.3.2.tar.gz ) FetchContent_MakeAvailable(cli11) diff --git a/cmake/fetch_doctest.cmake b/cmake/fetch_doctest.cmake index dcf1f55..6292bed 100644 --- a/cmake/fetch_doctest.cmake +++ b/cmake/fetch_doctest.cmake @@ -1,7 +1,7 @@ FetchContent_Declare( doctest GIT_REPOSITORY https://github.com/doctest/doctest - GIT_TAG v2.4.9 + GIT_TAG v2.4.10 ) FetchContent_GetProperties(doctest) diff --git a/cmake/fetch_fmt.cmake b/cmake/fetch_fmt.cmake index 0500cdf..c79c74a 100644 --- a/cmake/fetch_fmt.cmake +++ b/cmake/fetch_fmt.cmake @@ -1,6 +1,6 @@ FetchContent_Declare( fmt - URL https://github.com/fmtlib/fmt/archive/refs/tags/8.1.1.tar.gz + URL https://github.com/fmtlib/fmt/archive/refs/tags/9.1.0.tar.gz ) FetchContent_GetProperties(fmt) diff --git a/cmake/fetch_json.cmake b/cmake/fetch_json.cmake index 6b2976a..bc9c620 100644 --- a/cmake/fetch_json.cmake +++ b/cmake/fetch_json.cmake @@ -1,6 +1,6 @@ FetchContent_Declare( json - URL https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.tar.gz + URL https://github.com/nlohmann/json/archive/refs/tags/v3.11.2.tar.gz ) FetchContent_GetProperties(json) diff --git a/cmake/fetch_miniz.cmake b/cmake/fetch_miniz.cmake index 065e92d..388c108 100644 --- a/cmake/fetch_miniz.cmake +++ b/cmake/fetch_miniz.cmake @@ -1,6 +1,6 @@ FetchContent_Declare( miniz - URL https://github.com/richgel999/miniz/archive/refs/tags/2.2.0.tar.gz + URL https://github.com/richgel999/miniz/archive/refs/tags/3.0.2.tar.gz ) FetchContent_GetProperties(miniz) @@ -32,6 +32,9 @@ if(NOT miniz_POPULATED) string(REPLACE "#include \"${REPLACE_STRING}.h\"" "" AMAL_MINIZ_C "${AMAL_MINIZ_C}") endforeach() + string(REPLACE "static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };" "" AMAL_MINIZ_C "${AMAL_MINIZ_C}") + string(REPLACE "static const mz_uint s_tdefl_num_probes[11];" "static inline const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};" AMAL_MINIZ_C "${AMAL_MINIZ_C}") + string(CONCAT AMAL_MINIZ_H "#define MINIZ_EXPORT\n" "${AMAL_MINIZ_H}") string(CONCAT AMAL_MINIZ_H "${AMAL_MINIZ_H}" "\n#ifndef MINIZ_HEADER_FILE_ONLY\n" diff --git a/cmake/fetch_pugixml.cmake b/cmake/fetch_pugixml.cmake index bac037d..38a2783 100644 --- a/cmake/fetch_pugixml.cmake +++ b/cmake/fetch_pugixml.cmake @@ -1,7 +1,7 @@ FetchContent_Declare( pugixml GIT_REPOSITORY https://github.com/zeux/pugixml - GIT_TAG v1.12.1 + GIT_TAG v1.13 ) if(NOT pugixml_POPULATED) diff --git a/cmake/fetch_valijson.cmake b/cmake/fetch_valijson.cmake index 08dd029..c65460a 100644 --- a/cmake/fetch_valijson.cmake +++ b/cmake/fetch_valijson.cmake @@ -1,6 +1,6 @@ FetchContent_Declare( valijson - URL https://github.com/tristanpenman/valijson/archive/refs/tags/v0.6.tar.gz + URL https://github.com/tristanpenman/valijson/archive/refs/tags/v1.0.tar.gz ) FetchContent_GetProperties(valijson) diff --git a/test/JsonSchemaValidatorTest.cxx b/test/JsonSchemaValidatorTest.cxx index d0bf0b5..649ce56 100644 --- a/test/JsonSchemaValidatorTest.cxx +++ b/test/JsonSchemaValidatorTest.cxx @@ -147,7 +147,7 @@ TEST_CASE("Json schema validator test") CHECK(errors.empty()); CHECK_FALSE(validator.validate(rexsapi::json::parse(invalidValue), errors)); - CHECK(errors.size() == 5); + CHECK(errors.size() == 6); } SUBCASE("Valid complex schema") diff --git a/test/main.cpp b/test/main.cpp index 8022ad3..a38da25 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -16,7 +16,7 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include + #define REXSAPI_MINIZ_IMPL #include - -#include From 270c3c83e456979ad53fac0bcdb8418174541c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Tue, 28 Mar 2023 12:21:01 +0200 Subject: [PATCH 6/9] Added rexs 1.5 model database version (#21) closes #21 --- include/rexsapi/Types.hxx | 4 + models/rexs_model_1.5_de.xml | 5609 ++++++++++++++++++++++ models/rexs_model_1.5_en.xml | 5609 ++++++++++++++++++++++ test/database/FileResourceLoaderTest.cxx | 2 +- test/database/ModelRegistryTest.cxx | 4 +- test/database/XMLModelLoaderTest.cxx | 2 +- 6 files changed, 11226 insertions(+), 4 deletions(-) create mode 100644 models/rexs_model_1.5_de.xml create mode 100644 models/rexs_model_1.5_en.xml diff --git a/include/rexsapi/Types.hxx b/include/rexsapi/Types.hxx index 433517d..9aad2a0 100644 --- a/include/rexsapi/Types.hxx +++ b/include/rexsapi/Types.hxx @@ -352,6 +352,10 @@ namespace rexsapi if (type == "array_of_integer_arrays") { return TValueType::ARRAY_OF_INTEGER_ARRAYS; } + if (type == "date_time") { + // TODO(LCF): just to make the 1.5 version working + return TValueType::STRING; + } throw TException{fmt::format("unknown value type '{}'", type)}; } diff --git a/models/rexs_model_1.5_de.xml b/models/rexs_model_1.5_de.xml new file mode 100644 index 0000000..95b9c1a --- /dev/null +++ b/models/rexs_model_1.5_de.xml @@ -0,0 +1,5609 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/rexs_model_1.5_en.xml b/models/rexs_model_1.5_en.xml new file mode 100644 index 0000000..27f2d8a --- /dev/null +++ b/models/rexs_model_1.5_en.xml @@ -0,0 +1,5609 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/database/FileResourceLoaderTest.cxx b/test/database/FileResourceLoaderTest.cxx index 9448398..05c018d 100644 --- a/test/database/FileResourceLoaderTest.cxx +++ b/test/database/FileResourceLoaderTest.cxx @@ -43,7 +43,7 @@ TEST_CASE("File resource loader test") buffers.emplace_back(buffer); }); - CHECK(buffers.size() == 10); + CHECK(buffers.size() == 12); std::for_each(buffers.begin(), buffers.end(), [](const auto& buf) { checkBuffer(buf); }); diff --git a/test/database/ModelRegistryTest.cxx b/test/database/ModelRegistryTest.cxx index ad673fe..81c4c58 100644 --- a/test/database/ModelRegistryTest.cxx +++ b/test/database/ModelRegistryTest.cxx @@ -54,14 +54,14 @@ TEST_CASE("Test rexs model registry") SUBCASE("Get non existing model non-strict mode") { const auto& model = registry.getModel(rexsapi::TRexsVersion{"1.99"}, "de", false); - CHECK(model.getVersion() == rexsapi::TRexsVersion{"1.4"}); + CHECK(model.getVersion() == rexsapi::TRexsVersion{"1.5"}); CHECK(model.getLanguage() == "de"); } SUBCASE("Get non existing model non-strict mode with unknown language") { const auto& model = registry.getModel(rexsapi::TRexsVersion{"1.99"}, "es", false); - CHECK(model.getVersion() == rexsapi::TRexsVersion{"1.4"}); + CHECK(model.getVersion() == rexsapi::TRexsVersion{"1.5"}); CHECK(model.getLanguage() == "en"); } } diff --git a/test/database/XMLModelLoaderTest.cxx b/test/database/XMLModelLoaderTest.cxx index 88db83a..89728f3 100644 --- a/test/database/XMLModelLoaderTest.cxx +++ b/test/database/XMLModelLoaderTest.cxx @@ -67,7 +67,7 @@ TEST_CASE("XML database model loader test") }); CHECK(result); - REQUIRE(models.size() == 10); + REQUIRE(models.size() == 12); std::set> languages; for (const auto& model : models) { languages.insert(model.getLanguage()); From 4bde9a645e18c01bd07757a38f43c53e0f508956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Tue, 28 Mar 2023 13:23:38 +0200 Subject: [PATCH 7/9] Feature add model database rexs 15 (#22) closes #22 * Added rexs 1.5 model database version * New model files --- models/rexs-dbmodel.xsd | 3 + models/rexs_model_1.5_de.xml | 10498 ++++++++++++++++----------------- models/rexs_model_1.5_en.xml | 10498 ++++++++++++++++----------------- 3 files changed, 10501 insertions(+), 10498 deletions(-) diff --git a/models/rexs-dbmodel.xsd b/models/rexs-dbmodel.xsd index 8df7fb4..8869997 100644 --- a/models/rexs-dbmodel.xsd +++ b/models/rexs-dbmodel.xsd @@ -38,6 +38,7 @@ + @@ -107,6 +108,7 @@ + @@ -125,6 +127,7 @@ + diff --git a/models/rexs_model_1.5_de.xml b/models/rexs_model_1.5_de.xml index 95b9c1a..2f89f81 100644 --- a/models/rexs_model_1.5_de.xml +++ b/models/rexs_model_1.5_de.xml @@ -1,5 +1,5 @@ - - + + @@ -81,5529 +81,5529 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - + + + + + + + + + - - - + + + - - - - + + + + - - + + - - - - - + + + + + - - + + - - - - - - + + + + + + - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - + + + - + - - - + + + - + - - - + + + - + - - + + - + - - + + - + - - + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - - - - + + + + + + - + - - - + + + - + - - + + - + - - - + + + - + - - - - + + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - - - - + + + + + + - + - - - + + + - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - - - - - + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - + + + + + + - - - + + + - - - - + + + + - + - - + + - + - - + + - + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - + - - + + - + - - + + - + - - - - - + + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - - - - - - - - + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - - - + + + - + - - - - + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/rexs_model_1.5_en.xml b/models/rexs_model_1.5_en.xml index 27f2d8a..304a20f 100644 --- a/models/rexs_model_1.5_en.xml +++ b/models/rexs_model_1.5_en.xml @@ -1,5 +1,5 @@ - - + + @@ -81,5529 +81,5529 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - + + + + + + + + + - - - + + + - - - - + + + + - - + + - - - - - + + + + + - - + + - - - - - - + + + + + + - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - + + + - + - - - + + + - + - - - + + + - + - - + + - + - - + + - + - - + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - - - - + + + + + + - + - - - + + + - + - - + + - + - - - + + + - + - - - - + + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - - - - + + + + + + - + - - - + + + - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - - - - - + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - + + + + + + - - - + + + - - - - + + + + - + - - + + - + - - + + - + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - + - - + + - + - - + + - + - - - - - + + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - - - - - - - - + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - - - + + + - + - - - - + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1a15997eb381855af57bc1501f0f7fb5d4e2fa2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Wed, 29 Mar 2023 17:26:44 +0200 Subject: [PATCH 8/9] Feature add date time datatype (#23) closes #20 * Added a date_time type * Refactoring * Added date time to TValue. Added more tests. Updated tests to new value type. --- CMakeLists.txt | 1 + README.md | 19 ++-- cmake/fetch_date.cmake | 10 ++ include/rexsapi/Exception.hxx | 2 +- include/rexsapi/JsonModelSerializer.hxx | 3 + include/rexsapi/JsonSerializer.hxx | 4 + include/rexsapi/JsonValueDecoder.hxx | 33 ++++-- include/rexsapi/Model.hxx | 2 +- include/rexsapi/ModelLoader.hxx | 2 +- include/rexsapi/Types.hxx | 130 ++++++++++++++++++++---- include/rexsapi/ValidityChecker.hxx | 1 + include/rexsapi/Value.hxx | 19 +++- include/rexsapi/Value_Details.hxx | 14 ++- include/rexsapi/XMLModelSerializer.hxx | 3 + include/rexsapi/XMLValueDecoder.hxx | 36 +++++-- models/rexs-schema.json | 9 ++ src/CMakeLists.txt | 1 + test/ConversionHelperTest.cxx | 10 +- test/JsonModelLoaderTest.cxx | 58 ++++++----- test/JsonModelSerializerTest.cxx | 4 +- test/JsonValueDecoderTest.cxx | 21 ++++ test/ModelBuilderTest.cxx | 10 +- test/ModelVisitorTest.cxx | 4 +- test/TestModel.hxx | 7 +- test/TypesTest.cxx | 44 +++++++- test/ValueTest.cxx | 10 ++ test/ValueTypeTest.cxx | 10 ++ test/XMLModelLoaderTest.cxx | 71 +++++++------ test/XMLModelSerializerTest.cxx | 4 +- test/XMLValueDecoderTest.cxx | 15 +++ 30 files changed, 437 insertions(+), 120 deletions(-) create mode 100644 cmake/fetch_date.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index bb65b0d..5825b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ option(BUILD_WITH_DOCS "Build documentation" ${REXSAPI_MASTER_PROJECT}) include(cmake/create_docs.cmake) include(cmake/fetch_cli11.cmake) +include(cmake/fetch_date.cmake) include(cmake/fetch_fmt.cmake) include(cmake/fetch_json.cmake) include(cmake/fetch_miniz.cmake) diff --git a/README.md b/README.md index 1e985f4..f269c9a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![Supported Platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20Windows%20%7C%20Mac-blue.svg) ![License: Apache 2](https://img.shields.io/badge/license-Apache%202-blue) ![Language: C++17](https://img.shields.io/badge/language-C%2B%2B17-blue.svg) -![Version:](https://img.shields.io/badge/version-1.0.0-green) +![Version:](https://img.shields.io/badge/version-1.1.0-green) [![GitHub Build Status](https://github.com/fva-net/rexs-api-cpp/workflows/CMake%20Build%20Matrix/badge.svg)](https://github.com/fva-net/rexs-api-cpp/actions) [![Coverage Status](https://coveralls.io/repos/github/BearinxSimulationSuite/REXSapi/badge.svg?branch=main)](https://coveralls.io/github/BearinxSimulationSuite/REXSapi?branch=main) @@ -11,11 +11,11 @@ The REXSapi library is a C++ implementation of the [REXS specification](https:// # Status -The project is now in beta phase and the API should be stable. You can checkout the library and play with it. Probably still a bit early for production use, though. +The project is now released and is already used in production. However, the API will probably still change a bit due to the adaption of the 1.5 standards version. # Supported REXS Versions -The library uses REXS database model files in order to validate REXS model files. Database model files can be downloaded from the [REXS database page](https://database.rexs.info/). Currently, the implementation supports versions 1.0 to 1.4, but newer database files should also work. Version 1.0 to 1.4 database model files in english and german can also be found in the models directory of this project. +The library uses REXS database model files in order to validate REXS model files. Database model files can be downloaded from the [REXS database page](https://database.rexs.info/). Currently, the implementation supports versions 1.0 to 1.5, but newer database files should also work. Version 1.0 to 1.5 database model files in english and german can also be found in the models directory of this project. The library supports REXS model files in xml and json format. Compressed REXS zip archives can also be loaded. The loading and storing mechanism can be easily extended to support other sources besides files for model loading and storing. @@ -32,7 +32,7 @@ You need a C++17 compatible compiler to use the library. In order to use REXSapi it is most convinient to just include the `Rexsapi.hxx` header. Mind that you have to include this header along the `REXSAPI_MINIZ_IMPL` define right before the include in *exactly* one compilation unit (cpp file) in order to add the miniz implementation to the project. -```c++ +```cpp #define REXSAPI_MINIZ_IMPL #include ``` @@ -41,7 +41,7 @@ In order to use REXSapi it is most convinient to just include the `Rexsapi.hxx` Loading a REXS model file is straight forward. You need the REXS database model files for the API to validate the model. -```c++ +```cpp const rexsapi::TModelLoader loader{"/path/to/rexs/database/models"}; rexsapi::TResult result; const std::optional model = @@ -62,7 +62,7 @@ The `TModelLoader` class can load json and xml REXS model files. If successful, The Model itself provides methods for accessing every aspect of a model. -```c++ +```cpp const rexsapi::TModel model = loadModel(); for (const auto& relation : model.getRelations()) { for (const auto& ref : relation.getReferences()) { @@ -82,7 +82,7 @@ Alternatively, if the model shall be processed in a complete way, the `TModelVis The most reliable way to create a REXS model is to use the `TModelBuilder` class. It can create every aspect of a model, be it components, relations, or load spectrum, of a REXS model and highly abstracts the construction of REXS standard compliant models. The `TModelBuilder` needs a specific REXS database model for checking and validating the model. Most model builder methods return a reference to the model builder in order to allow chaining of method calls resulting in dense easy to read code. -```c++ +```cpp const auto registry = rexsapi::createModelRegistry("/path/to/rexs/database/models"); const auto& databaseModel = registry.getModel(rexsapi::TRexsVersion{"1.4"}, "en"); rexsapi::TModelBuilder modelBuilder{databaseModel}; @@ -111,7 +111,7 @@ If all necessary components have been added, you can start to add relations that Saving a REXS model to a file is straight forward using the `TModelSaver` convenience class. -```c++ +```cpp const rexsapi::TModel model = createModel(); rexsapi::TResult result; rexsapi::TModelSaver{}.store(result, model, "/path/to/your/rexs/model/file", @@ -278,12 +278,13 @@ The library is header only. A build is only necessary if you want to run the tes REXSapi uses the following thirdparty open source software - [cli11 2.3.2](https://github.com/CLIUtils/CLI11) +- [date 3.0.1](https://github.com/HowardHinnant/date) +- [doctest 2.4.10](https://github.com/doctest/doctest) - [fmt 9.1.0](https://github.com/fmtlib/fmt) - [nlohmann json 3.11.2](https://github.com/nlohmann/json) - [miniz 3.0.2](https://github.com/richgel999/miniz) - [pugixml 1.13](https://github.com/zeux/pugixml) - [valijson 1.0](https://github.com/tristanpenman/valijson) -- [doctest 2.4.10](https://github.com/doctest/doctest) # License REXsapi is licensed under the Apache-2.0 license. diff --git a/cmake/fetch_date.cmake b/cmake/fetch_date.cmake new file mode 100644 index 0000000..04a56a3 --- /dev/null +++ b/cmake/fetch_date.cmake @@ -0,0 +1,10 @@ +FetchContent_Declare( + date + URL https://github.com/HowardHinnant/date/archive/refs/tags/v3.0.1.tar.gz +) + +FetchContent_GetProperties(date) + +if(NOT date_POPULATED) + FetchContent_Populate(date) +endif() diff --git a/include/rexsapi/Exception.hxx b/include/rexsapi/Exception.hxx index 54bf105..d260841 100644 --- a/include/rexsapi/Exception.hxx +++ b/include/rexsapi/Exception.hxx @@ -22,7 +22,7 @@ namespace rexsapi { /** - * @brief Exception class for all REXSapi exceptions + * @brief Exception class for all REXS exceptions * * There is only one exception type and no exception hierarchie. */ diff --git a/include/rexsapi/JsonModelSerializer.hxx b/include/rexsapi/JsonModelSerializer.hxx index f94426b..24a73dd 100644 --- a/include/rexsapi/JsonModelSerializer.hxx +++ b/include/rexsapi/JsonModelSerializer.hxx @@ -217,6 +217,9 @@ namespace rexsapi [&j](rexsapi::TFileReferenceTag, const auto& s) -> void { j = s; }, + [&j](rexsapi::TDatetimeTag, const auto& d) -> void { + j = d.asUTCString(); + }, [&j, &attribute](rexsapi::TFloatArrayTag, const auto& a) -> void { encodeCodedArray(j, attribute.getValue().coded(), a); }, diff --git a/include/rexsapi/JsonSerializer.hxx b/include/rexsapi/JsonSerializer.hxx index c65c01d..c8978e7 100644 --- a/include/rexsapi/JsonSerializer.hxx +++ b/include/rexsapi/JsonSerializer.hxx @@ -27,6 +27,8 @@ namespace rexsapi /** * @brief Outputs a json object into a string * + * Will add a UTF-8 BOM to the beginning of the buffer. + * */ class TJsonStringSerializer { @@ -54,6 +56,8 @@ namespace rexsapi /** * @brief Outputs a json object into a file * + * Will add a UTF-8 BOM to the beginning of the file. + * */ class TJsonFileSerializer { diff --git a/include/rexsapi/JsonValueDecoder.hxx b/include/rexsapi/JsonValueDecoder.hxx index eb97ee9..11cfc4f 100644 --- a/include/rexsapi/JsonValueDecoder.hxx +++ b/include/rexsapi/JsonValueDecoder.hxx @@ -94,7 +94,8 @@ namespace rexsapi::detail const rexsapi::json& node) const override { auto value = node.at("string").get(); - return std::make_pair(TValue{value}, !value.empty() ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); + auto empty = value.empty(); + return std::make_pair(TValue{std::move(value)}, !empty ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); } }; @@ -113,7 +114,8 @@ namespace rexsapi::detail const rexsapi::json& node) const override { auto value = node.at("file_reference").get(); - return std::make_pair(TValue{value}, !value.empty() ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); + auto empty = value.empty(); + return std::make_pair(TValue{std::move(value)}, !empty ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); } }; @@ -206,11 +208,29 @@ namespace rexsapi::detail auto value = node.at("enum").get(); if (enumValue) { - return std::make_pair(TValue{value}, - enumValue->check(value) ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); + auto check = enumValue->check(value); + return std::make_pair(TValue{std::move(value)}, check ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); } /// No enum values means this is a custom enum attribute, so accept any text - return std::make_pair(TValue{value}, TDecoderResult::SUCCESS); + return std::make_pair(TValue{std::move(value)}, TDecoderResult::SUCCESS); + } + }; + + class TDatetimeDecoder : public TJsonDecoder + { + public: + using Type = double; + + bool isEmpty(const rexsapi::json& node) const noexcept override + { + return node.at("date_time").is_null(); + } + + private: + std::pair onDecode(const std::optional&, + const rexsapi::json& node) const override + { + return std::make_pair(TValue{TDatetime{node.at("date_time").get()}}, TDecoderResult::SUCCESS); } }; @@ -359,7 +379,7 @@ namespace rexsapi::detail } matrix.m_Values.emplace_back(std::move(r)); } - bool result = matrix.validate(); + const bool result = matrix.validate(); return std::make_pair(TValue{std::move(matrix)}, result ? TDecoderResult::SUCCESS : TDecoderResult::FAILURE); } std::string m_Name; @@ -475,6 +495,7 @@ namespace rexsapi::detail m_Decoder[TValueType::FLOATING_POINT] = std::make_unique(); m_Decoder[TValueType::STRING] = std::make_unique(); m_Decoder[TValueType::ENUM] = std::make_unique(); + m_Decoder[TValueType::DATE_TIME] = std::make_unique(); m_Decoder[TValueType::INTEGER_ARRAY] = std::make_unique>("integer_array"); m_Decoder[TValueType::FLOATING_POINT_ARRAY] = std::make_unique>("floating_point_array"); diff --git a/include/rexsapi/Model.hxx b/include/rexsapi/Model.hxx index 70289d5..bcca75f 100644 --- a/include/rexsapi/Model.hxx +++ b/include/rexsapi/Model.hxx @@ -81,7 +81,7 @@ namespace rexsapi /** * @brief Represents a REXS model loaded from a file or created by the TModelBuilder * - * A TModel instance is the main REXSapi object that abstracts a complete REXS model as described by the REXS + * A TModel instance is the main REXS object that abstracts a complete REXS model as described by the REXS * standard. It can be queried for meta information, components, relations, and load spectrum, drilling down to * attributes and values using getters from components and relations. * diff --git a/include/rexsapi/ModelLoader.hxx b/include/rexsapi/ModelLoader.hxx index ef0620b..2612390 100644 --- a/include/rexsapi/ModelLoader.hxx +++ b/include/rexsapi/ModelLoader.hxx @@ -46,7 +46,7 @@ namespace rexsapi * All allowed kinds of REXS model files can be loaded trasparently with this loader. The loader will also create it's * own model registry. For the successful creation of the model registry, all schema files have to be available to * the loader. Additionally, all necessary REXS database model files for different versions and languages have to be - * available. The REXSapi project contains the directory ```models``` with all relevant files that can be used with + * available. The REXS project contains the directory ```models``` with all relevant files that can be used with * the loader. * * Allows loading of multiple REXS model files with the same loader. diff --git a/include/rexsapi/Types.hxx b/include/rexsapi/Types.hxx index 9aad2a0..30952d6 100644 --- a/include/rexsapi/Types.hxx +++ b/include/rexsapi/Types.hxx @@ -17,9 +17,11 @@ #ifndef REXSAPI_TYPES_HXX #define REXSAPI_TYPES_HXX +#include #include #include +#include #include namespace rexsapi @@ -29,23 +31,24 @@ namespace rexsapi * */ enum class TValueType : uint8_t { - FLOATING_POINT, //!< floating_point - BOOLEAN, //!< boolean - INTEGER, //!< integer - ENUM, //!< enum - STRING, //!< string - FILE_REFERENCE, //!< file_reference - FLOATING_POINT_ARRAY, //!< floating_point_array - BOOLEAN_ARRAY, //!< boolean_array - INTEGER_ARRAY, //!< integer_array - STRING_ARRAY, //!< string_array - ENUM_ARRAY, //!< enum_array - REFERENCE_COMPONENT, //!< reference_component - FLOATING_POINT_MATRIX, //!< floating_point_matrix - INTEGER_MATRIX, //!< integer_matrix - BOOLEAN_MATRIX, //!< boolean_matrix - STRING_MATRIX, //!< string_matrix - ARRAY_OF_INTEGER_ARRAYS //!< array_of_integer_arrays + FLOATING_POINT, //!< floating_point + BOOLEAN, //!< boolean + INTEGER, //!< integer + ENUM, //!< enum + STRING, //!< string + FILE_REFERENCE, //!< file_reference + FLOATING_POINT_ARRAY, //!< floating_point_array + BOOLEAN_ARRAY, //!< boolean_array + INTEGER_ARRAY, //!< integer_array + STRING_ARRAY, //!< string_array + ENUM_ARRAY, //!< enum_array + REFERENCE_COMPONENT, //!< reference_component + FLOATING_POINT_MATRIX, //!< floating_point_matrix + INTEGER_MATRIX, //!< integer_matrix + BOOLEAN_MATRIX, //!< boolean_matrix + STRING_MATRIX, //!< string_matrix + ARRAY_OF_INTEGER_ARRAYS, //!< array_of_integer_arrays + DATE_TIME //!< date_time }; /** @@ -187,6 +190,94 @@ namespace rexsapi }; + /** + * @brief Represents the REXS date_time type + * + */ + class TDatetime + { + public: + using time_point = std::chrono::time_point; + + /** + * @brief Construct a new TDatetime object from a string + * + * @param datetime The string has to be in ISO8601 format `yyyy-mm-ddThh:mm:ss[+/-]` + * @throws std::exception if the string cannot be parsed or the date time is invalid + */ + explicit TDatetime(const std::string& datetime) + { + auto op = date::parse("%FT%T%Ez", m_Timepoint); + std::istringstream in{datetime}; + in >> op; + + if (!in.good()) { + throw std::runtime_error{"illegal date specified: " + datetime}; + } + } + + /** + * @brief Construct a new TDatetime object from a std::chrono::time_point + * + * @param datetime A time point + */ + explicit TDatetime(time_point datetime) noexcept + : m_Timepoint{datetime} + { + } + + friend bool operator==(const TDatetime& lhs, const TDatetime& rhs) noexcept + { + return lhs.m_Timepoint == rhs.m_Timepoint; + } + + /** + * @brief Returns a new TDatetime object constructed with the current date and time + * + * @return A new TDatetime object set to the current date and time + */ + static TDatetime now() noexcept + { + return TDatetime{std::chrono::time_point_cast(std::chrono::system_clock::now())}; + } + + /** + * @brief Returns the UTC string representation in ISO8601 format `yyyy-mm-ddThh:mm:ss[+/-]`. + * The offset will always be +00:00. + * + * @return The UTC string representation + */ + inline std::string asUTCString() const + { + return date::format("%FT%T%Ez", m_Timepoint); + } + + /** + * @brief Returns the locale string representation in ISO8601 format `yyyy-mm-ddThh:mm:ss[+/-]`. + * The offset will be set to the current timezone offset from UTC. + * + * @return The locale string representation + */ + inline std::string asLocaleString() const + { + return getTimeStringISO8601(m_Timepoint); + } + + /** + * @brief Returns the time point + * + * @return time_point + */ + inline time_point asTimepoint() const noexcept + { + return m_Timepoint; + } + + private: + time_point m_Timepoint; + }; + + /** * @brief Represents all currently allowed REXS relation types * @@ -353,8 +444,7 @@ namespace rexsapi return TValueType::ARRAY_OF_INTEGER_ARRAYS; } if (type == "date_time") { - // TODO(LCF): just to make the 1.5 version working - return TValueType::STRING; + return TValueType::DATE_TIME; } throw TException{fmt::format("unknown value type '{}'", type)}; } @@ -396,6 +486,8 @@ namespace rexsapi return "string_matrix"; case TValueType::ARRAY_OF_INTEGER_ARRAYS: return "array_of_integer_arrays"; + case TValueType::DATE_TIME: + return "date_time"; } throw TException{fmt::format("unknown value type '{}'", static_cast(type))}; } diff --git a/include/rexsapi/ValidityChecker.hxx b/include/rexsapi/ValidityChecker.hxx index 5e2608d..232bf47 100644 --- a/include/rexsapi/ValidityChecker.hxx +++ b/include/rexsapi/ValidityChecker.hxx @@ -103,6 +103,7 @@ namespace rexsapi::detail case TValueType::BOOLEAN_MATRIX: case TValueType::STRING_MATRIX: case TValueType::REFERENCE_COMPONENT: + case TValueType::DATE_TIME: return true; } diff --git a/include/rexsapi/Value.hxx b/include/rexsapi/Value.hxx index 25f8388..67298d3 100644 --- a/include/rexsapi/Value.hxx +++ b/include/rexsapi/Value.hxx @@ -57,6 +57,7 @@ namespace rexsapi /** * @brief Constructs a new empty TValue object * + * TValue::isEmpty will return true for default constructed TValue objects. */ TValue() = default; @@ -243,6 +244,8 @@ namespace rexsapi return std::holds_alternative(m_Value); case TValueType::STRING: return std::holds_alternative(m_Value); + case TValueType::DATE_TIME: + return std::holds_alternative(m_Value); case TValueType::FILE_REFERENCE: return std::holds_alternative(m_Value); case TValueType::FLOATING_POINT_ARRAY: @@ -282,9 +285,9 @@ namespace rexsapi std::function, std::function, std::function, std::function, std::function, std::function, - std::function, std::function, - std::function, std::function, - std::function, + std::function, std::function, + std::function, std::function, + std::function, std::function, std::function, std::function, std::function, std::function, @@ -383,6 +386,9 @@ namespace rexsapi [](const int64_t& i) -> std::string { return fmt::format("{}", i); }, + [](const TDatetime& d) -> std::string { + return d.asLocaleString(); + }, [](const std::vector& array) -> std::string { return detail::arrayToString(array, [](const auto& val) { return format(val); @@ -471,6 +477,13 @@ namespace rexsapi } break; } + case TValueType::DATE_TIME: { + auto c = std::get>(funcs); + if (c) { + return c(TDatetimeTag(), value.getValue()); + } + break; + } case TValueType::FILE_REFERENCE: { auto c = std::get>(funcs); if (c) { diff --git a/include/rexsapi/Value_Details.hxx b/include/rexsapi/Value_Details.hxx index 28d37ea..68efe93 100644 --- a/include/rexsapi/Value_Details.hxx +++ b/include/rexsapi/Value_Details.hxx @@ -33,9 +33,9 @@ namespace rexsapi overload(Ts...) -> overload; using Variant = - std::variant, std::vector, - std::vector, std::vector, std::vector>, TMatrix, - TMatrix, TMatrix, TMatrix>; + std::variant, + std::vector, std::vector, std::vector, std::vector>, + TMatrix, TMatrix, TMatrix, TMatrix>; template inline const auto& value_getter(const Variant& value) @@ -90,6 +90,11 @@ namespace rexsapi using Type = std::string; }; + template<> + struct TypeForValueType> { + using Type = TDatetime; + }; + template<> struct TypeForValueType> { using Type = std::string; @@ -161,6 +166,8 @@ namespace rexsapi Type; //!< The C++ type for the enum value type. Should always be used instead of the actual C++ type. using TStringType = detail::TypeForValueType>:: Type; //!< The C++ type for the string value type. Should always be used instead of the actual C++ type. + using TDatetimeType = detail::TypeForValueType>:: + Type; //!< The C++ type for the date_time value type. Should always be used instead of the actual C++ type. using TFileReferenceType = detail::TypeForValueType>:: Type; //!< The C++ type for the file_reference value type. Should always be used instead of the actual C++ type. @@ -200,6 +207,7 @@ namespace rexsapi using TBoolTag = detail::Enum2type; using TEnumTag = detail::Enum2type; using TStringTag = detail::Enum2type; + using TDatetimeTag = detail::Enum2type; using TFileReferenceTag = detail::Enum2type; using TFloatArrayTag = detail::Enum2type; using TBoolArrayTag = detail::Enum2type; diff --git a/include/rexsapi/XMLModelSerializer.hxx b/include/rexsapi/XMLModelSerializer.hxx index a6e8ddf..6cbf154 100644 --- a/include/rexsapi/XMLModelSerializer.hxx +++ b/include/rexsapi/XMLModelSerializer.hxx @@ -243,6 +243,9 @@ namespace rexsapi [&attNode](rexsapi::TFileReferenceTag, const auto& s) -> void { attNode.append_child(pugi::node_pcdata).set_value(s.c_str()); }, + [&attNode](rexsapi::TDatetimeTag, const auto& d) -> void { + attNode.append_child(pugi::node_pcdata).set_value(d.asUTCString().data()); + }, [&attNode, &attribute](rexsapi::TFloatArrayTag, const auto& a) -> void { xmlEncodeCodedArray(attNode, attribute.getValue(), a, [](double element) { return format(element); diff --git a/include/rexsapi/XMLValueDecoder.hxx b/include/rexsapi/XMLValueDecoder.hxx index 1c0e28b..e7e34ca 100644 --- a/include/rexsapi/XMLValueDecoder.hxx +++ b/include/rexsapi/XMLValueDecoder.hxx @@ -159,6 +159,23 @@ namespace rexsapi::detail } }; + class TDatetimeDecoder : public TXMLDecoder + { + public: + using Type = std::string; + + private: + std::pair onDecode(const std::optional&, + const pugi::xml_node& node) const override + { + try { + return std::make_pair(TValue{TDatetime{node.child_value()}}, TDecoderResult::SUCCESS); + } catch (const std::exception&) { + return std::make_pair(TValue{}, TDecoderResult::FAILURE); + } + } + }; + template class TArrayDecoder : public TXMLDecoder { @@ -170,7 +187,7 @@ namespace rexsapi::detail const pugi::xml_node& node) const override { std::vector array; - ElementDecoder decoder; + const ElementDecoder decoder; TDecoderResult result{TDecoderResult::SUCCESS}; for (const auto& arrayNode : node.select_nodes("array/c")) { const auto [value, res] = decoder.decode(enumValue, arrayNode.node()); @@ -232,7 +249,7 @@ namespace rexsapi::detail const pugi::xml_node& node) const override { TMatrix matrix; - ElementDecoder decoder; + const ElementDecoder decoder; bool result{true}; for (const auto& row : node.select_nodes("matrix/r")) { @@ -279,24 +296,28 @@ namespace rexsapi::detail case detail::TCodedValueType::Int32: { value = detail::TCodedValueMatrixDecoder< typename TMatrixDecoder::type, - detail::Enum2type>::decode(child.child_value(), columns, rows); + detail::Enum2type>::decode(child.child_value(), + columns, rows); break; } case detail::TCodedValueType::Float32: { value = detail::TCodedValueMatrixDecoder< typename TMatrixDecoder::type, - detail::Enum2type>::decode(child.child_value(), columns, rows); + detail::Enum2type>::decode(child.child_value(), + columns, rows); break; } case detail::TCodedValueType::Float64: { value = detail::TCodedValueMatrixDecoder< typename TMatrixDecoder::type, - detail::Enum2type>::decode(child.child_value(), columns, rows); + detail::Enum2type>::decode(child.child_value(), + columns, rows); break; } } if (codedType != detail::TCodedValueType::None) { - if (value.getValue::type>>().m_Values.size() != rows || value.getValue::type>>().m_Values[0].size() != columns) { + if (value.getValue::type>>().m_Values.size() != rows || + value.getValue::type>>().m_Values[0].size() != columns) { throw TException{"decoded matrix size does not correspond to configured size"}; } } @@ -314,7 +335,7 @@ namespace rexsapi::detail const pugi::xml_node& node) const override { std::vector> arrays; - ElementDecoder decoder; + const ElementDecoder decoder; TDecoderResult result{TDecoderResult::SUCCESS}; for (const auto& row : node.select_nodes("array_of_arrays/array")) { @@ -350,6 +371,7 @@ namespace rexsapi::detail m_Decoder[TValueType::FLOATING_POINT] = std::make_unique(); m_Decoder[TValueType::STRING] = std::make_unique(); m_Decoder[TValueType::ENUM] = std::make_unique(); + m_Decoder[TValueType::DATE_TIME] = std::make_unique(); m_Decoder[TValueType::INTEGER_ARRAY] = std::make_unique>(); m_Decoder[TValueType::FLOATING_POINT_ARRAY] = std::make_unique>(); m_Decoder[TValueType::BOOLEAN_ARRAY] = std::make_unique>(); diff --git a/models/rexs-schema.json b/models/rexs-schema.json index 3e25dcf..184e562 100644 --- a/models/rexs-schema.json +++ b/models/rexs-schema.json @@ -239,6 +239,15 @@ }, "required": ["file_reference"] }, + { + "type": "object", + "properties": { + "date_time": { + "type": ["null", "string"] + } + }, + "required": ["date_time"] + }, { "type": "object", "properties": { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e374e63..12c7c6b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,7 @@ target_sources(rexsapi INTERFACE ) target_include_directories(rexsapi INTERFACE $) +target_include_directories(rexsapi SYSTEM INTERFACE "${date_SOURCE_DIR}/include") target_include_directories(rexsapi SYSTEM INTERFACE "${fmt_SOURCE_DIR}/include") target_include_directories(rexsapi SYSTEM INTERFACE "${json_SOURCE_DIR}/single_include") target_include_directories(rexsapi SYSTEM INTERFACE "${pugixml_SOURCE_DIR}/src") diff --git a/test/ConversionHelperTest.cxx b/test/ConversionHelperTest.cxx index b94777f..ba7b862 100644 --- a/test/ConversionHelperTest.cxx +++ b/test/ConversionHelperTest.cxx @@ -86,8 +86,8 @@ TEST_CASE("Conversion double test") doctest::Approx(std::numeric_limits::max())); CHECK(rexsapi::convertToDouble(std::to_string(std::numeric_limits::min())) == doctest::Approx(std::numeric_limits::min())); - double d = rexsapi::convertToDouble("37.849999999999"); - auto s = rexsapi::format(d); + const double d = rexsapi::convertToDouble("37.849999999999"); + const auto s = rexsapi::format(d); CHECK(s == "37.849999999999"); } @@ -102,10 +102,10 @@ TEST_CASE("Time helper") { SUBCASE("ISO8601 date") { - auto s = rexsapi::getTimeStringISO8601(std::chrono::system_clock::now()); + const auto s = rexsapi::getTimeStringISO8601(std::chrono::system_clock::now()); std::regex reg_expr(R"(^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-](\d{2}):(\d{2})$)"); std::smatch match; - REQUIRE(std::regex_match(s, match, reg_expr)); + CHECK(std::regex_match(s, match, reg_expr)); } } @@ -113,7 +113,7 @@ TEST_CASE("String helper") { SUBCASE("To upper") { - std::string s{"Some lower and some Upper ChaRacter"}; + const std::string s{"Some lower and some Upper ChaRacter"}; CHECK(rexsapi::toupper(s) == "SOME LOWER AND SOME UPPER CHARACTER"); } } diff --git a/test/JsonModelLoaderTest.cxx b/test/JsonModelLoaderTest.cxx index 9b24f54..9c42287 100644 --- a/test/JsonModelLoaderTest.cxx +++ b/test/JsonModelLoaderTest.cxx @@ -28,8 +28,8 @@ namespace const rexsapi::database::TModelRegistry& registry, rexsapi::TMode mode = rexsapi::TMode::STRICT_MODE) { - rexsapi::TFileJsonSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.json"}; - rexsapi::TJsonSchemaValidator jsonValidator{schemaLoader}; + const rexsapi::TFileJsonSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.json"}; + const rexsapi::TJsonSchemaValidator jsonValidator{schemaLoader}; rexsapi::detail::TFileModelLoader loader{jsonValidator, path}; @@ -41,7 +41,7 @@ namespace "applicationId":"Bearinx", "applicationVersion":"12.0.8823", "date":"2021-07-01T12:18:38+01:00", - "version":"1.4", + "version":"1.5", "relations":[ { "id":48, @@ -105,6 +105,10 @@ namespace "id":"account_for_gravity", "boolean":true }, + { + "id":"modification_date", + "date_time":"2023-03-29T11:46:00+02:00" + }, { "id":"u_axis_vector", "unit":"mm", @@ -205,8 +209,8 @@ namespace TEST_CASE("Json model loader test") { - rexsapi::TFileJsonSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.json"}; - rexsapi::TJsonSchemaValidator validator{schemaLoader}; + const rexsapi::TFileJsonSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.json"}; + const rexsapi::TJsonSchemaValidator validator{schemaLoader}; rexsapi::TResult result; const auto registry = createModelRegistry(); @@ -214,7 +218,7 @@ TEST_CASE("Json model loader test") { rexsapi::detail::TBufferModelLoader loader{validator, MemModel}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK_FALSE(result); REQUIRE(result.getErrors().size() == 4); CHECK(result.getErrors()[0].getMessage() == @@ -226,20 +230,27 @@ TEST_CASE("Json model loader test") "load_case id=1: attribute id=load_duration_fraction is not part of component gear_unit id=1"); CHECK_FALSE(result.isCritical()); REQUIRE(model); + CHECK(model->getInfo().getVersion() == rexsapi::TRexsVersion{1, 5}); REQUIRE(model->getComponents().size() == 4); + CHECK(model->getComponents()[0].getName() == "Transmission unit"); + REQUIRE(model->getComponents()[0].getAttributes().size() == 8); + CHECK(model->getComponents()[0].getAttributes()[4].getName() == "Modification date"); + CHECK(model->getComponents()[0].getAttributes()[4].getValue().asUTCString() == + "2023-03-29T09:46:00+00:00"); REQUIRE(model->getRelations().size() == 2); CHECK(model->getLoadSpectrum().hasLoadCases()); REQUIRE(model->getLoadSpectrum().getLoadCases().size() == 1); REQUIRE(model->getLoadSpectrum().getLoadCases()[0].getLoadComponents().size() == 2); - CHECK(model->getLoadSpectrum().getLoadCases()[0].getLoadComponents()[0].getAttributes().size() == 8); + CHECK(model->getLoadSpectrum().getLoadCases()[0].getLoadComponents()[0].getAttributes().size() == 9); CHECK(model->getLoadSpectrum().getLoadCases()[0].getLoadComponents()[0].getLoadAttributes().size() == 1); REQUIRE(model->getLoadSpectrum().hasAccumulation()); } SUBCASE("Load complex model from file in strict mode") { - auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexsj", - registry, rexsapi::TMode::STRICT_MODE); + const auto model = + loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexsj", registry, + rexsapi::TMode::STRICT_MODE); REQUIRE(model); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); @@ -273,8 +284,9 @@ TEST_CASE("Json model loader test") SUBCASE("Load complex model from file in relaxed mode") { - auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexsj", - registry, rexsapi::TMode::RELAXED_MODE); + const auto model = + loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexsj", registry, + rexsapi::TMode::RELAXED_MODE); REQUIRE(model); CHECK(result); CHECK_FALSE(result.isCritical()); @@ -308,8 +320,8 @@ TEST_CASE("Json model loader test") SUBCASE("Load complex model without loadmodel from file") { - auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA_worm_stage_1-4.rexsj", registry, - rexsapi::TMode::RELAXED_MODE); + const auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA_worm_stage_1-4.rexsj", + registry, rexsapi::TMode::RELAXED_MODE); REQUIRE(model); CHECK(result); CHECK_FALSE(result.isCritical()); @@ -318,7 +330,7 @@ TEST_CASE("Json model loader test") SUBCASE("Load model from non-existent file failure") { - auto model = loadModel(result, "non-exising-file.rexsj", registry); + const auto model = loadModel(result, "non-exising-file.rexsj", registry); CHECK_FALSE(model); CHECK_FALSE(result); CHECK(result.isCritical()); @@ -328,7 +340,7 @@ TEST_CASE("Json model loader test") SUBCASE("Load model from directory failure") { - auto model = loadModel(result, projectDir(), registry); + const auto model = loadModel(result, projectDir(), registry); CHECK_FALSE(model); CHECK_FALSE(result); CHECK(result.isCritical()); @@ -338,7 +350,7 @@ TEST_CASE("Json model loader test") SUBCASE("Load incorrect json document") { - std::string buffer = R"({ + const std::string buffer = R"({ "model":{ "applicationId":"Bearinx", "applicationVersion":"12.0.8823", @@ -460,7 +472,7 @@ TEST_CASE("Json model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK(result); CHECK(result.getErrors().size() == 10); CHECK_FALSE(result.isCritical()); @@ -469,7 +481,7 @@ TEST_CASE("Json model loader test") SUBCASE("Load invalid json document") { - std::string buffer = R"({ + const std::string buffer = R"({ "model":{ "applicationId":"Bearinx", "applicationVersion":"12.0.8823", @@ -481,7 +493,7 @@ TEST_CASE("Json model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK_FALSE(result); CHECK(result.isCritical()); CHECK_FALSE(model); @@ -489,7 +501,7 @@ TEST_CASE("Json model loader test") SUBCASE("Load broken json document") { - std::string buffer = R"({ + const std::string buffer = R"({ "model":{ "applicationId":"Bearinx", "applicationVersion":"12.0.8823", @@ -498,7 +510,7 @@ TEST_CASE("Json model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK_FALSE(result); CHECK(result.isCritical()); CHECK_FALSE(model); @@ -507,10 +519,10 @@ TEST_CASE("Json model loader test") SUBCASE("Load valid document with unkown version") { std::string buffer{MemModel}; - replace(buffer, R"("version":"1.4")", R"("version":"1.99")"); + replace(buffer, R"("version":"1.5")", R"("version":"1.99")"); rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); REQUIRE(model); diff --git a/test/JsonModelSerializerTest.cxx b/test/JsonModelSerializerTest.cxx index 056cce2..604510c 100644 --- a/test/JsonModelSerializerTest.cxx +++ b/test/JsonModelSerializerTest.cxx @@ -52,7 +52,7 @@ namespace TEST_CASE("Json serialize new model") { - const auto& dbModel = loadModel("1.4"); + const auto& dbModel = loadModel("1.5"); rexsapi::TJsonModelSerializer modelSerializer; SUBCASE("Serialize model to memory") @@ -67,7 +67,7 @@ TEST_CASE("Json serialize new model") CHECK(roundtripModel.getInfo().getApplicationId() == "REXSApi Unit Test"); CHECK(roundtripModel.getInfo().getApplicationVersion() == "1.0"); CHECK(roundtripModel.getInfo().getDate() == "2022-05-20T08:59:10+01:00"); - CHECK(roundtripModel.getInfo().getVersion() == rexsapi::TRexsVersion{1, 4}); + CHECK(roundtripModel.getInfo().getVersion() == rexsapi::TRexsVersion{1, 5}); REQUIRE(roundtripModel.getInfo().getApplicationLanguage().has_value()); CHECK(*roundtripModel.getInfo().getApplicationLanguage() == "en"); CHECK(roundtripModel.getComponents().size() == 7); diff --git a/test/JsonValueDecoderTest.cxx b/test/JsonValueDecoderTest.cxx index aed205b..8342a80 100644 --- a/test/JsonValueDecoderTest.cxx +++ b/test/JsonValueDecoderTest.cxx @@ -42,6 +42,7 @@ TEST_CASE("Json value decoder test") "enum": { "enum": "injection_lubrication" }, "reference component": { "reference_component": 17 }, "file reference": { "file_reference": "/root/my/path" }, + "date time": { "date_time": "2022-06-05T04:50:27+04:00" }, "float array": { "floating_point_array": [1.0, 2.0, 3.0] }, "coded float array": { "floating_point_array_coded": { "code": "float32", "value": "MveeQZ6hM0I" } }, "coded float64 array": { "floating_point_array_coded": { "code": "float64", "value": "AAAAAAAAHEAAAAAAAAAgQAAAAAAAACJA" } }, @@ -73,6 +74,12 @@ TEST_CASE("Json value decoder test") { CHECK(rexsapi::detail::json::getType(getNode(doc, "boolean")) == rexsapi::TValueType::BOOLEAN); CHECK(rexsapi::detail::json::getType(getNode(doc, "integer")) == rexsapi::TValueType::INTEGER); + CHECK(rexsapi::detail::json::getType(getNode(doc, "string")) == rexsapi::TValueType::STRING); + CHECK(rexsapi::detail::json::getType(getNode(doc, "enum")) == rexsapi::TValueType::ENUM); + CHECK(rexsapi::detail::json::getType(getNode(doc, "reference component")) == + rexsapi::TValueType::REFERENCE_COMPONENT); + CHECK(rexsapi::detail::json::getType(getNode(doc, "file reference")) == rexsapi::TValueType::FILE_REFERENCE); + CHECK(rexsapi::detail::json::getType(getNode(doc, "date time")) == rexsapi::TValueType::DATE_TIME); CHECK(rexsapi::detail::json::getType(getNode(doc, "float array")) == rexsapi::TValueType::FLOATING_POINT_ARRAY); CHECK(rexsapi::detail::json::getType(getNode(doc, "coded float array")) == rexsapi::TValueType::FLOATING_POINT_ARRAY); @@ -141,6 +148,13 @@ TEST_CASE("Json value decoder test") CHECK(value.getValue() == "injection_lubrication"); } + SUBCASE("Decode date time") + { + const auto [value, result] = decoder.decode(rexsapi::TValueType::DATE_TIME, enumValue, getNode(doc, "date time")); + CHECK(result == rexsapi::detail::TDecoderResult::SUCCESS); + CHECK(value.getValue().asUTCString() == "2022-06-05T00:50:27+00:00"); + } + SUBCASE("Decode integer array") { const auto [value, result] = @@ -281,6 +295,7 @@ TEST_CASE("Json value decoder error test") "enum": { "enum": "unknown enum" }, "reference component": { "reference_component": "PR" }, "file reference": { "file_reference": 4711 }, + "date time": { "date_time": "2023-02-31T11:11:11+00:00" }, "float array": { "floating_point_array": ["a", "b", "c"] }, "integer array": { "integer_array": ["a", "b", "c"] }, "boolean array": { "boolean_array": ["true", "false", "false"] }, @@ -349,6 +364,12 @@ TEST_CASE("Json value decoder error test") rexsapi::detail::TDecoderResult::SUCCESS); } + SUBCASE("Decode date time") + { + CHECK(decoder.decode(rexsapi::TValueType::DATE_TIME, enumValue, getNode(doc, "date time")).second == + rexsapi::detail::TDecoderResult::FAILURE); + } + SUBCASE("Decode integer array") { CHECK(decoder.decode(rexsapi::TValueType::INTEGER_ARRAY, enumValue, getNode(doc, "integer array")).second == diff --git a/test/ModelBuilderTest.cxx b/test/ModelBuilderTest.cxx index 4a55b19..a67cd8d 100644 --- a/test/ModelBuilderTest.cxx +++ b/test/ModelBuilderTest.cxx @@ -65,7 +65,7 @@ TEST_CASE("Component builder test") const auto registry = createModelRegistry(); rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; rexsapi::TXSDSchemaValidator validator{schemaLoader}; - rexsapi::TComponentBuilder builder{registry.getModel({1, 4}, "de")}; + rexsapi::TComponentBuilder builder{registry.getModel({1, 5}, "de")}; SUBCASE("Component builder") { @@ -78,8 +78,12 @@ TEST_CASE("Component builder test") .value(rexsapi::TFloatArrayType{0.0, 65.0, 0.0}) .coded(rexsapi::TCodeType::Optimized); builder.addCustomAttribute("custom_hutzli", rexsapi::TValueType::BOOLEAN).value(true); - auto casingId = - builder.addComponent("gear_casing", "my-id").addAttribute("temperature_lubricant").value(128.0).id(); + auto casingId = builder.addComponent("gear_casing", "my-id") + .addAttribute("temperature_lubricant") + .value(128.0) + .addAttribute("modification_date") + .value(rexsapi::TDatetime{"2022-06-05T08:50:27+03:00"}) + .id(); CHECK(casingId == rexsapi::TComponentId{"my-id"}); auto components = builder.build(); REQUIRE(components.size() == 2); diff --git a/test/ModelVisitorTest.cxx b/test/ModelVisitorTest.cxx index 1231452..2601fb8 100644 --- a/test/ModelVisitorTest.cxx +++ b/test/ModelVisitorTest.cxx @@ -90,7 +90,7 @@ namespace TEST_CASE("Model visitor") { - const auto model = createModel(loadModel("1.4")); + const auto model = createModel(loadModel("1.5")); SUBCASE("Visit model") { @@ -101,7 +101,7 @@ TEST_CASE("Model visitor") CHECK(visitor.noRelations == 3); CHECK(visitor.noReferences == 7); CHECK(visitor.noComponents == 7); - CHECK(visitor.noAttributes == 19); + CHECK(visitor.noAttributes == 20); CHECK(visitor.noSpectrum == 1); CHECK(visitor.noCases == 1); CHECK(visitor.noAccumulation == 1); diff --git a/test/TestModel.hxx b/test/TestModel.hxx index e76a738..747b225 100644 --- a/test/TestModel.hxx +++ b/test/TestModel.hxx @@ -17,8 +17,8 @@ #ifndef TEST_TEST_MODEL_HXX #define TEST_TEST_MODEL_HXX -#include #include +#include static inline rexsapi::TModel createModel(const rexsapi::database::TModel& dbModel) @@ -33,6 +33,9 @@ static inline rexsapi::TModel createModel(const rexsapi::database::TModel& dbMod // INTEGER attributes.emplace_back( rexsapi::TAttribute{gearUnitComponent.findAttributeById("gear_shift_index"), rexsapi::TValue{5}}); + // DATE_TIME + attributes.emplace_back(rexsapi::TAttribute{gearUnitComponent.findAttributeById("modification_date"), + rexsapi::TValue{rexsapi::TDatetime{"2022-06-05T08:50:27+03:00"}}}); components.emplace_back(rexsapi::TComponent{componentId++, gearUnitComponent, "Getriebe", std::move(attributes)}); @@ -174,7 +177,7 @@ static inline rexsapi::TModel createModel(const rexsapi::database::TModel& dbMod rexsapi::TLoadSpectrum loadSpectrum{std::move(loadCases), std::move(accumulation)}; - rexsapi::TModelInfo info{"REXSApi Unit Test", "1.0", "2022-05-20T08:59:10+01:00", rexsapi::TRexsVersion{"1.4"}, "en"}; + rexsapi::TModelInfo info{"REXSApi Unit Test", "1.0", "2022-05-20T08:59:10+01:00", dbModel.getVersion(), "en"}; return rexsapi::TModel{info, std::move(components), std::move(relations), std::move(loadSpectrum)}; } diff --git a/test/TypesTest.cxx b/test/TypesTest.cxx index cd1910e..a7385b2 100644 --- a/test/TypesTest.cxx +++ b/test/TypesTest.cxx @@ -16,6 +16,8 @@ #include +#include + #include @@ -115,8 +117,8 @@ TEST_CASE("Relation role test") TEST_CASE("Bool test") { - rexsapi::Bool bTrue{true}; - rexsapi::Bool bFalse{false}; + const rexsapi::Bool bTrue{true}; + const rexsapi::Bool bFalse{false}; SUBCASE("Create") { @@ -146,3 +148,41 @@ TEST_CASE("Bool test") CHECK_FALSE(*bFalse); } } + +TEST_CASE("Datetime test") +{ + const std::regex reg_expr(R"(^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-](\d{2}):(\d{2})$)"); + std::smatch match; + + SUBCASE("Parse") + { + const rexsapi::TDatetime dt{"2023-03-28T13:49:36+02:00"}; + using namespace date; + CHECK(dt.asTimepoint() == date::sys_days{2023_y / mar / 28} + std::chrono::hours{11} + std::chrono::minutes{49} + + std::chrono::seconds{36}); + CHECK(dt.asUTCString() == "2023-03-28T11:49:36+00:00"); + const auto s = dt.asLocaleString(); + CHECK(std::regex_match(s, match, reg_expr)); + } + + SUBCASE("Equality") + { + const rexsapi::TDatetime dt{"2023-03-28T13:49:36+02:00"}; + CHECK(dt == dt); + const rexsapi::TDatetime dt1{"2022-03-28T13:49:36+02:00"}; + CHECK_FALSE(dt == dt1); + CHECK_FALSE(dt1 == dt); + } + + SUBCASE("Now") + { + const rexsapi::TDatetime dt = rexsapi::TDatetime::now(); + const auto s = dt.asLocaleString(); + CHECK(std::regex_match(s, match, reg_expr)); + } + + SUBCASE("Illegal date") + { + CHECK_THROWS(rexsapi::TDatetime{"2023-02-31T13:49:36+02:00"}); + } +} diff --git a/test/ValueTest.cxx b/test/ValueTest.cxx index 1f36c94..a3db345 100644 --- a/test/ValueTest.cxx +++ b/test/ValueTest.cxx @@ -80,6 +80,13 @@ TEST_CASE("Value test") CHECK(val.asString() == "My std String!"); } + SUBCASE("date time value") + { + rexsapi::TValue val{rexsapi::TDatetime{"2019-09-23T08:08:00+09:00"}}; + CHECK_FALSE(val.isEmpty()); + CHECK(val.getValue().asUTCString() == "2019-09-22T23:08:00+00:00"); + } + SUBCASE("vector of integer") { std::vector aofi{42, 815, 4711}; @@ -208,6 +215,9 @@ TEST_CASE("Value test") val = std::string("My String!"); CHECK(val.matchesValueType(rexsapi::TValueType::STRING)); + val = rexsapi::TDatetime{"2023-03-29T14:25:39+02:00"}; + CHECK(val.matchesValueType(rexsapi::TValueType::DATE_TIME)); + val = std::vector{42, 815, 4711}; CHECK(val.matchesValueType(rexsapi::TValueType::INTEGER_ARRAY)); diff --git a/test/ValueTypeTest.cxx b/test/ValueTypeTest.cxx index a6a52b9..0270952 100644 --- a/test/ValueTypeTest.cxx +++ b/test/ValueTypeTest.cxx @@ -56,6 +56,11 @@ namespace stream << "file reference " << s; return stream.str(); }, + [](rexsapi::TDatetimeTag, const auto& d) -> std::string { + std::stringstream stream; + stream << "date time " << d.asUTCString(); + return stream.str(); + }, [](rexsapi::TFloatArrayTag, const auto& a) -> std::string { return "float array " + std::to_string(a.size()) + " entries"; }, @@ -109,6 +114,7 @@ namespace rexsapi CHECK(rexsapi::typeFromString("enum") == rexsapi::TValueType::ENUM); CHECK(rexsapi::typeFromString("string") == rexsapi::TValueType::STRING); CHECK(rexsapi::typeFromString("file_reference") == rexsapi::TValueType::FILE_REFERENCE); + CHECK(rexsapi::typeFromString("date_time") == rexsapi::TValueType::DATE_TIME); CHECK(rexsapi::typeFromString("boolean_array") == rexsapi::TValueType::BOOLEAN_ARRAY); CHECK(rexsapi::typeFromString("floating_point_array") == rexsapi::TValueType::FLOATING_POINT_ARRAY); CHECK(rexsapi::typeFromString("integer_array") == rexsapi::TValueType::INTEGER_ARRAY); @@ -132,6 +138,7 @@ namespace rexsapi CHECK(rexsapi::toTypeString(rexsapi::TValueType::ENUM) == "enum"); CHECK(rexsapi::toTypeString(rexsapi::TValueType::STRING) == "string"); CHECK(rexsapi::toTypeString(rexsapi::TValueType::FILE_REFERENCE) == "file_reference"); + CHECK(rexsapi::toTypeString(rexsapi::TValueType::DATE_TIME) == "date_time"); CHECK(rexsapi::toTypeString(rexsapi::TValueType::BOOLEAN_ARRAY) == "boolean_array"); CHECK(rexsapi::toTypeString(rexsapi::TValueType::FLOATING_POINT_ARRAY) == "floating_point_array"); CHECK(rexsapi::toTypeString(rexsapi::TValueType::INTEGER_ARRAY) == "integer_array"); @@ -156,6 +163,8 @@ namespace rexsapi "enum heat_treatable_steel_quenched_tempered_condition"); CHECK(::dispatch(rexsapi::TValueType::FILE_REFERENCE, rexsapi::TValue{"./gear.gde"}) == "file reference ./gear.gde"); + CHECK(::dispatch(rexsapi::TValueType::DATE_TIME, rexsapi::TValue{rexsapi::TDatetime{ + "2023-03-29T11:46:00+02:00"}}) == "date time 2023-03-29T09:46:00+00:00"); CHECK(::dispatch(rexsapi::TValueType::REFERENCE_COMPONENT, rexsapi::TValue{15}) == "reference component 15"); CHECK(::dispatch(rexsapi::TValueType::FLOATING_POINT_ARRAY, rexsapi::TValue{rexsapi::TFloatArrayType{1.1, 2.1, 3.1, 4.1}}) == "float array 4 entries"); @@ -192,6 +201,7 @@ namespace rexsapi CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::ENUM, rexsapi::TValue{})); CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::STRING, rexsapi::TValue{})); CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::FILE_REFERENCE, rexsapi::TValue{})); + CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::DATE_TIME, rexsapi::TValue{})); CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::FLOATING_POINT_ARRAY, rexsapi::TValue{})); CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::BOOLEAN_ARRAY, rexsapi::TValue{})); CHECK_THROWS(::dispatch_empty(rexsapi::TValueType::INTEGER_ARRAY, rexsapi::TValue{})); diff --git a/test/XMLModelLoaderTest.cxx b/test/XMLModelLoaderTest.cxx index fd2a53b..06d8ef1 100644 --- a/test/XMLModelLoaderTest.cxx +++ b/test/XMLModelLoaderTest.cxx @@ -29,8 +29,8 @@ namespace const rexsapi::database::TModelRegistry& registry, rexsapi::TMode mode = rexsapi::TMode::STRICT_MODE) { - rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; - rexsapi::TXSDSchemaValidator validator{schemaLoader}; + const rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; + const rexsapi::TXSDSchemaValidator validator{schemaLoader}; rexsapi::detail::TFileModelLoader loader{validator, path}; return loader.load(mode, result, registry); @@ -38,7 +38,7 @@ namespace const std::string MemModel = R"( - + @@ -63,6 +63,7 @@ namespace 100000.0 100000.0 1 + 2023-03-29T11:46:00+02:00 0.0 @@ -127,15 +128,15 @@ namespace TEST_CASE("XML model loader test") { const auto registry = createModelRegistry(); - rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; - rexsapi::TXSDSchemaValidator validator{schemaLoader}; + const rexsapi::TFileXsdSchemaLoader schemaLoader{projectDir() / "models" / "rexs-schema.xsd"}; + const rexsapi::TXSDSchemaValidator validator{schemaLoader}; rexsapi::TResult result; SUBCASE("Load model from buffer") { rexsapi::detail::TBufferModelLoader loader{validator, MemModel}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); REQUIRE(result.getErrors().size() == 1); CHECK(result.getErrors()[0].getMessage() == @@ -146,7 +147,7 @@ TEST_CASE("XML model loader test") CHECK(*model->getInfo().getApplicationLanguage() == "de"); CHECK(model->getInfo().getApplicationVersion() == "1.0"); CHECK(model->getInfo().getDate() == "2022-05-05T10:35:00+02:00"); - CHECK(model->getInfo().getVersion() == rexsapi::TRexsVersion{1, 4}); + CHECK(model->getInfo().getVersion() == rexsapi::TRexsVersion{1, 5}); REQUIRE(model->getComponents().size() == 3); const auto& attribute = model->getComponents()[0].getAttributes()[0]; CHECK(attribute.getAttributeId() == "account_for_gravity"); @@ -157,6 +158,16 @@ TEST_CASE("XML model loader test") REQUIRE(model->getRelations()[0].getReferences().size() == 2); CHECK(model->getRelations()[0].getReferences()[0].getComponent().getType() == "gear_unit"); CHECK(model->getRelations()[0].getReferences()[0].getComponent().getName() == "Getriebeeinheit"); + REQUIRE(model->getRelations()[0].getReferences()[0].getComponent().getAttributes().size() == 16); + CHECK(model->getRelations()[0].getReferences()[0].getComponent().getAttributes()[12].getName() == + "Änderungszeitpunkt"); + CHECK(model->getRelations()[0] + .getReferences()[0] + .getComponent() + .getAttributes()[12] + .getValue() + .getValue() + .asUTCString() == "2023-03-29T09:46:00+00:00"); CHECK(model->getLoadSpectrum().hasLoadCases()); REQUIRE(model->getLoadSpectrum().getLoadCases().size() == 2); REQUIRE(model->getLoadSpectrum().getLoadCases()[0].getLoadComponents().size() == 2); @@ -167,7 +178,8 @@ TEST_CASE("XML model loader test") SUBCASE("Load simple model from file") { - auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA_worm_stage_1-4.rexs", registry); + const auto model = + loadModel(result, projectDir() / "test" / "example_models" / "FVA_worm_stage_1-4.rexs", registry); CHECK(model); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); @@ -188,7 +200,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load complex model from file in strict mode") { - auto model = + const auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexs", registry); REQUIRE(model); CHECK_FALSE(result); @@ -223,8 +235,9 @@ TEST_CASE("XML model loader test") SUBCASE("Load complex model from file in relaxed mode") { - auto model = loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexs", - registry, rexsapi::TMode::RELAXED_MODE); + const auto model = + loadModel(result, projectDir() / "test" / "example_models" / "FVA-Industriegetriebe_2stufig_1-4.rexs", registry, + rexsapi::TMode::RELAXED_MODE); REQUIRE(model); CHECK(result); CHECK_FALSE(result.isCritical()); @@ -258,7 +271,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load model from non-existent file failure") { - auto model = loadModel(result, "non-exising-file.rexs", registry); + const auto model = loadModel(result, "non-exising-file.rexs", registry); CHECK_FALSE(model); CHECK_FALSE(result); CHECK(result.isCritical()); @@ -268,7 +281,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load model from directory failure") { - auto model = loadModel(result, projectDir(), registry); + const auto model = loadModel(result, projectDir(), registry); CHECK_FALSE(model); CHECK_FALSE(result); CHECK(result.isCritical()); @@ -277,7 +290,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load invalid xml document") { - std::string buffer = R"( + const std::string buffer = R"( @@ -296,7 +309,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK_FALSE(result); CHECK(result.isCritical()); CHECK_FALSE(model); @@ -304,7 +317,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load invalid component") { - std::string buffer = R"( + const std::string buffer = R"( @@ -322,7 +335,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); CHECK(model); @@ -330,7 +343,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load invalid relation order") { - std::string buffer = R"( + const std::string buffer = R"( @@ -346,7 +359,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); CHECK(model); @@ -354,7 +367,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load invalid relation type") { - std::string buffer = R"( + const std::string buffer = R"( @@ -370,7 +383,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); CHECK(model); @@ -378,7 +391,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load invalid reference type") { - std::string buffer = R"( + const std::string buffer = R"( @@ -394,7 +407,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); CHECK(model); @@ -402,7 +415,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load non-existing reference component") { - std::string buffer = R"( + const std::string buffer = R"( @@ -421,7 +434,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK_FALSE(result); CHECK_FALSE(result.isCritical()); CHECK(model); @@ -429,7 +442,7 @@ TEST_CASE("XML model loader test") SUBCASE("Load non used component") { - std::string buffer = R"( + const std::string buffer = R"( @@ -453,7 +466,7 @@ TEST_CASE("XML model loader test") rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::STRICT_MODE, result, registry); CHECK(result); CHECK_FALSE(result.isCritical()); CHECK(result.hasIssues()); @@ -463,11 +476,11 @@ TEST_CASE("XML model loader test") SUBCASE("Load valid document with unkown version") { std::string buffer{MemModel}; - replace(buffer, R"(version="1.4")", R"(version="1.99")"); + replace(buffer, R"(version="1.5")", R"(version="1.99")"); { rexsapi::detail::TBufferModelLoader loader{validator, buffer}; - auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); + const auto model = loader.load(rexsapi::TMode::RELAXED_MODE, result, registry); CHECK(result); REQUIRE(model); } diff --git a/test/XMLModelSerializerTest.cxx b/test/XMLModelSerializerTest.cxx index 9076c1c..862e5cd 100644 --- a/test/XMLModelSerializerTest.cxx +++ b/test/XMLModelSerializerTest.cxx @@ -94,7 +94,7 @@ TEST_CASE("XML model file serializer test") TEST_CASE("XML serialize new model") { - const auto& dbModel = loadModel("1.4"); + const auto& dbModel = loadModel("1.5"); rexsapi::TXMLStringSerializer stringSerializer; rexsapi::XMLModelSerializer modelSerializer; @@ -107,7 +107,7 @@ TEST_CASE("XML serialize new model") CHECK(roundtripModel.getInfo().getApplicationId() == "REXSApi Unit Test"); CHECK(roundtripModel.getInfo().getApplicationVersion() == "1.0"); CHECK(roundtripModel.getInfo().getDate() == "2022-05-20T08:59:10+01:00"); - CHECK(roundtripModel.getInfo().getVersion() == rexsapi::TRexsVersion{1, 4}); + CHECK(roundtripModel.getInfo().getVersion() == rexsapi::TRexsVersion{1, 5}); REQUIRE(roundtripModel.getInfo().getApplicationLanguage().has_value()); CHECK(*roundtripModel.getInfo().getApplicationLanguage() == "en"); CHECK(roundtripModel.getComponents().size() == 7); diff --git a/test/XMLValueDecoderTest.cxx b/test/XMLValueDecoderTest.cxx index d55cb72..8cc06b1 100644 --- a/test/XMLValueDecoderTest.cxx +++ b/test/XMLValueDecoderTest.cxx @@ -45,6 +45,7 @@ TEST_CASE("XML value decoder test") injection_lubrication 17 /root/my/path + 2022-06-05T08:50:27+03:00 MveeQZ6hM0I= @@ -190,6 +191,13 @@ TEST_CASE("XML value decoder test") CHECK(value.getValue() == "injection_lubrication"); } + SUBCASE("Decode date time") + { + const auto [value, result] = decoder.decode(rexsapi::TValueType::DATE_TIME, enumValue, getNode(doc, "date time")); + CHECK(result == rexsapi::detail::TDecoderResult::SUCCESS); + CHECK(value.getValue().asUTCString() == "2022-06-05T05:50:27+00:00"); + } + SUBCASE("Decode integer array") { const auto [value, result] = @@ -297,6 +305,7 @@ TEST_CASE("XML value decoder error test") unknown enum PR + 2022-02-30T08:50:27+02:00 1.1 @@ -381,6 +390,12 @@ TEST_CASE("XML value decoder error test") rexsapi::detail::TDecoderResult::SUCCESS); } + SUBCASE("Decode date time") + { + CHECK(decoder.decode(rexsapi::TValueType::DATE_TIME, enumValue, getNode(doc, "date time")).second == + rexsapi::detail::TDecoderResult::FAILURE); + } + SUBCASE("Decode integer array") { CHECK(decoder.decode(rexsapi::TValueType::INTEGER_ARRAY, enumValue, getNode(doc, "integer array")).second == From 0f3e4510e3d085576f8b5a624e52bd3db16b2939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars-Christian=20F=C3=BCrstenberg?= Date: Mon, 17 Apr 2023 09:53:13 +0200 Subject: [PATCH 9/9] Added missing install for the new date library --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 12c7c6b..fab3544 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,6 +93,10 @@ if(REXSAPI_MASTER_PROJECT) DIRECTORY "${miniz_BINARY_DIR}/miniz" DESTINATION ./deps/include ) + install( + DIRECTORY "${date_SOURCE_DIR}/include" + DESTINATION ./deps + ) install( DIRECTORY "${PROJECT_SOURCE_DIR}/examples" DESTINATION .