From 43eed00cd981a4144d7e4d48ef7bfd890ea1c2f6 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sat, 29 Jul 2023 05:07:20 +0200 Subject: [PATCH] Add `deserializeXxx(JsonVariant, ...)` (resolves #1226) --- CHANGELOG.md | 1 + extras/tests/JsonDeserializer/CMakeLists.txt | 1 + .../JsonDeserializer/destination_types.cpp | 104 ++++++++++++++++++ .../tests/MsgPackDeserializer/CMakeLists.txt | 1 + .../MsgPackDeserializer/destination_types.cpp | 104 ++++++++++++++++++ .../Deserialization/deserialize.hpp | 47 ++++---- src/ArduinoJson/Json/JsonDeserializer.hpp | 15 +-- .../MsgPack/MsgPackDeserializer.hpp | 14 ++- 8 files changed, 249 insertions(+), 38 deletions(-) create mode 100644 extras/tests/JsonDeserializer/destination_types.cpp create mode 100644 extras/tests/MsgPackDeserializer/destination_types.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 692292be..2393d0b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,3 +24,4 @@ HEAD * Show a link to the documentation when user passes an unsupported input type * Remove `JsonDocument::memoryUsage()` * Remove `JsonDocument::garbageCollect()` +* Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226) diff --git a/extras/tests/JsonDeserializer/CMakeLists.txt b/extras/tests/JsonDeserializer/CMakeLists.txt index 15c84721..5940451f 100644 --- a/extras/tests/JsonDeserializer/CMakeLists.txt +++ b/extras/tests/JsonDeserializer/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(JsonDeserializerTests array.cpp DeserializationError.cpp + destination_types.cpp errors.cpp filter.cpp input_types.cpp diff --git a/extras/tests/JsonDeserializer/destination_types.cpp b/extras/tests/JsonDeserializer/destination_types.cpp new file mode 100644 index 00000000..20841171 --- /dev/null +++ b/extras/tests/JsonDeserializer/destination_types.cpp @@ -0,0 +1,104 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#include + +#include +#include + +#include "Allocators.hpp" + +TEST_CASE("deserializeJson(JsonDocument&)") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc.add(std::string("hello")); + spy.clearLog(); + + auto err = deserializeJson(doc, "[42]"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[42]"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofPool()), + Deallocate(sizeofString("hello")), + Allocate(sizeofPool()), + }); +} + +TEST_CASE("deserializeJson(JsonVariant)") { + SECTION("variant is bound") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc.add(std::string("hello")); + spy.clearLog(); + + JsonVariant variant = doc[0]; + + auto err = deserializeJson(variant, "[42]"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[[42]]"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofString("hello")), + }); + } + + SECTION("variant is unbound") { + JsonVariant variant; + + auto err = deserializeJson(variant, "[42]"); + + REQUIRE(err == DeserializationError::NoMemory); + } +} + +TEST_CASE("deserializeJson(ElementProxy)") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc.add(std::string("hello")); + spy.clearLog(); + + SECTION("element already exists") { + auto err = deserializeJson(doc[0], "[42]"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[[42]]"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofString("hello")), + }); + } + + SECTION("element must be created exists") { + auto err = deserializeJson(doc[1], "[42]"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[\"hello\",[42]]"); + REQUIRE(spy.log() == AllocatorLog{}); + } +} + +TEST_CASE("deserializeJson(MemberProxy)") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc[std::string("hello")] = std::string("world"); + spy.clearLog(); + + SECTION("member already exists") { + auto err = deserializeJson(doc["hello"], "[42]"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "{\"hello\":[42]}"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofString("world")), + }); + } + + SECTION("member must be created exists") { + auto err = deserializeJson(doc["value"], "[42]"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "{\"hello\":\"world\",\"value\":[42]}"); + REQUIRE(spy.log() == AllocatorLog{}); + } +} diff --git a/extras/tests/MsgPackDeserializer/CMakeLists.txt b/extras/tests/MsgPackDeserializer/CMakeLists.txt index f82a9643..6a303027 100644 --- a/extras/tests/MsgPackDeserializer/CMakeLists.txt +++ b/extras/tests/MsgPackDeserializer/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(MsgPackDeserializerTests deserializeArray.cpp deserializeObject.cpp deserializeVariant.cpp + destination_types.cpp doubleToFloat.cpp errors.cpp filter.cpp diff --git a/extras/tests/MsgPackDeserializer/destination_types.cpp b/extras/tests/MsgPackDeserializer/destination_types.cpp new file mode 100644 index 00000000..b0a7aa39 --- /dev/null +++ b/extras/tests/MsgPackDeserializer/destination_types.cpp @@ -0,0 +1,104 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#include + +#include +#include + +#include "Allocators.hpp" + +TEST_CASE("deserializeMsgPack(JsonDocument&)") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc.add(std::string("hello")); + spy.clearLog(); + + auto err = deserializeMsgPack(doc, "\x91\x2A"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[42]"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofPool()), + Deallocate(sizeofString("hello")), + Allocate(sizeofPool()), + }); +} + +TEST_CASE("deserializeMsgPack(JsonVariant)") { + SECTION("variant is bound") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc.add(std::string("hello")); + spy.clearLog(); + + JsonVariant variant = doc[0]; + + auto err = deserializeMsgPack(variant, "\x91\x2A"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[[42]]"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofString("hello")), + }); + } + + SECTION("variant is unbound") { + JsonVariant variant; + + auto err = deserializeMsgPack(variant, "\x91\x2A"); + + REQUIRE(err == DeserializationError::NoMemory); + } +} + +TEST_CASE("deserializeMsgPack(ElementProxy)") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc.add(std::string("hello")); + spy.clearLog(); + + SECTION("element already exists") { + auto err = deserializeMsgPack(doc[0], "\x91\x2A"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[[42]]"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofString("hello")), + }); + } + + SECTION("element must be created exists") { + auto err = deserializeMsgPack(doc[1], "\x91\x2A"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "[\"hello\",[42]]"); + REQUIRE(spy.log() == AllocatorLog{}); + } +} + +TEST_CASE("deserializeMsgPack(MemberProxy)") { + SpyingAllocator spy; + JsonDocument doc(&spy); + doc[std::string("hello")] = std::string("world"); + spy.clearLog(); + + SECTION("member already exists") { + auto err = deserializeMsgPack(doc["hello"], "\x91\x2A"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "{\"hello\":[42]}"); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofString("world")), + }); + } + + SECTION("member must be created exists") { + auto err = deserializeMsgPack(doc["value"], "\x91\x2A"); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(doc.as() == "{\"hello\":\"world\",\"value\":[42]}"); + REQUIRE(spy.log() == AllocatorLog{}); + } +} diff --git a/src/ArduinoJson/Deserialization/deserialize.hpp b/src/ArduinoJson/Deserialization/deserialize.hpp index 3f6b4f32..3140879a 100644 --- a/src/ArduinoJson/Deserialization/deserialize.hpp +++ b/src/ArduinoJson/Deserialization/deserialize.hpp @@ -22,40 +22,37 @@ struct first_or_void { using type = T; }; -template