Update to ArduinoJson 7.0.4

This commit is contained in:
iranl
2024-04-19 14:44:01 +02:00
parent 1378732081
commit 81be0a689a
444 changed files with 10842 additions and 9422 deletions

View File

@@ -1,20 +1,18 @@
# ArduinoJson - https://arduinojson.org
# Copyright © 2014-2023, Benoit BLANCHON
# Copyright © 2014-2024, Benoit BLANCHON
# MIT License
add_executable(JsonDeserializerTests
array.cpp
array_static.cpp
DeserializationError.cpp
destination_types.cpp
errors.cpp
filter.cpp
incomplete_input.cpp
input_types.cpp
invalid_input.cpp
misc.cpp
nestingLimit.cpp
number.cpp
object.cpp
object_static.cpp
string.cpp
)

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>

View File

@@ -1,12 +1,17 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
TEST_CASE("deserialize JSON array") {
DynamicJsonDocument doc(4096);
SpyingAllocator spy;
JsonDocument doc(&spy);
SECTION("An empty array") {
DeserializationError err = deserializeJson(doc, "[]");
@@ -244,10 +249,71 @@ TEST_CASE("deserialize JSON array") {
SECTION("Should clear the JsonArray") {
deserializeJson(doc, "[1,2,3,4]");
deserializeJson(doc, "[]");
JsonArray arr = doc.as<JsonArray>();
spy.clearLog();
deserializeJson(doc, "[]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr.size() == 0);
REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(0));
REQUIRE(spy.log() == AllocatorLog{
Deallocate(sizeofArray(4)),
});
}
}
TEST_CASE("deserialize JSON array under memory constraints") {
TimebombAllocator timebomb(100);
SpyingAllocator spy(&timebomb);
JsonDocument doc(&spy);
SECTION("empty array requires no allocation") {
timebomb.setCountdown(0);
char input[] = "[]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("allocation of pool list fails") {
timebomb.setCountdown(0);
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
REQUIRE(doc.as<std::string>() == "[]");
}
SECTION("allocation of pool fails") {
timebomb.setCountdown(0);
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
REQUIRE(doc.as<std::string>() == "[]");
}
SECTION("allocation of string fails in array") {
timebomb.setCountdown(1);
char input[] = "[0,\"hi!\"]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
REQUIRE(doc.as<std::string>() == "[0,null]");
}
SECTION("don't store space characters") {
deserializeJson(doc, " [ \"1234567\" ] ");
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("1234567")),
Reallocate(sizeofPool(), sizeofArray(1)),
});
}
}

View File

@@ -1,89 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
SECTION("BufferOfTheRightSizeForEmptyArray") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
char input[] = "[]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("TooSmallBufferForArrayWithOneValue") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithOneValue") {
StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc;
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("TooSmallBufferForArrayWithNestedObject") {
StaticJsonDocument<JSON_ARRAY_SIZE(0) + JSON_OBJECT_SIZE(0)> doc;
char input[] = "[{}]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithNestedObject") {
StaticJsonDocument<JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(0)> doc;
char input[] = "[{}]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("CopyStringNotSpaces") {
StaticJsonDocument<100> doc;
deserializeJson(doc, " [ \"1234567\" ] ");
REQUIRE(JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(7) == doc.memoryUsage());
// note: we use a string of 8 bytes to be sure that the StaticMemoryPool
// will not insert bytes to enforce alignement
}
SECTION("Should clear the JsonArray") {
StaticJsonDocument<JSON_ARRAY_SIZE(4)> doc;
char input[] = "[1,2,3,4]";
deserializeJson(doc, input);
deserializeJson(doc, "[]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr.size() == 0);
REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(0));
}
SECTION("Array") {
StaticJsonDocument<JSON_ARRAY_SIZE(2)> doc;
char input[] = "[1,2]";
DeserializationError err = deserializeJson(doc, input);
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<JsonArray>());
REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(2));
REQUIRE(arr[0] == 1);
REQUIRE(arr[1] == 2);
}
}

View File

