diff --git a/lib/ArduinoJson/CHANGELOG.md b/lib/ArduinoJson/CHANGELOG.md index 2148c6d7..c0a8b4b8 100644 --- a/lib/ArduinoJson/CHANGELOG.md +++ b/lib/ArduinoJson/CHANGELOG.md @@ -1,6 +1,46 @@ ArduinoJson: change log ======================= +v7.3.0 (2024-12-29) +------ + +* Fix support for NUL characters in `deserializeJson()` +* Make `ElementProxy` and `MemberProxy` non-copyable +* Change string copy policy: only string literal are stored by pointer +* `JsonString` is now stored by copy, unless specified otherwise +* Replace undocumented `JsonString::Ownership` with `bool` +* Rename undocumented `JsonString::isLinked()` to `isStatic()` +* Move public facing SFINAEs to template declarations + +> ### BREAKING CHANGES +> +> In previous versions, `MemberProxy` (the class returned by `operator[]`) could lead to dangling pointers when used with a temporary string. +> To prevent this issue, `MemberProxy` and `ElementProxy` are now non-copyable. +> +> Your code is likely to be affected if you use `auto` to store the result of `operator[]`. For example, the following line won't compile anymore: +> +> ```cpp +> auto value = doc["key"]; +> ``` +> +> To fix the issue, you must append either `.as()` or `.to()`, depending on the situation. +> +> For example, if you are extracting values from a JSON document, you should update like this: +> +> ```diff +> - auto config = doc["config"]; +> + auto config = doc["config"].as(); +> const char* name = config["name"]; +> ``` +> +> However, if you are building a JSON document, you should update like this: +> +> ```diff +> - auto config = doc["config"]; +> + auto config = doc["config"].to(); +> config["name"] = "ArduinoJson"; +> ``` + v7.2.1 (2024-11-15) ------ diff --git a/lib/ArduinoJson/CMakeLists.txt b/lib/ArduinoJson/CMakeLists.txt index 24584f02..b607bdb8 100644 --- a/lib/ArduinoJson/CMakeLists.txt +++ b/lib/ArduinoJson/CMakeLists.txt @@ -10,7 +10,7 @@ if(ESP_PLATFORM) return() endif() -project(ArduinoJson VERSION 7.2.1) +project(ArduinoJson VERSION 7.3.0) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) include(CTest) diff --git a/lib/ArduinoJson/README b/lib/ArduinoJson/README deleted file mode 100644 index 2593a33f..00000000 --- a/lib/ArduinoJson/README +++ /dev/null @@ -1,46 +0,0 @@ - -This directory is intended for project specific (private) libraries. -PlatformIO will compile them to static libraries and link into executable file. - -The source code of each library should be placed in an own separate directory -("lib/your_library_name/[here are source files]"). - -For example, see a structure of the following two libraries `Foo` and `Bar`: - -|--lib -| | -| |--Bar -| | |--docs -| | |--examples -| | |--src -| | |- Bar.c -| | |- Bar.h -| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html -| | -| |--Foo -| | |- Foo.c -| | |- Foo.h -| | -| |- README --> THIS FILE -| -|- platformio.ini -|--src - |- main.c - -and a contents of `src/main.c`: -``` -#include -#include - -int main (void) -{ - ... -} - -``` - -PlatformIO Library Dependency Finder will find automatically dependent -libraries scanning project source files. - -More information about PlatformIO Library Dependency Finder -- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/lib/ArduinoJson/appveyor.yml b/lib/ArduinoJson/appveyor.yml index 3660d01a..cdcadc1f 100644 --- a/lib/ArduinoJson/appveyor.yml +++ b/lib/ArduinoJson/appveyor.yml @@ -1,4 +1,4 @@ -version: 7.2.1.{build} +version: 7.3.0.{build} environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 diff --git a/lib/ArduinoJson/extras/scripts/extract_changes.awk b/lib/ArduinoJson/extras/scripts/extract_changes.awk new file mode 100644 index 00000000..d96d459d --- /dev/null +++ b/lib/ArduinoJson/extras/scripts/extract_changes.awk @@ -0,0 +1,29 @@ +#!/usr/bin/awk -f + +# Start echoing after the first list item +/\* / { + STARTED=1 + EMPTY_LINE=0 +} + +# Remember if we have seen an empty line +/^[[:space:]]*$/ { + EMPTY_LINE=1 +} + +# Exit when seeing a new version number +/^v[[:digit:]]/ { + if (STARTED) exit +} + +# Print if the line is not empty +# and restore the empty line we have skipped +!/^[[:space:]]*$/ { + if (STARTED) { + if (EMPTY_LINE) { + print "" + EMPTY_LINE=0 + } + print + } +} diff --git a/lib/ArduinoJson/extras/scripts/get-release-body.sh b/lib/ArduinoJson/extras/scripts/get-release-body.sh deleted file mode 100755 index 7c842c23..00000000 --- a/lib/ArduinoJson/extras/scripts/get-release-body.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -eu - -TAG="$1" -CHANGELOG="$2" - -cat << END -## Changes - -$(awk '/\* /{ FOUND=1 } /^[[:space:]]*$/ { if(FOUND) exit } { if(FOUND) print }' "$CHANGELOG") - -[View version history](https://github.com/bblanchon/ArduinoJson/blob/$TAG/CHANGELOG.md) -END diff --git a/lib/ArduinoJson/extras/scripts/get-release-page.sh b/lib/ArduinoJson/extras/scripts/get-release-page.sh index 9eb53e1f..10fa0877 100755 --- a/lib/ArduinoJson/extras/scripts/get-release-page.sh +++ b/lib/ArduinoJson/extras/scripts/get-release-page.sh @@ -14,5 +14,5 @@ date: '$(date +'%Y-%m-%d')' $(extras/scripts/wandbox/publish.sh "$ARDUINOJSON_H") --- -$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' "$CHANGELOG") +$(extras/scripts/extract_changes.awk "$CHANGELOG") END diff --git a/lib/ArduinoJson/extras/scripts/wandbox/publish.sh b/lib/ArduinoJson/extras/scripts/wandbox/publish.sh index b3f7077f..611572f8 100755 --- a/lib/ArduinoJson/extras/scripts/wandbox/publish.sh +++ b/lib/ArduinoJson/extras/scripts/wandbox/publish.sh @@ -15,7 +15,7 @@ compile() { "code":$(read_string "$FILE_PATH"), "codes": [{"file":"ArduinoJson.h","code":$(read_string "$ARDUINOJSON_H")}], "options": "warning,c++11", - "compiler": "gcc-5.5.0", + "compiler": "gcc-head", "save": true } END diff --git a/lib/ArduinoJson/extras/tests/Deprecated/containsKey.cpp b/lib/ArduinoJson/extras/tests/Deprecated/containsKey.cpp index 1b508975..846e98fb 100644 --- a/lib/ArduinoJson/extras/tests/Deprecated/containsKey.cpp +++ b/lib/ArduinoJson/extras/tests/Deprecated/containsKey.cpp @@ -67,7 +67,7 @@ TEST_CASE("JsonDocument::containsKey()") { TEST_CASE("MemberProxy::containsKey()") { JsonDocument doc; - auto mp = doc["hello"]; + const auto& mp = doc["hello"]; SECTION("containsKey(const char*)") { mp["key"] = "value"; diff --git a/lib/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt b/lib/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt index bb9719a3..2ee1a34d 100644 --- a/lib/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt +++ b/lib/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt @@ -13,7 +13,6 @@ add_executable(JsonArrayTests nesting.cpp remove.cpp size.cpp - std_string.cpp subscript.cpp unbound.cpp ) diff --git a/lib/ArduinoJson/extras/tests/JsonArray/add.cpp b/lib/ArduinoJson/extras/tests/JsonArray/add.cpp index 1527670a..f1ca5f20 100644 --- a/lib/ArduinoJson/extras/tests/JsonArray/add.cpp +++ b/lib/ArduinoJson/extras/tests/JsonArray/add.cpp @@ -17,31 +17,112 @@ TEST_CASE("JsonArray::add(T)") { SECTION("int") { array.add(123); + REQUIRE(123 == array[0].as()); REQUIRE(array[0].is()); REQUIRE(array[0].is()); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); } SECTION("double") { array.add(123.45); + REQUIRE(123.45 == array[0].as()); REQUIRE(array[0].is()); REQUIRE_FALSE(array[0].is()); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); } SECTION("bool") { array.add(true); - REQUIRE(true == array[0].as()); + + REQUIRE(array[0].as() == true); REQUIRE(array[0].is()); REQUIRE_FALSE(array[0].is()); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); + } + + SECTION("string literal") { + array.add("hello"); + + REQUIRE(array[0].as() == "hello"); + REQUIRE(array[0].is()); + REQUIRE(array[0].is() == false); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); + } + + SECTION("std::string") { + array.add("hello"_s); + + REQUIRE(array[0].as() == "hello"); + REQUIRE(array[0].is() == true); + REQUIRE(array[0].is() == false); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); } SECTION("const char*") { const char* str = "hello"; array.add(str); - REQUIRE(str == array[0].as()); - REQUIRE(array[0].is()); - REQUIRE_FALSE(array[0].is()); + + REQUIRE(array[0].as() == "hello"); + REQUIRE(array[0].as() != str); + REQUIRE(array[0].is() == true); + REQUIRE(array[0].is() == false); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); + } + + SECTION("serialized(const char*)") { + array.add(serialized("{}")); + + REQUIRE(doc.as() == "[{}]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("{}")), + }); + } + + SECTION("serialized(char*)") { + array.add(serialized(const_cast("{}"))); + + REQUIRE(doc.as() == "[{}]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("{}")), + }); + } + + SECTION("serialized(std::string)") { + array.add(serialized("{}"_s)); + + REQUIRE(doc.as() == "[{}]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("{}")), + }); + } + + SECTION("serialized(std::string)") { + array.add(serialized("\0XX"_s)); + + REQUIRE(doc.as() == "[\0XX]"_s); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString(" XX")), + }); } #ifdef HAS_VARIABLE_LENGTH_ARRAY @@ -52,7 +133,12 @@ TEST_CASE("JsonArray::add(T)") { array.add(vla); - REQUIRE("world"_s == array[0]); + strcpy(vla, "hello"); + REQUIRE(array[0] == "world"_s); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); } #endif @@ -99,61 +185,6 @@ TEST_CASE("JsonArray::add(T)") { REQUIRE(str == array[0]); } - - SECTION("should not duplicate const char*") { - array.add("world"); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - }); - } - - SECTION("should duplicate char*") { - array.add(const_cast("world")); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("world")), - }); - } - - SECTION("should duplicate std::string") { - array.add("world"_s); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("world")), - }); - } - - SECTION("should duplicate serialized(const char*)") { - array.add(serialized("{}")); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("{}")), - }); - } - - SECTION("should duplicate serialized(char*)") { - array.add(serialized(const_cast("{}"))); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("{}")), - }); - } - - SECTION("should duplicate serialized(std::string)") { - array.add(serialized("{}"_s)); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("{}")), - }); - } - - SECTION("should duplicate serialized(std::string)") { - array.add(serialized("\0XX"_s)); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString(" XX")), - }); - } } TEST_CASE("JsonArray::add()") { diff --git a/lib/ArduinoJson/extras/tests/JsonArray/std_string.cpp b/lib/ArduinoJson/extras/tests/JsonArray/std_string.cpp deleted file mode 100644 index d6cae2e6..00000000 --- a/lib/ArduinoJson/extras/tests/JsonArray/std_string.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include - -#include "Literals.hpp" - -static void eraseString(std::string& str) { - char* p = const_cast(str.c_str()); - while (*p) - *p++ = '*'; -} - -TEST_CASE("std::string") { - JsonDocument doc; - JsonArray array = doc.to(); - - SECTION("add()") { - std::string value("hello"); - array.add(value); - eraseString(value); - REQUIRE("hello"_s == array[0]); - } - - SECTION("operator[]") { - std::string value("world"); - array.add("hello"); - array[0] = value; - eraseString(value); - REQUIRE("world"_s == array[0]); - } -} diff --git a/lib/ArduinoJson/extras/tests/JsonArray/subscript.cpp b/lib/ArduinoJson/extras/tests/JsonArray/subscript.cpp index b0332f85..40b17361 100644 --- a/lib/ArduinoJson/extras/tests/JsonArray/subscript.cpp +++ b/lib/ArduinoJson/extras/tests/JsonArray/subscript.cpp @@ -59,14 +59,55 @@ TEST_CASE("JsonArray::operator[]") { REQUIRE(false == array[0].is()); } + SECTION("string literal") { + array[0] = "hello"; + + REQUIRE(array[0].as() == "hello"); + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); + } + SECTION("const char*") { const char* str = "hello"; - array[0] = str; - REQUIRE(str == array[0].as()); + + REQUIRE(array[0].as() == "hello"); + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); + } + + SECTION("std::string") { + array[0] = "hello"_s; + + REQUIRE(array[0].as() == "hello"); REQUIRE(true == array[0].is()); REQUIRE(false == array[0].is()); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); + } + +#ifdef HAS_VARIABLE_LENGTH_ARRAY + SECTION("VLA") { + size_t i = 16; + char vla[i]; + strcpy(vla, "world"); + + array.add("hello"); + array[0] = vla; + + REQUIRE(array[0] == "world"_s); } +#endif SECTION("nested array") { JsonDocument doc2; @@ -114,58 +155,11 @@ TEST_CASE("JsonArray::operator[]") { REQUIRE(str == array[0]); } - SECTION("should not duplicate const char*") { - array[0] = "world"; - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - }); - } - - SECTION("should duplicate char*") { - array[0] = const_cast("world"); - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("world")), - }); - } - - SECTION("should duplicate std::string") { - array[0] = "world"_s; - REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofPool()), - Allocate(sizeofString("world")), - }); - } - SECTION("array[0].to()") { JsonObject obj = array[0].to(); REQUIRE(obj.isNull() == false); } -#ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("set(VLA)") { - size_t i = 16; - char vla[i]; - strcpy(vla, "world"); - - array.add("hello"); - array[0].set(vla); - - REQUIRE("world"_s == array[0]); - } - - SECTION("operator=(VLA)") { - size_t i = 16; - char vla[i]; - strcpy(vla, "world"); - - array.add("hello"); - array[0] = vla; - - REQUIRE("world"_s == array[0]); - } -#endif - SECTION("Use a JsonVariant as index") { array[0] = 1; array[1] = 2; diff --git a/lib/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp b/lib/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp index 4dc2fc6d..894df750 100644 --- a/lib/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp @@ -693,6 +693,15 @@ TEST_CASE("Filtering") { "null", 0, }, + { + "NUL character in key", + "{\"x\":0,\"x\\u0000a\":1,\"x\\u0000b\":2}", + "{\"x\\u0000a\":true}", + 10, + DeserializationError::Ok, + "{\"x\\u0000a\":1}", + sizeofObject(1) + sizeofString("x?a"), + }, }; for (auto& tc : testCases) { diff --git a/lib/ArduinoJson/extras/tests/JsonDeserializer/object.cpp b/lib/ArduinoJson/extras/tests/JsonDeserializer/object.cpp index ee62ae43..9f0aecb4 100644 --- a/lib/ArduinoJson/extras/tests/JsonDeserializer/object.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDeserializer/object.cpp @@ -6,6 +6,7 @@ #include #include "Allocators.hpp" +#include "Literals.hpp" using ArduinoJson::detail::sizeofObject; @@ -322,10 +323,11 @@ TEST_CASE("deserialize JSON object") { SECTION("NUL in keys") { DeserializationError err = - deserializeJson(doc, "{\"x\\u0000a\":1,\"x\\u0000b\":2}"); + deserializeJson(doc, "{\"x\":0,\"x\\u0000a\":1,\"x\\u0000b\":2}"); REQUIRE(err == DeserializationError::Ok); - REQUIRE(doc.as() == "{\"x\\u0000a\":1,\"x\\u0000b\":2}"); + REQUIRE(doc.as() == + "{\"x\":0,\"x\\u0000a\":1,\"x\\u0000b\":2}"); } } diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp index 7faf0e47..387dc884 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp @@ -5,37 +5,60 @@ #include #include +#include "Allocators.hpp" #include "Literals.hpp" using ElementProxy = ArduinoJson::detail::ElementProxy; TEST_CASE("ElementProxy::add()") { - JsonDocument doc; + SpyingAllocator spy; + JsonDocument doc(&spy); doc.add(); - ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; - SECTION("add(int)") { + SECTION("integer") { ep.add(42); REQUIRE(doc.as() == "[[42]]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); } - SECTION("add(const char*)") { + SECTION("string literal") { ep.add("world"); REQUIRE(doc.as() == "[[\"world\"]]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); + } + + SECTION("const char*") { + const char* s = "world"; + ep.add(s); + + REQUIRE(doc.as() == "[[\"world\"]]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); } - SECTION("add(char[])") { + SECTION("char[]") { char s[] = "world"; ep.add(s); strcpy(s, "!!!!!"); REQUIRE(doc.as() == "[[\"world\"]]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); } #ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("set(vla)") { + SECTION("VLA") { size_t i = 8; char vla[i]; strcpy(vla, "world"); @@ -43,6 +66,10 @@ TEST_CASE("ElementProxy::add()") { ep.add(vla); REQUIRE(doc.as() == "[[\"world\"]]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); } #endif } @@ -50,7 +77,7 @@ TEST_CASE("ElementProxy::add()") { TEST_CASE("ElementProxy::clear()") { JsonDocument doc; doc.add(); - ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; SECTION("size goes back to zero") { ep.add(42); @@ -110,7 +137,7 @@ TEST_CASE("ElementProxy::operator==()") { TEST_CASE("ElementProxy::remove()") { JsonDocument doc; doc.add(); - ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; SECTION("remove(int)") { ep.add(1); @@ -157,7 +184,7 @@ TEST_CASE("ElementProxy::remove()") { TEST_CASE("ElementProxy::set()") { JsonDocument doc; - ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; SECTION("set(int)") { ep.set(42); @@ -195,7 +222,7 @@ TEST_CASE("ElementProxy::set()") { TEST_CASE("ElementProxy::size()") { JsonDocument doc; doc.add(); - ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; SECTION("returns 0") { REQUIRE(ep.size() == 0); @@ -216,7 +243,7 @@ TEST_CASE("ElementProxy::size()") { TEST_CASE("ElementProxy::operator[]") { JsonDocument doc; - ElementProxy ep = doc[1]; + const ElementProxy& ep = doc[1]; SECTION("set member") { ep["world"] = 42; @@ -247,7 +274,7 @@ TEST_CASE("ElementProxy cast to JsonVariantConst") { JsonDocument doc; doc[0] = "world"; - const ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; JsonVariantConst var = ep; @@ -258,7 +285,7 @@ TEST_CASE("ElementProxy cast to JsonVariant") { JsonDocument doc; doc[0] = "world"; - ElementProxy ep = doc[0]; + const ElementProxy& ep = doc[0]; JsonVariant var = ep; diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp index d59b5813..4eb7468c 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp @@ -14,27 +14,54 @@ using ArduinoJson::detail::sizeofArray; using ArduinoJson::detail::sizeofObject; -using MemberProxy = - ArduinoJson::detail::MemberProxy; - TEST_CASE("MemberProxy::add()") { - JsonDocument doc; - MemberProxy mp = doc["hello"]; + SpyingAllocator spy; + JsonDocument doc(&spy); + const auto& mp = doc["hello"]; - SECTION("add(int)") { + SECTION("integer") { mp.add(42); REQUIRE(doc.as() == "{\"hello\":[42]}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); } - SECTION("add(const char*)") { + SECTION("string literal") { mp.add("world"); REQUIRE(doc.as() == "{\"hello\":[\"world\"]}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); + } + + SECTION("const char*") { + const char* temp = "world"; + mp.add(temp); + + REQUIRE(doc.as() == "{\"hello\":[\"world\"]}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); + } + + SECTION("char[]") { + char temp[] = "world"; + mp.add(temp); + + REQUIRE(doc.as() == "{\"hello\":[\"world\"]}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + + }); } #ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("add(vla)") { + SECTION("VLA") { size_t i = 16; char vla[i]; strcpy(vla, "world"); @@ -42,13 +69,17 @@ TEST_CASE("MemberProxy::add()") { mp.add(vla); REQUIRE(doc.as() == "{\"hello\":[\"world\"]}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("world")), + }); } #endif } TEST_CASE("MemberProxy::clear()") { JsonDocument doc; - MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; SECTION("size goes back to zero") { mp.add(42); @@ -139,7 +170,7 @@ TEST_CASE("MemberProxy::operator|()") { TEST_CASE("MemberProxy::remove()") { JsonDocument doc; - MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; SECTION("remove(int)") { mp.add(1); @@ -186,7 +217,7 @@ TEST_CASE("MemberProxy::remove()") { TEST_CASE("MemberProxy::set()") { JsonDocument doc; - MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; SECTION("set(int)") { mp.set(42); @@ -223,7 +254,7 @@ TEST_CASE("MemberProxy::set()") { TEST_CASE("MemberProxy::size()") { JsonDocument doc; - MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; SECTION("returns 0") { REQUIRE(mp.size() == 0); @@ -246,7 +277,7 @@ TEST_CASE("MemberProxy::size()") { TEST_CASE("MemberProxy::operator[]") { JsonDocument doc; - MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; SECTION("set member") { mp["world"] = 42; @@ -265,7 +296,7 @@ TEST_CASE("MemberProxy cast to JsonVariantConst") { JsonDocument doc; doc["hello"] = "world"; - const MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; JsonVariantConst var = mp; @@ -276,7 +307,7 @@ TEST_CASE("MemberProxy cast to JsonVariant") { JsonDocument doc; doc["hello"] = "world"; - MemberProxy mp = doc["hello"]; + const auto& mp = doc["hello"]; JsonVariant var = mp; diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/add.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/add.cpp index 31aa6c2f..8a1c48e3 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/add.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/add.cpp @@ -26,7 +26,7 @@ TEST_CASE("JsonDocument::add(T)") { }); } - SECTION("const char*") { + SECTION("string literal") { doc.add("hello"); REQUIRE(doc.as() == "[\"hello\"]"); @@ -35,6 +35,17 @@ TEST_CASE("JsonDocument::add(T)") { }); } + SECTION("const char*") { + const char* value = "hello"; + doc.add(value); + + REQUIRE(doc.as() == "[\"hello\"]"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); + } + SECTION("std::string") { doc.add("example"_s); doc.add("example"_s); diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp deleted file mode 100644 index a68236e3..00000000 --- a/lib/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include - -#include "Literals.hpp" - -TEST_CASE("JsonDocument::containsKey()") { - JsonDocument doc; - - SECTION("returns true on object") { - doc["hello"] = "world"; - - REQUIRE(doc.containsKey("hello") == true); - } - - SECTION("returns true when value is null") { - doc["hello"] = static_cast(0); - - REQUIRE(doc.containsKey("hello") == true); - } - - SECTION("returns true when key is a std::string") { - doc["hello"] = "world"; - - REQUIRE(doc.containsKey("hello"_s) == true); - } - - SECTION("returns false on object") { - doc["world"] = "hello"; - - REQUIRE(doc.containsKey("hello") == false); - } - - SECTION("returns false on array") { - doc.add("hello"); - - REQUIRE(doc.containsKey("hello") == false); - } - - SECTION("returns false on null") { - REQUIRE(doc.containsKey("hello") == false); - } - - SECTION("support JsonVariant") { - doc["hello"] = "world"; - doc["key"] = "hello"; - - REQUIRE(doc.containsKey(doc["key"]) == true); - REQUIRE(doc.containsKey(doc["foo"]) == false); - } -} diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/issue1120.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/issue1120.cpp index 07ad9324..aa3132f5 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/issue1120.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/issue1120.cpp @@ -12,49 +12,41 @@ TEST_CASE("Issue #1120") { SECTION("MemberProxy::isNull()") { SECTION("returns false") { - auto value = doc["contents"_s]; - CHECK(value.isNull() == false); + CHECK(doc["contents"_s].isNull() == false); } SECTION("returns true") { - auto value = doc["zontents"_s]; - CHECK(value.isNull() == true); + CHECK(doc["zontents"_s].isNull() == true); } } SECTION("ElementProxy >::isNull()") { SECTION("returns false") { // Issue #1120 - auto value = doc["contents"][1]; - CHECK(value.isNull() == false); + CHECK(doc["contents"][1].isNull() == false); } SECTION("returns true") { - auto value = doc["contents"][2]; - CHECK(value.isNull() == true); + CHECK(doc["contents"][2].isNull() == true); } } SECTION("MemberProxy, const char*>::isNull()") { SECTION("returns false") { - auto value = doc["contents"][1]["module"]; - CHECK(value.isNull() == false); + CHECK(doc["contents"][1]["module"].isNull() == false); } SECTION("returns true") { - auto value = doc["contents"][1]["zodule"]; - CHECK(value.isNull() == true); + CHECK(doc["contents"][1]["zodule"].isNull() == true); } } SECTION("MemberProxy, std::string>::isNull()") { SECTION("returns false") { - auto value = doc["contents"][1]["module"_s]; - CHECK(value.isNull() == false); + CHECK(doc["contents"][1]["module"_s].isNull() == false); } SECTION("returns true") { - auto value = doc["contents"][1]["zodule"_s]; - CHECK(value.isNull() == true); + CHECK(doc["contents"][1]["zodule"_s].isNull() == true); } } } diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/remove.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/remove.cpp index afabf4eb..1656a4d2 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/remove.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/remove.cpp @@ -20,11 +20,21 @@ TEST_CASE("JsonDocument::remove()") { REQUIRE(doc.as() == "[1,3]"); } + SECTION("string literal") { + doc["a"] = 1; + doc["a\0b"_s] = 2; + doc["b"] = 3; + + doc.remove("a\0b"); + + REQUIRE(doc.as() == "{\"a\":1,\"b\":3}"); + } + SECTION("remove(const char *)") { doc["a"] = 1; doc["b"] = 2; - doc.remove("a"); + doc.remove(static_cast("a")); REQUIRE(doc.as() == "{\"b\":2}"); } diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/set.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/set.cpp index ce9de42a..1205acf5 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/set.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/set.cpp @@ -11,6 +11,21 @@ TEST_CASE("JsonDocument::set()") { SpyingAllocator spy; JsonDocument doc(&spy); + SECTION("nullptr") { + doc.set(nullptr); + + REQUIRE(doc.isNull()); + REQUIRE(spy.log() == AllocatorLog{}); + } + + SECTION("integer&") { + int toto = 42; + doc.set(toto); + + REQUIRE(doc.as() == "42"); + REQUIRE(spy.log() == AllocatorLog{}); + } + SECTION("integer") { doc.set(42); @@ -18,13 +33,23 @@ TEST_CASE("JsonDocument::set()") { REQUIRE(spy.log() == AllocatorLog{}); } - SECTION("const char*") { + SECTION("string literal") { doc.set("example"); REQUIRE(doc.as() == "example"_s); REQUIRE(spy.log() == AllocatorLog{}); } + SECTION("const char*") { + const char* value = "example"; + doc.set(value); + + REQUIRE(doc.as() == "example"_s); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofString("example")), + }); + } + SECTION("std::string") { doc.set("example"_s); diff --git a/lib/ArduinoJson/extras/tests/JsonDocument/subscript.cpp b/lib/ArduinoJson/extras/tests/JsonDocument/subscript.cpp index 250ce1dd..2150d15c 100644 --- a/lib/ArduinoJson/extras/tests/JsonDocument/subscript.cpp +++ b/lib/ArduinoJson/extras/tests/JsonDocument/subscript.cpp @@ -5,6 +5,7 @@ #include #include +#include "Allocators.hpp" #include "Literals.hpp" TEST_CASE("JsonDocument::operator[]") { @@ -16,8 +17,16 @@ TEST_CASE("JsonDocument::operator[]") { doc["abc\0d"_s] = "ABCD"; SECTION("const char*") { + const char* key = "abc"; + REQUIRE(doc[key] == "ABC"); + REQUIRE(cdoc[key] == "ABC"); + } + + SECTION("string literal") { REQUIRE(doc["abc"] == "ABC"); REQUIRE(cdoc["abc"] == "ABC"); + REQUIRE(doc["abc\0d"] == "ABCD"); + REQUIRE(cdoc["abc\0d"] == "ABCD"); } SECTION("std::string") { @@ -94,3 +103,65 @@ TEST_CASE("JsonDocument automatically promotes to array") { REQUIRE(doc.as() == "[null,null,2]"); } + +TEST_CASE("JsonDocument::operator[] key storage") { + SpyingAllocator spy; + JsonDocument doc(&spy); + + SECTION("string literal") { + doc["hello"] = 0; + + REQUIRE(doc.as() == "{\"hello\":0}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + }); + } + + SECTION("const char*") { + const char* key = "hello"; + doc[key] = 0; + + REQUIRE(doc.as() == "{\"hello\":0}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); + } + + SECTION("char[]") { + char key[] = "hello"; + doc[key] = 0; + + REQUIRE(doc.as() == "{\"hello\":0}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); + } + + SECTION("std::string") { + doc["hello"_s] = 0; + + REQUIRE(doc.as() == "{\"hello\":0}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); + } +#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \ + !defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR) + SECTION("VLA") { + size_t i = 16; + char vla[i]; + strcpy(vla, "hello"); + + doc[vla] = 0; + + REQUIRE(doc.as() == "{\"hello\":0}"); + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofPool()), + Allocate(sizeofString("hello")), + }); + } +#endif +} diff --git a/lib/ArduinoJson/extras/tests/JsonObject/containsKey.cpp b/lib/ArduinoJson/extras/tests/JsonObject/containsKey.cpp deleted file mode 100644 index d7dd8d1e..00000000 --- a/lib/ArduinoJson/extras/tests/JsonObject/containsKey.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include - -TEST_CASE("JsonObject::containsKey()") { - JsonDocument doc; - JsonObject obj = doc.to(); - obj["hello"] = 42; - - SECTION("returns true only if key is present") { - REQUIRE(false == obj.containsKey("world")); - REQUIRE(true == obj.containsKey("hello")); - } - - SECTION("returns false after remove()") { - obj.remove("hello"); - - REQUIRE(false == obj.containsKey("hello")); - } - -#ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("key is a VLA") { - size_t i = 16; - char vla[i]; - strcpy(vla, "hello"); - - REQUIRE(true == obj.containsKey(vla)); - } -#endif - - SECTION("key is a JsonVariant") { - doc["key"] = "hello"; - REQUIRE(true == obj.containsKey(obj["key"])); - REQUIRE(false == obj.containsKey(obj["hello"])); - } -} diff --git a/lib/ArduinoJson/extras/tests/JsonObject/subscript.cpp b/lib/ArduinoJson/extras/tests/JsonObject/subscript.cpp index 23512a02..0acc01e5 100644 --- a/lib/ArduinoJson/extras/tests/JsonObject/subscript.cpp +++ b/lib/ArduinoJson/extras/tests/JsonObject/subscript.cpp @@ -158,7 +158,7 @@ TEST_CASE("JsonObject::operator[]") { } SECTION("should duplicate a non-static JsonString key") { - obj[JsonString("hello", JsonString::Copied)] = "world"; + obj[JsonString("hello", false)] = "world"; REQUIRE(spy.log() == AllocatorLog{ Allocate(sizeofPool()), Allocate(sizeofString("hello")), @@ -166,7 +166,7 @@ TEST_CASE("JsonObject::operator[]") { } SECTION("should not duplicate a static JsonString key") { - obj[JsonString("hello", JsonString::Linked)] = "world"; + obj[JsonString("hello", true)] = "world"; REQUIRE(spy.log() == AllocatorLog{ Allocate(sizeofPool()), }); diff --git a/lib/ArduinoJson/extras/tests/JsonObjectConst/containsKey.cpp b/lib/ArduinoJson/extras/tests/JsonObjectConst/containsKey.cpp deleted file mode 100644 index 3283c08d..00000000 --- a/lib/ArduinoJson/extras/tests/JsonObjectConst/containsKey.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include - -#include "Literals.hpp" - -TEST_CASE("JsonObjectConst::containsKey()") { - JsonDocument doc; - doc["hello"] = 42; - auto obj = doc.as(); - - SECTION("supports const char*") { - REQUIRE(false == obj.containsKey("world")); - REQUIRE(true == obj.containsKey("hello")); - } - - SECTION("supports std::string") { - REQUIRE(false == obj.containsKey("world"_s)); - REQUIRE(true == obj.containsKey("hello"_s)); - } - -#ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("supports VLA") { - size_t i = 16; - char vla[i]; - strcpy(vla, "hello"); - - REQUIRE(true == obj.containsKey(vla)); - } -#endif - - SECTION("supports JsonVariant") { - doc["key"] = "hello"; - REQUIRE(true == obj.containsKey(obj["key"])); - REQUIRE(false == obj.containsKey(obj["hello"])); - } -} diff --git a/lib/ArduinoJson/extras/tests/JsonVariant/as.cpp b/lib/ArduinoJson/extras/tests/JsonVariant/as.cpp index 2c6f54b1..bfdea044 100644 --- a/lib/ArduinoJson/extras/tests/JsonVariant/as.cpp +++ b/lib/ArduinoJson/extras/tests/JsonVariant/as.cpp @@ -184,7 +184,7 @@ TEST_CASE("JsonVariant::as()") { REQUIRE(variant.as() == 42L); REQUIRE(variant.as() == "42"); - REQUIRE(variant.as().isLinked() == true); + REQUIRE(variant.as().isStatic() == true); } SECTION("set(\"hello\")") { @@ -207,7 +207,7 @@ TEST_CASE("JsonVariant::as()") { REQUIRE(variant.as() == "4.2"_s); REQUIRE(variant.as() == "4.2"_s); REQUIRE(variant.as() == "4.2"); - REQUIRE(variant.as().isLinked() == false); + REQUIRE(variant.as().isStatic() == false); } SECTION("set(\"true\")") { diff --git a/lib/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp b/lib/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp deleted file mode 100644 index a406fe14..00000000 --- a/lib/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include -#include - -#include "Literals.hpp" - -TEST_CASE("JsonVariant::containsKey()") { - JsonDocument doc; - JsonVariant var = doc.to(); - - SECTION("containsKey(const char*)") { - var["hello"] = "world"; - - REQUIRE(var.containsKey("hello") == true); - REQUIRE(var.containsKey("world") == false); - } - - SECTION("containsKey(std::string)") { - var["hello"] = "world"; - - REQUIRE(var.containsKey("hello"_s) == true); - REQUIRE(var.containsKey("world"_s) == false); - } - - SECTION("containsKey(JsonVariant)") { - var["hello"] = "world"; - var["key"] = "hello"; - - REQUIRE(var.containsKey(doc["key"]) == true); - REQUIRE(var.containsKey(doc["foo"]) == false); - } -} diff --git a/lib/ArduinoJson/extras/tests/JsonVariant/set.cpp b/lib/ArduinoJson/extras/tests/JsonVariant/set.cpp index b10f9505..b71c0016 100644 --- a/lib/ArduinoJson/extras/tests/JsonVariant/set.cpp +++ b/lib/ArduinoJson/extras/tests/JsonVariant/set.cpp @@ -17,6 +17,15 @@ TEST_CASE("JsonVariant::set() when there is enough memory") { JsonDocument doc(&spy); JsonVariant variant = doc.to(); + SECTION("string literal") { + bool result = variant.set("hello\0world"); + + REQUIRE(result == true); + CHECK(variant == + "hello"_s); // linked string cannot contain '\0' at the moment + CHECK(spy.log() == AllocatorLog{}); + } + SECTION("const char*") { char str[16]; @@ -25,8 +34,10 @@ TEST_CASE("JsonVariant::set() when there is enough memory") { strcpy(str, "world"); REQUIRE(result == true); - REQUIRE(variant == "world"); // stores by pointer - REQUIRE(spy.log() == AllocatorLog{}); + REQUIRE(variant == "hello"); // stores by copy + REQUIRE(spy.log() == AllocatorLog{ + Allocate(sizeofString("hello")), + }); } SECTION("(const char*)0") { @@ -34,6 +45,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") { REQUIRE(result == true); REQUIRE(variant.isNull()); + REQUIRE(variant.as() == nullptr); REQUIRE(spy.log() == AllocatorLog{}); } @@ -105,16 +117,14 @@ TEST_CASE("JsonVariant::set() when there is enough memory") { #endif SECTION("std::string") { - std::string str; - - str = "hello"; + std::string str = "hello\0world"_s; bool result = variant.set(str); str.replace(0, 5, "world"); REQUIRE(result == true); - REQUIRE(variant == "hello"); // stores by copy + REQUIRE(variant == "hello\0world"_s); // stores by copy REQUIRE(spy.log() == AllocatorLog{ - Allocate(sizeofString("hello")), + Allocate(sizeofString("hello?world")), }); } @@ -122,7 +132,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") { char str[16]; strcpy(str, "hello"); - bool result = variant.set(JsonString(str, JsonString::Linked)); + bool result = variant.set(JsonString(str, true)); strcpy(str, "world"); REQUIRE(result == true); @@ -134,7 +144,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") { char str[16]; strcpy(str, "hello"); - bool result = variant.set(JsonString(str, JsonString::Copied)); + bool result = variant.set(JsonString(str)); strcpy(str, "world"); REQUIRE(result == true); diff --git a/lib/ArduinoJson/extras/tests/JsonVariant/types.cpp b/lib/ArduinoJson/extras/tests/JsonVariant/types.cpp index eb0ee628..b04c91f1 100644 --- a/lib/ArduinoJson/extras/tests/JsonVariant/types.cpp +++ b/lib/ArduinoJson/extras/tests/JsonVariant/types.cpp @@ -7,14 +7,8 @@ #include #include -template -void checkValue(T expected) { - JsonDocument doc; - JsonVariant variant = doc.to(); - - variant.set(expected); - REQUIRE(expected == variant.as()); -} +#include "Allocators.hpp" +#include "Literals.hpp" template void checkReference(T& expected) { @@ -39,27 +33,29 @@ void checkNumericType() { } TEST_CASE("JsonVariant set()/get()") { + SpyingAllocator spy; + JsonDocument doc(&spy); + JsonVariant variant = doc.to(); + #if ARDUINOJSON_USE_LONG_LONG SECTION("SizeOfJsonInteger") { REQUIRE(8 == sizeof(JsonInteger)); } #endif - SECTION("Null") { - checkValue(NULL); - } - SECTION("const char*") { - checkValue("hello"); - } - SECTION("std::string") { - checkValue("hello"); - } + // /!\ Most test were moved to `JsonVariant/set.cpp` + // TODO: move the remaining tests too SECTION("False") { - checkValue(false); + variant.set(false); + REQUIRE(variant.as() == false); + REQUIRE(spy.log() == AllocatorLog{}); } + SECTION("True") { - checkValue(true); + variant.set(true); + REQUIRE(variant.as() == true); + REQUIRE(spy.log() == AllocatorLog{}); } SECTION("Double") { @@ -129,10 +125,12 @@ TEST_CASE("JsonVariant set()/get()") { #endif SECTION("CanStoreObject") { - JsonDocument doc; - JsonObject object = doc.to(); + JsonDocument doc2; + JsonObject object = doc2.to(); - checkValue(object); + variant.set(object); + REQUIRE(variant.is()); + REQUIRE(variant.as() == object); } } diff --git a/lib/ArduinoJson/extras/tests/JsonVariantConst/containsKey.cpp b/lib/ArduinoJson/extras/tests/JsonVariantConst/containsKey.cpp deleted file mode 100644 index dfa1fc80..00000000 --- a/lib/ArduinoJson/extras/tests/JsonVariantConst/containsKey.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include -#include - -#include "Literals.hpp" - -TEST_CASE("JsonVariantConst::containsKey()") { - JsonDocument doc; - doc["hello"] = "world"; - JsonVariantConst var = doc.as(); - - SECTION("support const char*") { - REQUIRE(var.containsKey("hello") == true); - REQUIRE(var.containsKey("world") == false); - } - - SECTION("support std::string") { - REQUIRE(var.containsKey("hello"_s) == true); - REQUIRE(var.containsKey("world"_s) == false); - } - -#ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("supports VLA") { - size_t i = 16; - char vla[i]; - strcpy(vla, "hello"); - - REQUIRE(true == var.containsKey(vla)); - } -#endif - - SECTION("support JsonVariant") { - doc["key"] = "hello"; - REQUIRE(var.containsKey(var["key"]) == true); - REQUIRE(var.containsKey(var["foo"]) == false); - } -} diff --git a/lib/ArduinoJson/extras/tests/JsonVariantConst/subscript.cpp b/lib/ArduinoJson/extras/tests/JsonVariantConst/subscript.cpp index 735506ae..a207c531 100644 --- a/lib/ArduinoJson/extras/tests/JsonVariantConst/subscript.cpp +++ b/lib/ArduinoJson/extras/tests/JsonVariantConst/subscript.cpp @@ -54,13 +54,22 @@ TEST_CASE("JsonVariantConst::operator[]") { object["abc"_s] = "ABC"; object["abc\0d"_s] = "ABCD"; - SECTION("supports const char*") { + SECTION("string literal") { REQUIRE(var["ab"] == "AB"_s); REQUIRE(var["abc"] == "ABC"_s); + REQUIRE(var["abc\0d"] == "ABCD"_s); REQUIRE(var["def"].isNull()); REQUIRE(var[0].isNull()); } + SECTION("const char*") { + REQUIRE(var[static_cast("ab")] == "AB"_s); + REQUIRE(var[static_cast("abc")] == "ABC"_s); + REQUIRE(var[static_cast("abc\0d")] == "ABC"_s); + REQUIRE(var[static_cast("def")].isNull()); + REQUIRE(var[static_cast(0)].isNull()); + } + SECTION("supports std::string") { REQUIRE(var["ab"_s] == "AB"_s); REQUIRE(var["abc"_s] == "ABC"_s); diff --git a/lib/ArduinoJson/extras/tests/Misc/FloatParts.cpp b/lib/ArduinoJson/extras/tests/Misc/FloatParts.cpp deleted file mode 100644 index e75a88db..00000000 --- a/lib/ArduinoJson/extras/tests/Misc/FloatParts.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#include -#include - -using namespace ArduinoJson::detail; - -TEST_CASE("FloatParts") { - SECTION("1.7976931348623157E+308") { - FloatParts parts(1.7976931348623157E+308); - REQUIRE(parts.integral == 1); - REQUIRE(parts.decimal == 797693135); - REQUIRE(parts.decimalPlaces == 9); - REQUIRE(parts.exponent == 308); - } - - SECTION("4.94065645841247e-324") { - FloatParts parts(4.94065645841247e-324); - REQUIRE(parts.integral == 4); - REQUIRE(parts.decimal == 940656458); - REQUIRE(parts.decimalPlaces == 9); - REQUIRE(parts.exponent == -324); - } -} - -TEST_CASE("FloatParts") { - SECTION("3.4E+38") { - FloatParts parts(3.4E+38f); - REQUIRE(parts.integral == 3); - REQUIRE(parts.decimal == 4); - REQUIRE(parts.decimalPlaces == 1); - REQUIRE(parts.exponent == 38); - } - - SECTION("1.17549435e−38") { - FloatParts parts(1.17549435e-38f); - REQUIRE(parts.integral == 1); - REQUIRE(parts.decimal == 175494); - REQUIRE(parts.decimalPlaces == 6); - REQUIRE(parts.exponent == -38); - } -} diff --git a/lib/ArduinoJson/extras/tests/Misc/JsonString.cpp b/lib/ArduinoJson/extras/tests/Misc/JsonString.cpp index 6b9ac5e1..3a33677f 100644 --- a/lib/ArduinoJson/extras/tests/Misc/JsonString.cpp +++ b/lib/ArduinoJson/extras/tests/Misc/JsonString.cpp @@ -13,7 +13,7 @@ TEST_CASE("JsonString") { CHECK(s.isNull() == true); CHECK(s.c_str() == 0); - CHECK(s.isLinked() == true); + CHECK(s.isStatic() == true); CHECK(s == JsonString()); CHECK(s != ""); } @@ -96,7 +96,7 @@ TEST_CASE("JsonString") { JsonString s("hello world", 5); CHECK(s.size() == 5); - CHECK(s.isLinked() == true); + CHECK(s.isStatic() == false); CHECK(s == "hello"); CHECK(s != "hello world"); } diff --git a/lib/ArduinoJson/extras/tests/Misc/StringAdapters.cpp b/lib/ArduinoJson/extras/tests/Misc/StringAdapters.cpp index b33ab990..71e458bc 100644 --- a/lib/ArduinoJson/extras/tests/Misc/StringAdapters.cpp +++ b/lib/ArduinoJson/extras/tests/Misc/StringAdapters.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -16,27 +17,36 @@ using ArduinoJson::JsonString; using namespace ArduinoJson::detail; TEST_CASE("adaptString()") { + SECTION("string literal") { + auto s = adaptString("bravo\0alpha"); + + CHECK(s.isNull() == false); + CHECK(s.size() == 11); + CHECK(s.isStatic() == true); + } + SECTION("null const char*") { auto s = adaptString(static_cast(0)); CHECK(s.isNull() == true); CHECK(s.size() == 0); - CHECK(s.isLinked() == true); } SECTION("non-null const char*") { - auto s = adaptString("bravo"); + const char* p = "bravo"; + auto s = adaptString(p); CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == true); + CHECK(s.isStatic() == false); + CHECK(s.data() == p); } SECTION("null const char* + size") { auto s = adaptString(static_cast(0), 10); CHECK(s.isNull() == true); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("non-null const char* + size") { @@ -44,7 +54,7 @@ TEST_CASE("adaptString()") { CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("null Flash string") { @@ -52,7 +62,7 @@ TEST_CASE("adaptString()") { CHECK(s.isNull() == true); CHECK(s.size() == 0); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("non-null Flash string") { @@ -60,7 +70,7 @@ TEST_CASE("adaptString()") { CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("std::string") { @@ -69,7 +79,7 @@ TEST_CASE("adaptString()") { CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("Arduino String") { @@ -78,7 +88,7 @@ TEST_CASE("adaptString()") { CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("custom_string") { @@ -87,25 +97,25 @@ TEST_CASE("adaptString()") { CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } SECTION("JsonString linked") { - JsonString orig("hello", JsonString::Ownership::Linked); + JsonString orig("hello", true); auto s = adaptString(orig); CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == true); + CHECK(s.isStatic() == true); } SECTION("JsonString copied") { - JsonString orig("hello", JsonString::Ownership::Copied); + JsonString orig("hello", false); auto s = adaptString(orig); CHECK(s.isNull() == false); CHECK(s.size() == 5); - CHECK(s.isLinked() == false); + CHECK(s.isStatic() == false); } } diff --git a/lib/ArduinoJson/extras/tests/Misc/TypeTraits.cpp b/lib/ArduinoJson/extras/tests/Misc/TypeTraits.cpp index 7beb4658..5d081061 100644 --- a/lib/ArduinoJson/extras/tests/Misc/TypeTraits.cpp +++ b/lib/ArduinoJson/extras/tests/Misc/TypeTraits.cpp @@ -211,6 +211,23 @@ TEST_CASE("Polyfills/type_traits") { CHECK(is_enum::value == false); CHECK(is_enum::value == false); } + + SECTION("remove_cv") { + CHECK(is_same, int>::value); + CHECK(is_same, int>::value); + CHECK(is_same, int>::value); + CHECK(is_same, int>::value); + CHECK(is_same, decltype("toto")>::value); + } + + SECTION("decay") { + CHECK(is_same, int>::value); + CHECK(is_same, int>::value); + CHECK(is_same, int>::value); + CHECK(is_same, int*>::value); + CHECK(is_same, int*>::value); + CHECK(is_same, const char*>::value); + } } TEST_CASE("is_std_string") { diff --git a/lib/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp b/lib/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp index 43ca3ff4..505b56ce 100644 --- a/lib/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp +++ b/lib/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp @@ -139,7 +139,8 @@ TEST_CASE("serialize MsgPack value") { SECTION("str 32") { std::string shortest(65536, '?'); - checkVariant(shortest.c_str(), "\xDB\x00\x01\x00\x00"_s + shortest); + checkVariant(JsonString(shortest.c_str(), true), // force store by pointer + "\xDB\x00\x01\x00\x00"_s + shortest); } SECTION("serialized(const char*)") { diff --git a/lib/ArduinoJson/idf_component.yml b/lib/ArduinoJson/idf_component.yml index 4a65119b..70641db9 100644 --- a/lib/ArduinoJson/idf_component.yml +++ b/lib/ArduinoJson/idf_component.yml @@ -1,7 +1,7 @@ -version: "7.2.1" +version: "7.3.0" description: >- A simple and efficient JSON library for embedded C++. - ★ 6739 stars on GitHub! + ★ 6785 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented. url: https://arduinojson.org/ diff --git a/lib/ArduinoJson/library.json b/lib/ArduinoJson/library.json index 4c61b310..ba5d224c 100644 --- a/lib/ArduinoJson/library.json +++ b/lib/ArduinoJson/library.json @@ -1,13 +1,13 @@ { "name": "ArduinoJson", "keywords": "json, rest, http, web", - "description": "A simple and efficient JSON library for embedded C++. ⭐ 6739 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.", + "description": "A simple and efficient JSON library for embedded C++. ⭐ 6785 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.", "homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json", "repository": { "type": "git", "url": "https://github.com/bblanchon/ArduinoJson.git" }, - "version": "7.2.1", + "version": "7.3.0", "authors": { "name": "Benoit Blanchon", "url": "https://blog.benoitblanchon.fr" diff --git a/lib/ArduinoJson/library.properties b/lib/ArduinoJson/library.properties index c3ea5c35..6a153c08 100644 --- a/lib/ArduinoJson/library.properties +++ b/lib/ArduinoJson/library.properties @@ -1,9 +1,9 @@ name=ArduinoJson -version=7.2.1 +version=7.3.0 author=Benoit Blanchon maintainer=Benoit Blanchon sentence=A simple and efficient JSON library for embedded C++. -paragraph=⭐ 6739 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented. +paragraph=⭐ 6785 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented. category=Data Processing url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties architectures=* diff --git a/lib/ArduinoJson/src/ArduinoJson/Array/ArrayData.hpp b/lib/ArduinoJson/src/ArduinoJson/Array/ArrayData.hpp index c2ae1fb3..f0f3175d 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Array/ArrayData.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Array/ArrayData.hpp @@ -19,10 +19,10 @@ class ArrayData : public CollectionData { } template - bool addValue(T&& value, ResourceManager* resources); + bool addValue(const T& value, ResourceManager* resources); template - static bool addValue(ArrayData* array, T&& value, + static bool addValue(ArrayData* array, const T& value, ResourceManager* resources) { if (!array) return false; diff --git a/lib/ArduinoJson/src/ArduinoJson/Array/ArrayImpl.hpp b/lib/ArduinoJson/src/ArduinoJson/Array/ArrayImpl.hpp index 9599a5eb..de261930 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Array/ArrayImpl.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Array/ArrayImpl.hpp @@ -57,13 +57,13 @@ inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { } template -inline bool ArrayData::addValue(T&& value, ResourceManager* resources) { +inline bool ArrayData::addValue(const T& value, ResourceManager* resources) { ARDUINOJSON_ASSERT(resources != nullptr); auto slot = resources->allocVariant(); if (!slot) return false; JsonVariant variant(slot.ptr(), resources); - if (!variant.set(detail::forward(value))) { + if (!variant.set(value)) { resources->freeVariant(slot); return false; } diff --git a/lib/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp b/lib/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp index f36b68ea..06994a93 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp @@ -15,13 +15,18 @@ class ElementProxy : public VariantRefBase>, public VariantOperators> { friend class VariantAttorney; + friend class VariantRefBase>; + + template + friend class MemberProxy; + + template + friend class ElementProxy; + public: ElementProxy(TUpstream upstream, size_t index) : upstream_(upstream), index_(index) {} - ElementProxy(const ElementProxy& src) - : upstream_(src.upstream_), index_(src.index_) {} - ElementProxy& operator=(const ElementProxy& src) { this->set(src); return *this; @@ -40,6 +45,11 @@ class ElementProxy : public VariantRefBase>, } private: + // clang-format off + ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/ + : upstream_(src.upstream_), index_(src.index_) {} + // clang-format on + ResourceManager* getResourceManager() const { return VariantAttorney::getResourceManager(upstream_); } diff --git a/lib/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp b/lib/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp index 0e3ea2ee..7f02f987 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp @@ -43,16 +43,18 @@ class JsonArray : public detail::VariantOperators { // Appends a new (empty) element to the array. // Returns a reference to the new element. // https://arduinojson.org/v7/api/jsonarray/add/ - template - detail::enable_if_t::value, T> add() const { + template ::value, int> = 0> + T add() const { return add().to(); } // Appends a new (null) element to the array. // Returns a reference to the new element. // https://arduinojson.org/v7/api/jsonarray/add/ - template - detail::enable_if_t::value, T> add() const { + template ::value, int> = 0> + JsonVariant add() const { return JsonVariant(detail::ArrayData::addElement(data_, resources_), resources_); } @@ -66,7 +68,8 @@ class JsonArray : public detail::VariantOperators { // Appends a value to the array. // https://arduinojson.org/v7/api/jsonarray/add/ - template + template ::value, int> = 0> bool add(T* value) const { return detail::ArrayData::addValue(data_, value, resources_); } @@ -114,9 +117,9 @@ class JsonArray : public detail::VariantOperators { // Removes the element at the specified index. // https://arduinojson.org/v7/api/jsonarray/remove/ - template - detail::enable_if_t::value> remove( - TVariant variant) const { + template ::value, int> = 0> + void remove(const TVariant& variant) const { if (variant.template is()) remove(variant.template as()); } @@ -129,21 +132,19 @@ class JsonArray : public detail::VariantOperators { // Gets or sets the element at the specified index. // https://arduinojson.org/v7/api/jsonarray/subscript/ - template - detail::enable_if_t::value, - detail::ElementProxy> - operator[](T index) const { + template ::value, int> = 0> + detail::ElementProxy operator[](T index) const { return {*this, size_t(index)}; } // Gets or sets the element at the specified index. // https://arduinojson.org/v7/api/jsonarray/subscript/ - template - detail::enable_if_t::value, - detail::ElementProxy> - operator[](const TVariant& variant) const { + template ::value, int> = 0> + detail::ElementProxy operator[](const TVariant& variant) const { if (variant.template is()) - return operator[](variant.template as()); + return {*this, variant.template as()}; else return {*this, size_t(-1)}; } diff --git a/lib/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp b/lib/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp index 6b9db192..b0535187 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp @@ -45,9 +45,9 @@ class JsonArrayConst : public detail::VariantOperators { // Returns the element at the specified index. // https://arduinojson.org/v7/api/jsonarrayconst/subscript/ - template - detail::enable_if_t::value, JsonVariantConst> - operator[](T index) const { + template ::value, int> = 0> + JsonVariantConst operator[](T index) const { return JsonVariantConst( detail::ArrayData::getElement(data_, size_t(index), resources_), resources_); @@ -55,9 +55,9 @@ class JsonArrayConst : public detail::VariantOperators { // Returns the element at the specified index. // https://arduinojson.org/v7/api/jsonarrayconst/subscript/ - template - detail::enable_if_t::value, JsonVariantConst> - operator[](const TVariant& variant) const { + template ::value, int> = 0> + JsonVariantConst operator[](const TVariant& variant) const { if (variant.template is()) return operator[](variant.template as()); else diff --git a/lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp b/lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp index 9073468c..200cb66b 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp @@ -11,27 +11,26 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // Copies a value to a JsonVariant. // This is a degenerated form of copyArray() to stop the recursion. -template -inline detail::enable_if_t::value, bool> copyArray( - const T& src, JsonVariant dst) { +template ::value, int> = 0> +inline bool copyArray(const T& src, JsonVariant dst) { return dst.set(src); } // Copies values from an array to a JsonArray or a JsonVariant. // https://arduinojson.org/v7/api/misc/copyarray/ -template -inline detail::enable_if_t< - !detail::is_base_of::value, bool> -copyArray(T (&src)[N], const TDestination& dst) { +template ::value, int> = 0> +inline bool copyArray(T (&src)[N], const TDestination& dst) { return copyArray(src, N, dst); } // Copies values from an array to a JsonArray or a JsonVariant. // https://arduinojson.org/v7/api/misc/copyarray/ -template -inline detail::enable_if_t< - !detail::is_base_of::value, bool> -copyArray(const T* src, size_t len, const TDestination& dst) { +template ::value, int> = 0> +inline bool copyArray(const T* src, size_t len, const TDestination& dst) { bool ok = true; for (size_t i = 0; i < len; i++) { ok &= copyArray(src[i], dst.template add()); @@ -62,9 +61,8 @@ inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { // Copies a value from a JsonVariant. // This is a degenerated form of copyArray() to stop the recursion. -template -inline detail::enable_if_t::value, size_t> copyArray( - JsonVariantConst src, T& dst) { +template ::value, int> = 0> +inline size_t copyArray(JsonVariantConst src, T& dst) { dst = src.as(); return 1; } @@ -102,11 +100,12 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) { // Copies values from a JsonDocument to an array. // https://arduinojson.org/v7/api/misc/copyarray/ -template -inline detail::enable_if_t::value && - detail::is_base_of::value, - size_t> -copyArray(const TSource& src, T& dst) { +template < + typename TSource, typename T, + detail::enable_if_t::value && + detail::is_base_of::value, + int> = 0> +inline size_t copyArray(const TSource& src, T& dst) { return copyArray(src.template as(), dst); } diff --git a/lib/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp b/lib/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp index fed87b34..e728047c 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp @@ -11,7 +11,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -// The default reader is a simple wrapper for Readers that are not copiable +// The default reader is a simple wrapper for Readers that are not copyable template struct Reader { public: diff --git a/lib/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp b/lib/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp index a95049a3..c1963a8f 100644 --- a/lib/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp +++ b/lib/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp @@ -55,10 +55,11 @@ DeserializationError doDeserialize(TDestination&& dst, TReader reader, return err; } -template