@@ -0,0 +1,108 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include <string>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
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<std::string>() == "[42]");
REQUIRE(spy.log() == AllocatorLog{
Deallocate(sizeofPool()),
Deallocate(sizeofString("hello")),
Allocate(sizeofPool()),
Reallocate(sizeofPool(), sizeofArray(1)),
});
}
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<std::string>() == "[[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<std::string>() == "[[42]]");
REQUIRE(spy.log() == AllocatorLog{
Deallocate(sizeofString("hello")),
});
}
SECTION("element must be created") {
auto err = deserializeJson(doc[1], "[42]");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.as<std::string>() == "[\"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<std::string>() == "{\"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<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
REQUIRE(spy.log() == AllocatorLog{});
}
}

View File

@@ -0,0 +1,120 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserializeJson() returns IncompleteInput") {
const char* testCases[] = {
// strings
"\"\\",
"\"hello",
"\'hello",
// unicode
"'\\u",
"'\\u00",
"'\\u000",
// false
"f",
"fa",
"fal",
"fals",
// true
"t",
"tr",
"tru",
// null
"n",
"nu",
"nul",
// object
"{",
"{a",
"{a:",
"{a:1",
"{a:1,",
"{a:1,b",
"{a:1,b:",
};
for (auto input : testCases) {
SECTION(input) {
JsonDocument doc;
REQUIRE(deserializeJson(doc, input) ==
DeserializationError::IncompleteInput);
}
}
}
TEST_CASE("deserializeJson() returns InvalidInput") {
const char* testCases[] = {
// unicode
"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'", "'\\u000/'", "\\x1234",
// numbers
"6a9", "1,", "2]", "3}",
// constants
"nulL", "tru3", "fals3",
// garbage
"%*$£¤"};
for (auto input : testCases) {
SECTION(input) {
JsonDocument doc;
REQUIRE(deserializeJson(doc, input) ==
DeserializationError::InvalidInput);
}
}
}
TEST_CASE("deserializeJson() oversees some edge cases") {
const char* testCases[] = {
"'\\ud83d'", // leading surrogate without a trailing surrogate
"'\\udda4'", // trailing surrogate without a leading surrogate
"'\\ud83d\\ud83d'", // two leading surrogates
};
for (auto input : testCases) {
SECTION(input) {
JsonDocument doc;
REQUIRE(deserializeJson(doc, input) == DeserializationError::Ok);
}
}
}
TEST_CASE("deserializeJson() returns EmptyInput") {
JsonDocument doc;
SECTION("null") {
auto err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err == DeserializationError::EmptyInput);
}
SECTION("Empty string") {
auto err = deserializeJson(doc, "");
REQUIRE(err == DeserializationError::EmptyInput);
}
SECTION("Only spaces") {
auto err = deserializeJson(doc, " \t\n\r");
REQUIRE(err == DeserializationError::EmptyInput);
}
}
TEST_CASE("deserializeJson() returns NoMemory if string length overflows") {
JsonDocument doc;
auto maxLength = ArduinoJson::detail::StringNode::maxLength;
SECTION("max length should succeed") {
auto err = deserializeJson(doc, "\"" + std::string(maxLength, 'a') + "\"");
REQUIRE(err == DeserializationError::Ok);
}
SECTION("one above max length should fail") {
auto err =
deserializeJson(doc, "\"" + std::string(maxLength + 1, 'a') + "\"");
REQUIRE(err == DeserializationError::NoMemory);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Truncated JSON input") {
const char* testCases[] = {"\"hello", "\'hello", "'\\u", "'\\u00", "'\\u000",
// false
"f", "fa", "fal", "fals",
// true
"t", "tr", "tru",
// null
"n", "nu", "nul",
// object
"{", "{a", "{a:", "{a:1", "{a:1,", "{a:1,"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
CAPTURE(input);
REQUIRE(deserializeJson(doc, input) ==
DeserializationError::IncompleteInput);
}
}

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
@@ -7,25 +7,58 @@
#include <catch.hpp>
#include <sstream>
#include "Allocators.hpp"
#include "CustomReader.hpp"
using ArduinoJson::detail::sizeofObject;
TEST_CASE("deserializeJson(char*)") {
StaticJsonDocument<1024> doc;
SpyingAllocator spy;
JsonDocument doc(&spy);
SECTION("should not duplicate strings") {
char input[] = "{\"hello\":\"world\"}";
char input[] = "{\"hello\":\"world\"}";
DeserializationError err = deserializeJson(doc, input);
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1));
CHECK(doc.as<JsonVariant>().memoryUsage() ==
JSON_OBJECT_SIZE(1)); // issue #1318
}
REQUIRE(err == DeserializationError::Ok);
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("hello")),
Allocate(sizeofPool()),
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("world")),
Reallocate(sizeofPool(), sizeofObject(1)),
});
}
TEST_CASE("deserializeJson(unsigned char*, unsigned int)") { // issue #1897
JsonDocument doc;
unsigned char input[] = "{\"hello\":\"world\"}";
unsigned char* input_ptr = input;
unsigned int size = sizeof(input);
DeserializationError err = deserializeJson(doc, input_ptr, size);
REQUIRE(err == DeserializationError::Ok);
}
TEST_CASE("deserializeJson(uint8_t*, size_t)") { // issue #1898
JsonDocument doc;
uint8_t input[] = "{\"hello\":\"world\"}";
uint8_t* input_ptr = input;
size_t size = sizeof(input);
DeserializationError err = deserializeJson(doc, input_ptr, size);
REQUIRE(err == DeserializationError::Ok);
}
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc(4096);
JsonDocument doc;
SECTION("should accept const string") {
const std::string input("[42]");
@@ -54,7 +87,7 @@ TEST_CASE("deserializeJson(const std::string&)") {
}
TEST_CASE("deserializeJson(std::istream&)") {
DynamicJsonDocument doc(4096);
JsonDocument doc;
SECTION("array") {
std::istringstream json(" [ 42 ] ");
@@ -125,7 +158,7 @@ TEST_CASE("deserializeJson(VLA)") {
char vla[i];
strcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
JsonDocument doc;
DeserializationError err = deserializeJson(doc, vla);
REQUIRE(err == DeserializationError::Ok);
@@ -133,7 +166,7 @@ TEST_CASE("deserializeJson(VLA)") {
#endif
TEST_CASE("deserializeJson(CustomReader)") {
DynamicJsonDocument doc(4096);
JsonDocument doc;
CustomReader reader("[4,2]");
DeserializationError err = deserializeJson(doc, reader);
@@ -144,10 +177,10 @@ TEST_CASE("deserializeJson(CustomReader)") {
}
TEST_CASE("deserializeJson(JsonDocument&, MemberProxy)") {
DynamicJsonDocument doc1(4096);
JsonDocument doc1;
doc1["payload"] = "[4,2]";
DynamicJsonDocument doc2(4096);
JsonDocument doc2;
DeserializationError err = deserializeJson(doc2, doc1["payload"]);
REQUIRE(err == DeserializationError::Ok);
@@ -157,10 +190,10 @@ TEST_CASE("deserializeJson(JsonDocument&, MemberProxy)") {
}
TEST_CASE("deserializeJson(JsonDocument&, JsonVariant)") {
DynamicJsonDocument doc1(4096);
JsonDocument doc1;
doc1["payload"] = "[4,2]";
DynamicJsonDocument doc2(4096);
JsonDocument doc2;
DeserializationError err =
deserializeJson(doc2, doc1["payload"].as<JsonVariant>());
@@ -171,10 +204,10 @@ TEST_CASE("deserializeJson(JsonDocument&, JsonVariant)") {
}
TEST_CASE("deserializeJson(JsonDocument&, JsonVariantConst)") {
DynamicJsonDocument doc1(4096);
JsonDocument doc1;
doc1["payload"] = "[4,2]";
DynamicJsonDocument doc2(4096);
JsonDocument doc2;
DeserializationError err =
deserializeJson(doc2, doc1["payload"].as<JsonVariantConst>());
@@ -185,10 +218,10 @@ TEST_CASE("deserializeJson(JsonDocument&, JsonVariantConst)") {
}
TEST_CASE("deserializeJson(JsonDocument&, ElementProxy)") {
DynamicJsonDocument doc1(4096);
JsonDocument doc1;
doc1[0] = "[4,2]";
DynamicJsonDocument doc2(4096);
JsonDocument doc2;
DeserializationError err = deserializeJson(doc2, doc1[0]);
REQUIRE(err == DeserializationError::Ok);

View File

@@ -1,40 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Invalid JSON input") {
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'",
"'\\u000/'", "\\x1234", "6a9", "1,",
"nulL", "tru3", "fals3", "2]",
"3}"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
CAPTURE(input);
REQUIRE(deserializeJson(doc, input) == DeserializationError::InvalidInput);
}
}
TEST_CASE("Invalid JSON input that should pass") {
const char* testCases[] = {
"'\\ud83d'", // leading surrogate without a trailing surrogate
"'\\udda4'", // trailing surrogate without a leading surrogate
"'\\ud83d\\ud83d'", // two leading surrogates
};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
CAPTURE(input);
REQUIRE(deserializeJson(doc, input) == DeserializationError::Ok);
}
}

View File

@@ -1,117 +1,49 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace Catch::Matchers;
#include "Allocators.hpp"
TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
DynamicJsonDocument doc(4096);
using ArduinoJson::detail::sizeofArray;
SECTION("Edge cases") {
SECTION("null char*") {
DeserializationError err = deserializeJson(doc, static_cast<char*>(0));
TEST_CASE("deserializeJson() misc cases") {
SpyingAllocator spy;
JsonDocument doc(&spy);
REQUIRE(err != DeserializationError::Ok);
}
SECTION("null const char*") {
DeserializationError err =
deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err != DeserializationError::Ok);
}
SECTION("Empty input") {
DeserializationError err = deserializeJson(doc, "");
REQUIRE(err == DeserializationError::EmptyInput);
}
SECTION("Only spaces") {
DeserializationError err = deserializeJson(doc, " \t\n\r");
REQUIRE(err == DeserializationError::EmptyInput);
}
SECTION("issue #628") {
DeserializationError err = deserializeJson(doc, "null");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == false);
}
SECTION("Garbage") {
DeserializationError err = deserializeJson(doc, "%*$£¤");
REQUIRE(err == DeserializationError::InvalidInput);
}
SECTION("null") {
DeserializationError err = deserializeJson(doc, "null");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == false);
}
SECTION("Booleans") {
SECTION("True") {
DeserializationError err = deserializeJson(doc, "true");
SECTION("true") {
DeserializationError err = deserializeJson(doc, "true");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<bool>());
REQUIRE(doc.as<bool>() == true);
}
SECTION("False") {
DeserializationError err = deserializeJson(doc, "false");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<bool>());
REQUIRE(doc.as<bool>() == false);
}
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<bool>());
REQUIRE(doc.as<bool>() == true);
}
SECTION("Premature null-terminator") {
SECTION("In escape sequence") {
DeserializationError err = deserializeJson(doc, "\"\\");
SECTION("false") {
DeserializationError err = deserializeJson(doc, "false");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In double quoted string") {
DeserializationError err = deserializeJson(doc, "\"hello");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In single quoted string") {
DeserializationError err = deserializeJson(doc, "'hello");
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
SECTION("Premature end of input") {
SECTION("In escape sequence") {
DeserializationError err = deserializeJson(doc, "\"\\n\"", 2);
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In double quoted string") {
DeserializationError err = deserializeJson(doc, "\"hello\"", 6);
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In single quoted string") {
DeserializationError err = deserializeJson(doc, "'hello'", 6);
REQUIRE(err == DeserializationError::IncompleteInput);
}
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<bool>());
REQUIRE(doc.as<bool>() == false);
}
SECTION("Should clear the JsonVariant") {
deserializeJson(doc, "[1,2,3]");
spy.clearLog();
deserializeJson(doc, "{}");
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0));
REQUIRE(spy.log() == AllocatorLog{
Deallocate(sizeofArray(3)),
});
}
}

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
@@ -12,7 +12,7 @@
REQUIRE(DeserializationError::TooDeep == expression);
TEST_CASE("JsonDeserializer nesting") {
DynamicJsonDocument doc(4096);
JsonDocument doc;
SECTION("Input = const char*") {
SECTION("limit = 0") {

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#define ARDUINOJSON_USE_LONG_LONG 0
@@ -16,7 +16,7 @@ using ArduinoJson::detail::isnan;
} // namespace my
TEST_CASE("deserialize an integer") {
DynamicJsonDocument doc(4096);
JsonDocument doc;
SECTION("Integer") {
SECTION("0") {

View File

@@ -1,12 +1,17 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofObject;
TEST_CASE("deserialize JSON object") {
DynamicJsonDocument doc(4096);
SpyingAllocator spy;
JsonDocument doc(&spy);
SECTION("An empty object") {
DeserializationError err = deserializeJson(doc, "{}");
@@ -277,7 +282,22 @@ TEST_CASE("deserialize JSON object") {
DeserializationError err = deserializeJson(doc, "{a:{b:{c:1}},a:2}");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc["a"] == 2);
REQUIRE(doc.as<std::string>() == "{\"a\":2}");
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("a")),
Allocate(sizeofPool()),
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("b")),
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("c")),
Allocate(sizeofStringBuffer()),
Deallocate(sizeofString("b")),
Deallocate(sizeofString("c")),
Deallocate(sizeofStringBuffer()),
Reallocate(sizeofPool(), sizeofObject(2) + sizeofObject(1)),
});
}
SECTION("Repeated key with zero copy mode") { // issue #1697
@@ -299,12 +319,17 @@ TEST_CASE("deserialize JSON object") {
SECTION("Should clear the JsonObject") {
deserializeJson(doc, "{\"hello\":\"world\"}");
spy.clearLog();
deserializeJson(doc, "{}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(doc.is<JsonObject>());
REQUIRE(obj.size() == 0);
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0));
REQUIRE(doc.size() == 0);
REQUIRE(spy.log() == AllocatorLog{
Deallocate(sizeofObject(1)),
Deallocate(sizeofString("hello")),
Deallocate(sizeofString("world")),
});
}
SECTION("Issue #1335") {
@@ -313,3 +338,48 @@ TEST_CASE("deserialize JSON object") {
CHECK(doc.as<std::string>() == json);
}
}
TEST_CASE("deserialize JSON object under memory constraints") {
TimebombAllocator timebomb(1024);
JsonDocument doc(&timebomb);
SECTION("empty object requires no allocation") {
timebomb.setCountdown(0);
char input[] = "{}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.as<std::string>() == "{}");
}
SECTION("key allocation fails") {
timebomb.setCountdown(0);
char input[] = "{\"a\":1}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
REQUIRE(doc.as<std::string>() == "{}");
}
SECTION("pool allocation fails") {
timebomb.setCountdown(2);
char input[] = "{\"a\":1}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
REQUIRE(doc.as<std::string>() == "{}");
}
SECTION("string allocation fails") {
timebomb.setCountdown(3);
char input[] = "{\"a\":\"b\"}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
REQUIRE(doc.as<std::string>() == "{\"a\":null}");
}
}

View File

@@ -1,64 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserialize JSON object with StaticJsonDocument") {
SECTION("BufferOfTheRightSizeForEmptyObject") {
StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc;
char input[] = "{}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("TooSmallBufferForObjectWithOneValue") {
StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc;
char input[] = "{\"a\":1}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("BufferOfTheRightSizeForObjectWithOneValue") {
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
char input[] = "{\"a\":1}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("TooSmallBufferForObjectWithNestedObject") {
StaticJsonDocument<JSON_OBJECT_SIZE(0) + JSON_ARRAY_SIZE(0)> doc;
char input[] = "{\"a\":[]}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("BufferOfTheRightSizeForObjectWithNestedObject") {
StaticJsonDocument<JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(0)> doc;
char input[] = "{\"a\":[]}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("Should clear the JsonObject") {
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
char input[] = "{\"hello\":\"world\"}";
deserializeJson(doc, input);
deserializeJson(doc, "{}");
REQUIRE(doc.as<JsonObject>().size() == 0);
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0));
}
}

View File

@@ -1,11 +1,16 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
TEST_CASE("Valid JSON strings value") {
struct TestCase {
const char* input;
@@ -35,7 +40,7 @@ TEST_CASE("Valid JSON strings value") {
};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
JsonDocument doc;
for (size_t i = 0; i < testCount; i++) {
const TestCase& testCase = testCases[i];
@@ -47,7 +52,7 @@ TEST_CASE("Valid JSON strings value") {
}
TEST_CASE("\\u0000") {
StaticJsonDocument<200> doc;
JsonDocument doc;
DeserializationError err = deserializeJson(doc, "\"wx\\u0000yz\"");
REQUIRE(err == DeserializationError::Ok);
@@ -68,7 +73,7 @@ TEST_CASE("Truncated JSON string") {
const char* testCases[] = {"\"hello", "\'hello", "'\\u", "'\\u00", "'\\u000"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
JsonDocument doc;
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
@@ -83,7 +88,7 @@ TEST_CASE("Invalid JSON string") {
"'\\u000G'", "'\\u000/'", "'\\x1234'"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
JsonDocument doc;
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
@@ -92,41 +97,102 @@ TEST_CASE("Invalid JSON string") {
}
}
TEST_CASE("Not enough room to save the key") {
DynamicJsonDocument doc(JSON_OBJECT_SIZE(1) + 8);
TEST_CASE("Allocation of the key fails") {
TimebombAllocator timebomb(0);
SpyingAllocator spy(&timebomb);
JsonDocument doc(&spy);
SECTION("Quoted string") {
SECTION("Quoted string, first member") {
REQUIRE(deserializeJson(doc, "{\"example\":1}") ==
DeserializationError::Ok);
REQUIRE(deserializeJson(doc, "{\"accuracy\":1}") ==
DeserializationError::NoMemory);
REQUIRE(deserializeJson(doc, "{\"hello\":1,\"world\"}") ==
DeserializationError::NoMemory); // fails in the second string
REQUIRE(spy.log() == AllocatorLog{
AllocateFail(sizeofStringBuffer()),
});
}
SECTION("Non-quoted string") {
REQUIRE(deserializeJson(doc, "{example:1}") == DeserializationError::Ok);
REQUIRE(deserializeJson(doc, "{accuracy:1}") ==
SECTION("Quoted string, second member") {
timebomb.setCountdown(3);
REQUIRE(deserializeJson(doc, "{\"hello\":1,\"world\"}") ==
DeserializationError::NoMemory);
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("hello")),
Allocate(sizeofPool()),
AllocateFail(sizeofStringBuffer()),
ReallocateFail(sizeofPool(), sizeofObject(1)),
});
}
SECTION("Non-Quoted string, first member") {
REQUIRE(deserializeJson(doc, "{example:1}") ==
DeserializationError::NoMemory);
REQUIRE(spy.log() == AllocatorLog{
AllocateFail(sizeofStringBuffer()),
});
}
SECTION("Non-Quoted string, second member") {
timebomb.setCountdown(3);
REQUIRE(deserializeJson(doc, "{hello:1,world}") ==
DeserializationError::NoMemory); // fails in the second string
DeserializationError::NoMemory);
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("hello")),
Allocate(sizeofPool()),
AllocateFail(sizeofStringBuffer()),
ReallocateFail(sizeofPool(), sizeofObject(1)),
});
}
}
TEST_CASE("Empty memory pool") {
// NOLINTNEXTLINE(clang-analyzer-optin.portability.UnixAPI)
DynamicJsonDocument doc(0);
TEST_CASE("String allocation fails") {
SpyingAllocator spy(FailingAllocator::instance());
JsonDocument doc(&spy);
SECTION("Input is const char*") {
REQUIRE(deserializeJson(doc, "\"hello\"") ==
DeserializationError::NoMemory);
REQUIRE(deserializeJson(doc, "\"\"") == DeserializationError::NoMemory);
}
SECTION("Input is const char*") {
char hello[] = "\"hello\"";
REQUIRE(deserializeJson(doc, hello) == DeserializationError::Ok);
char empty[] = "\"hello\"";
REQUIRE(deserializeJson(doc, empty) == DeserializationError::Ok);
REQUIRE(spy.log() == AllocatorLog{
AllocateFail(sizeofStringBuffer()),
});
}
}
TEST_CASE("Deduplicate values") {
SpyingAllocator spy;
JsonDocument doc(&spy);
deserializeJson(doc, "[\"example\",\"example\"]");
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("example")),
Allocate(sizeofStringBuffer()),
Deallocate(sizeofStringBuffer()),
Reallocate(sizeofPool(), sizeofArray(2)),
});
}
TEST_CASE("Deduplicate keys") {
SpyingAllocator spy;
JsonDocument doc(&spy);
deserializeJson(doc, "[{\"example\":1},{\"example\":2}]");
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
CHECK(key1 == key2);
REQUIRE(spy.log() ==
AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofStringBuffer()),
Reallocate(sizeofStringBuffer(), sizeofString("example")),
Allocate(sizeofStringBuffer()),
Deallocate(sizeofStringBuffer()),
Reallocate(sizeofPool(), sizeofArray(2) + 2 * sizeofObject(1)),
});
}