Update ArduinoJSON, esp-nimble-cpp, Arduino Core, ESP-IDF (#448)

* ArduinoJSON 7.1.0

* Update nimble and arduino core

* Update nuki_ble
This commit is contained in:
iranl
2024-08-11 11:20:31 +02:00
committed by GitHub
parent 4af90cbc79
commit 9d55c2173d
216 changed files with 6437 additions and 5705 deletions

View File

@@ -1,6 +1,21 @@
ArduinoJson: change log
=======================
v7.1.0 (2024-06-27)
------
* Add `ARDUINOJSON_STRING_LENGTH_SIZE` to the namespace name
* Add support for MsgPack binary (PR #2078 by @Sanae6)
* Add support for MsgPack extension
* Make string support even more generic (PR #2084 by @d-a-v)
* Optimize `deserializeMsgPack()`
* Allow using a `JsonVariant` as a key or index (issue #2080)
Note: works only for reading, not for writing
* Support `ElementProxy` and `MemberProxy` in `JsonDocument`'s constructor
* Don't add partial objects when allocation fails (issue #2081)
* Read MsgPack's 64-bit integers even if `ARDUINOJSON_USE_LONG_LONG` is `0`
(they are set to `null` if they don't fit in a `long`)
v7.0.4 (2024-03-12)
------

View File

@@ -10,7 +10,7 @@ if(ESP_PLATFORM)
return()
endif()
project(ArduinoJson VERSION 7.0.4)
project(ArduinoJson VERSION 7.1.0)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)

46
lib/ArduinoJson/README Normal file
View File

@@ -0,0 +1,46 @@
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 <Foo.h>
#include <Bar.h>
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

View File

@@ -1,4 +1,4 @@
version: 7.0.4.{build}
version: 7.1.0.{build}
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022

View File

@@ -1,3 +1,7 @@
if(NOT DEFINED COVERAGE)
set(COVERAGE OFF)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
add_compile_options(
-pedantic
@@ -30,7 +34,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8) AND(NOT ${COVERAGE}))
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) AND(NOT ${COVERAGE}))
add_compile_options(-g -Og)
else() # GCC 4.8
add_compile_options(

View File

@@ -52,7 +52,16 @@ macro(add_fuzzer name)
)
endmacro()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6)
# Needs Clang 6+ to compile
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6)
if(DEFINED ENV{GITHUB_ACTIONS} AND CMAKE_CXX_COMPILER_VERSION MATCHES "^11\\.")
# Clang 11 fails on GitHub Actions with the following error:
# > ERROR: UndefinedBehaviorSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
# > Sanitizer CHECK failed: /build/llvm-toolchain-11-mnvtwk/llvm-toolchain-11-11.1.0/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp:54 ((0 && "unable to mmap")) != (0) (0, 0)
message(WARNING "Fuzzing is disabled on GitHub Actions to workaround a bug in Clang 11")
return()
endif()
add_fuzzer(json)
add_fuzzer(msgpack)
endif()

View File

@@ -12,6 +12,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
#if !ARDUINOJSON_ENABLE_STRING_VIEW
# error ARDUINOJSON_ENABLE_STRING_VIEW must be set to 1
@@ -92,7 +93,7 @@ TEST_CASE("string_view") {
}
SECTION("String containing NUL") {
doc.set(std::string("hello\0world", 11));
doc.set("hello\0world"_s);
REQUIRE(doc.as<std::string_view>().size() == 11);
REQUIRE(doc.as<std::string_view>() == std::string_view("hello\0world", 11));
}

View File

@@ -7,6 +7,8 @@
#include <string>
#include "Literals.hpp"
TEST_CASE("JsonDocument::createNestedArray()") {
JsonDocument doc;
@@ -23,7 +25,7 @@ TEST_CASE("JsonDocument::createNestedArray()") {
}
SECTION("createNestedArray(std::string)") {
JsonArray array = doc.createNestedArray(std::string("key"));
JsonArray array = doc.createNestedArray("key"_s);
array.add(42);
REQUIRE(doc.as<std::string>() == "{\"key\":[42]}");
}
@@ -59,7 +61,7 @@ TEST_CASE("JsonObject::createNestedArray()") {
}
SECTION("createNestedArray(std::string)") {
JsonArray array = object.createNestedArray(std::string("key"));
JsonArray array = object.createNestedArray("key"_s);
array.add(42);
REQUIRE(doc.as<std::string>() == "{\"key\":[42]}");
}
@@ -93,7 +95,7 @@ TEST_CASE("JsonVariant::createNestedArray()") {
}
SECTION("createNestedArray(std::string)") {
JsonArray array = variant.createNestedArray(std::string("key"));
JsonArray array = variant.createNestedArray("key"_s);
array.add(42);
REQUIRE(doc.as<std::string>() == "{\"key\":[42]}");
}

View File

@@ -7,6 +7,8 @@
#include <string>
#include "Literals.hpp"
TEST_CASE("JsonDocument::createNestedObject()") {
JsonDocument doc;
@@ -23,7 +25,7 @@ TEST_CASE("JsonDocument::createNestedObject()") {
}
SECTION("createNestedObject(std::string)") {
JsonObject object = doc.createNestedObject(std::string("key"));
JsonObject object = doc.createNestedObject("key"_s);
object["hello"] = "world";
REQUIRE(doc.as<std::string>() == "{\"key\":{\"hello\":\"world\"}}");
}
@@ -59,7 +61,7 @@ TEST_CASE("JsonObject::createNestedObject()") {
}
SECTION("createNestedObject(std::string)") {
JsonObject nestedObject = object.createNestedObject(std::string("key"));
JsonObject nestedObject = object.createNestedObject("key"_s);
nestedObject["hello"] = "world";
REQUIRE(doc.as<std::string>() == "{\"key\":{\"hello\":\"world\"}}");
}
@@ -93,7 +95,7 @@ TEST_CASE("JsonVariant::createNestedObject()") {
}
SECTION("createNestedObject(std::string)") {
JsonObject object = variant.createNestedObject(std::string("key"));
JsonObject object = variant.createNestedObject("key"_s);
object["hello"] = "world";
REQUIRE(doc.as<std::string>() == "{\"key\":{\"hello\":\"world\"}}");
}

View File

@@ -10,6 +10,8 @@
#include <sstream>
namespace {
struct FailingAllocator : ArduinoJson::Allocator {
static FailingAllocator* instance() {
static FailingAllocator allocator;
@@ -54,31 +56,31 @@ class AllocatorLogEntry {
inline AllocatorLogEntry Allocate(size_t s) {
char buffer[32];
sprintf(buffer, "allocate(%zu)", s);
snprintf(buffer, sizeof(buffer), "allocate(%zu)", s);
return AllocatorLogEntry(buffer);
}
inline AllocatorLogEntry AllocateFail(size_t s) {
char buffer[32];
sprintf(buffer, "allocate(%zu) -> nullptr", s);
snprintf(buffer, sizeof(buffer), "allocate(%zu) -> nullptr", s);
return AllocatorLogEntry(buffer);
}
inline AllocatorLogEntry Reallocate(size_t s1, size_t s2) {
char buffer[32];
sprintf(buffer, "reallocate(%zu, %zu)", s1, s2);
snprintf(buffer, sizeof(buffer), "reallocate(%zu, %zu)", s1, s2);
return AllocatorLogEntry(buffer);
}
inline AllocatorLogEntry ReallocateFail(size_t s1, size_t s2) {
char buffer[32];
sprintf(buffer, "reallocate(%zu, %zu) -> nullptr", s1, s2);
snprintf(buffer, sizeof(buffer), "reallocate(%zu, %zu) -> nullptr", s1, s2);
return AllocatorLogEntry(buffer);
}
inline AllocatorLogEntry Deallocate(size_t s) {
char buffer[32];
sprintf(buffer, "deallocate(%zu)", s);
snprintf(buffer, sizeof(buffer), "deallocate(%zu)", s);
return AllocatorLogEntry(buffer);
}
@@ -260,6 +262,7 @@ class TimebombAllocator : public ArduinoJson::Allocator {
size_t countdown_ = 0;
Allocator* upstream_;
};
} // namespace
inline size_t sizeofPoolList(size_t n = ARDUINOJSON_INITIAL_POOL_COUNT) {
return sizeof(ArduinoJson::detail::VariantPool) * n;

View File

@@ -0,0 +1,12 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <string>
// the space before _s is required by GCC 4.8
inline std::string operator"" _s(const char* str, size_t len) {
return std::string(str, len);
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
@@ -51,7 +52,7 @@ TEST_CASE("JsonArray::add(T)") {
array.add(vla);
REQUIRE(std::string("world") == array[0]);
REQUIRE("world"_s == array[0]);
}
#endif
@@ -115,7 +116,7 @@ TEST_CASE("JsonArray::add(T)") {
}
SECTION("should duplicate std::string") {
array.add(std::string("world"));
array.add("world"_s);
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("world")),
@@ -139,7 +140,7 @@ TEST_CASE("JsonArray::add(T)") {
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("{}")));
array.add(serialized("{}"_s));
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("{}")),
@@ -147,7 +148,7 @@ TEST_CASE("JsonArray::add(T)") {
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("\0XX", 3)));
array.add(serialized("\0XX"_s));
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString(" XX")),
@@ -179,3 +180,52 @@ TEST_CASE("JsonArray::add<T>()") {
REQUIRE(doc.as<std::string>() == "[42]");
}
}
TEST_CASE("JsonObject::add(JsonObject) ") {
JsonDocument doc1;
doc1["key1"_s] = "value1"_s;
TimebombAllocator allocator(10);
SpyingAllocator spy(&allocator);
JsonDocument doc2(&spy);
JsonArray array = doc2.to<JsonArray>();
SECTION("success") {
bool result = array.add(doc1.as<JsonObject>());
REQUIRE(result == true);
REQUIRE(doc2.as<std::string>() == "[{\"key1\":\"value1\"}]");
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("key1")),
Allocate(sizeofString("value1")),
});
}
SECTION("partial failure") { // issue #2081
allocator.setCountdown(2);
bool result = array.add(doc1.as<JsonObject>());
REQUIRE(result == false);
REQUIRE(doc2.as<std::string>() == "[]");
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("key1")),
AllocateFail(sizeofString("value1")),
Deallocate(sizeofString("key1")),
});
}
SECTION("complete failure") {
allocator.setCountdown(0);
bool result = array.add(doc1.as<JsonObject>());
REQUIRE(result == false);
REQUIRE(doc2.as<std::string>() == "[]");
REQUIRE(spy.log() == AllocatorLog{
AllocateFail(sizeofPool()),
});
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("copyArray()") {
SECTION("int[] -> JsonArray") {
@@ -18,7 +19,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[1,2,3]") == json);
CHECK("[1,2,3]"_s == json);
}
SECTION("std::string[] -> JsonArray") {
@@ -31,7 +32,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
}
SECTION("const char*[] -> JsonArray") {
@@ -44,7 +45,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
}
SECTION("const char[][] -> JsonArray") {
@@ -57,7 +58,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
}
SECTION("const char[][] -> JsonDocument") {
@@ -69,7 +70,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
}
SECTION("const char[][] -> MemberProxy") {
@@ -81,7 +82,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("{\"data\":[\"a\",\"b\",\"c\"]}") == json);
CHECK("{\"data\":[\"a\",\"b\",\"c\"]}"_s == json);
}
SECTION("int[] -> JsonDocument") {
@@ -93,7 +94,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("[1,2,3]") == json);
CHECK("[1,2,3]"_s == json);
}
SECTION("int[] -> MemberProxy") {
@@ -105,7 +106,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("{\"data\":[1,2,3]}") == json);
CHECK("{\"data\":[1,2,3]}"_s == json);
}
SECTION("int[] -> JsonArray, but not enough memory") {
@@ -127,7 +128,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[[1,2,3],[4,5,6]]") == json);
CHECK("[[1,2,3],[4,5,6]]"_s == json);
}
SECTION("int[][] -> MemberProxy") {
@@ -139,7 +140,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("{\"data\":[[1,2,3],[4,5,6]]}") == json);
CHECK("{\"data\":[[1,2,3],[4,5,6]]}"_s == json);
}
SECTION("int[][] -> JsonDocument") {
@@ -151,7 +152,7 @@ TEST_CASE("copyArray()") {
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("[[1,2,3],[4,5,6]]") == json);
CHECK("[[1,2,3],[4,5,6]]"_s == json);
}
SECTION("int[][] -> JsonArray, but not enough memory") {
@@ -223,9 +224,9 @@ TEST_CASE("copyArray()") {
size_t result = copyArray(array, destination);
CHECK(3 == result);
CHECK(std::string("a12345") == destination[0]);
CHECK(std::string("b123456") == destination[1]);
CHECK(std::string("c123456") == destination[2]); // truncated
CHECK("a12345"_s == destination[0]);
CHECK("b123456"_s == destination[1]);
CHECK("c123456"_s == destination[2]); // truncated
CHECK(std::string("") == destination[3]);
}

View File

@@ -88,6 +88,15 @@ TEST_CASE("JsonArray::remove()") {
JsonArray unboundArray;
unboundArray.remove(unboundArray.begin());
}
SECTION("use JsonVariant as index") {
array.remove(array[3]); // no effect with null variant
array.remove(array[0]); // remove element at index 1
REQUIRE(2 == array.size());
REQUIRE(array[0] == 1);
REQUIRE(array[1] == 3);
}
}
TEST_CASE("Removed elements are recycled") {

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
static void eraseString(std::string& str) {
char* p = const_cast<char*>(str.c_str());
while (*p)
@@ -19,7 +21,7 @@ TEST_CASE("std::string") {
std::string value("hello");
array.add(value);
eraseString(value);
REQUIRE(std::string("hello") == array[0]);
REQUIRE("hello"_s == array[0]);
}
SECTION("operator[]") {
@@ -27,6 +29,6 @@ TEST_CASE("std::string") {
array.add("hello");
array[0] = value;
eraseString(value);
REQUIRE(std::string("world") == array[0]);
REQUIRE("world"_s == array[0]);
}
}

View File

@@ -7,6 +7,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonArray::operator[]") {
SpyingAllocator spy;
@@ -129,7 +130,7 @@ TEST_CASE("JsonArray::operator[]") {
}
SECTION("should duplicate std::string") {
array[0] = std::string("world");
array[0] = "world"_s;
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("world")),
@@ -150,7 +151,7 @@ TEST_CASE("JsonArray::operator[]") {
array.add("hello");
array[0].set(vla);
REQUIRE(std::string("world") == array[0]);
REQUIRE("world"_s == array[0]);
}
SECTION("operator=(VLA)") {
@@ -161,7 +162,16 @@ TEST_CASE("JsonArray::operator[]") {
array.add("hello");
array[0] = vla;
REQUIRE(std::string("world") == array[0]);
REQUIRE("world"_s == array[0]);
}
#endif
SECTION("Use a JsonVariant as index") {
array[0] = 1;
array[1] = 2;
array[2] = 3;
REQUIRE(array[array[1]] == 3);
REQUIRE(array[array[3]] == nullptr);
}
}

View File

@@ -13,8 +13,15 @@ TEST_CASE("JsonArrayConst::operator[]") {
doc.add(2);
doc.add(3);
REQUIRE(1 == arr[0].as<int>());
REQUIRE(2 == arr[1].as<int>());
REQUIRE(3 == arr[2].as<int>());
REQUIRE(0 == arr[3].as<int>());
SECTION("int") {
REQUIRE(1 == arr[0].as<int>());
REQUIRE(2 == arr[1].as<int>());
REQUIRE(3 == arr[2].as<int>());
REQUIRE(0 == arr[3].as<int>());
}
SECTION("JsonVariant") {
REQUIRE(2 == arr[arr[0]].as<int>());
REQUIRE(0 == arr[arr[3]].as<int>());
}
}

View File

@@ -8,6 +8,7 @@
#include <string>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
@@ -15,7 +16,7 @@ using ArduinoJson::detail::sizeofObject;
TEST_CASE("deserializeJson(JsonDocument&)") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc.add(std::string("hello"));
doc.add("hello"_s);
spy.clearLog();
auto err = deserializeJson(doc, "[42]");
@@ -34,7 +35,7 @@ TEST_CASE("deserializeJson(JsonVariant)") {
SECTION("variant is bound") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc.add(std::string("hello"));
doc.add("hello"_s);
spy.clearLog();
JsonVariant variant = doc[0];
@@ -60,7 +61,7 @@ TEST_CASE("deserializeJson(JsonVariant)") {
TEST_CASE("deserializeJson(ElementProxy)") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc.add(std::string("hello"));
doc.add("hello"_s);
spy.clearLog();
SECTION("element already exists") {
@@ -85,7 +86,7 @@ TEST_CASE("deserializeJson(ElementProxy)") {
TEST_CASE("deserializeJson(MemberProxy)") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc[std::string("hello")] = std::string("world");
doc["hello"_s] = "world"_s;
spy.clearLog();
SECTION("member already exists") {

View File

@@ -10,6 +10,7 @@
#include <string>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
@@ -732,7 +733,7 @@ TEST_CASE("Overloads") {
}
SECTION("const std::string&, Filter") {
deserializeJson(doc, std::string("{}"), Filter(filter));
deserializeJson(doc, "{}"_s, Filter(filter));
}
SECTION("std::istream&, Filter") {
@@ -760,7 +761,7 @@ TEST_CASE("Overloads") {
}
SECTION("const std::string&, Filter, NestingLimit") {
deserializeJson(doc, std::string("{}"), Filter(filter), NestingLimit(5));
deserializeJson(doc, "{}"_s, Filter(filter), NestingLimit(5));
}
SECTION("std::istream&, Filter, NestingLimit") {
@@ -788,7 +789,7 @@ TEST_CASE("Overloads") {
}
SECTION("const std::string&, NestingLimit, Filter") {
deserializeJson(doc, std::string("{}"), NestingLimit(5), Filter(filter));
deserializeJson(doc, "{}"_s, NestingLimit(5), Filter(filter));
}
SECTION("std::istream&, NestingLimit, Filter") {

View File

@@ -9,6 +9,7 @@
#include "Allocators.hpp"
#include "CustomReader.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofObject;
@@ -69,7 +70,7 @@ TEST_CASE("deserializeJson(const std::string&)") {
}
SECTION("should accept temporary string") {
DeserializationError err = deserializeJson(doc, std::string("[42]"));
DeserializationError err = deserializeJson(doc, "[42]"_s);
REQUIRE(err == DeserializationError::Ok);
}
@@ -82,7 +83,7 @@ TEST_CASE("deserializeJson(const std::string&)") {
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
REQUIRE("hello"_s == array[0]);
}
}
@@ -108,7 +109,7 @@ TEST_CASE("deserializeJson(std::istream&)") {
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == obj.size());
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
SECTION("Should not read after the closing brace of an empty object") {

View File

@@ -7,6 +7,8 @@
#include <sstream>
#include "Literals.hpp"
#define SHOULD_WORK(expression) REQUIRE(DeserializationError::Ok == expression);
#define SHOULD_FAIL(expression) \
REQUIRE(DeserializationError::TooDeep == expression);
@@ -63,23 +65,23 @@ TEST_CASE("JsonDeserializer nesting") {
SECTION("Input = std::string") {
SECTION("limit = 0") {
DeserializationOption::NestingLimit nesting(0);
SHOULD_WORK(deserializeJson(doc, std::string("\"toto\""), nesting));
SHOULD_WORK(deserializeJson(doc, std::string("123"), nesting));
SHOULD_WORK(deserializeJson(doc, std::string("true"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[]"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[\"toto\"]"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{\"toto\":1}"), nesting));
SHOULD_WORK(deserializeJson(doc, "\"toto\""_s, nesting));
SHOULD_WORK(deserializeJson(doc, "123"_s, nesting));
SHOULD_WORK(deserializeJson(doc, "true"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "[]"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "{}"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "[\"toto\"]"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":1}"_s, nesting));
}
SECTION("limit = 1") {
DeserializationOption::NestingLimit nesting(1);
SHOULD_WORK(deserializeJson(doc, std::string("[\"toto\"]"), nesting));
SHOULD_WORK(deserializeJson(doc, std::string("{\"toto\":1}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{\"toto\":{}}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{\"toto\":[]}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[[\"toto\"]]"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[{\"toto\":1}]"), nesting));
SHOULD_WORK(deserializeJson(doc, "[\"toto\"]"_s, nesting));
SHOULD_WORK(deserializeJson(doc, "{\"toto\":1}"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":{}}"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":[]}"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "[[\"toto\"]]"_s, nesting));
SHOULD_FAIL(deserializeJson(doc, "[{\"toto\":1}]"_s, nesting));
}
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
typedef ArduinoJson::detail::ElementProxy<JsonDocument&> ElementProxy;
TEST_CASE("ElementProxy::add()") {
@@ -121,7 +123,7 @@ TEST_CASE("ElementProxy::remove()") {
ep["a"] = 1;
ep["b"] = 2;
ep.remove(std::string("b"));
ep.remove("b"_s);
REQUIRE(ep.as<std::string>() == "{\"a\":1}");
}

View File

@@ -9,6 +9,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
@@ -106,8 +107,8 @@ TEST_CASE("MemberProxy::containsKey()") {
SECTION("containsKey(std::string)") {
mp["key"] = "value";
REQUIRE(mp.containsKey(std::string("key")) == true);
REQUIRE(mp.containsKey(std::string("key")) == true);
REQUIRE(mp.containsKey("key"_s) == true);
REQUIRE(mp.containsKey("key"_s) == true);
}
}
@@ -117,8 +118,8 @@ TEST_CASE("MemberProxy::operator|()") {
SECTION("const char*") {
doc["a"] = "hello";
REQUIRE((doc["a"] | "world") == std::string("hello"));
REQUIRE((doc["b"] | "world") == std::string("world"));
REQUIRE((doc["a"] | "world") == "hello"_s);
REQUIRE((doc["b"] | "world") == "world"_s);
}
SECTION("Issue #1411") {
@@ -128,7 +129,7 @@ TEST_CASE("MemberProxy::operator|()") {
// to trigger the bug
const char* sensor = doc["sensor"] | test; // "gps"
REQUIRE(sensor == std::string("gps"));
REQUIRE(sensor == "gps"_s);
}
SECTION("Issue #1415") {
@@ -170,7 +171,7 @@ TEST_CASE("MemberProxy::remove()") {
mp["a"] = 1;
mp["b"] = 2;
mp.remove(std::string("b"));
mp.remove("b"_s);
REQUIRE(mp.as<std::string>() == "{\"a\":1}");
}
@@ -286,8 +287,8 @@ TEST_CASE("Deduplicate keys") {
JsonDocument doc(&spy);
SECTION("std::string") {
doc[0][std::string("example")] = 1;
doc[1][std::string("example")] = 2;
doc[0]["example"_s] = 1;
doc[1]["example"_s] = 2;
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
@@ -351,7 +352,7 @@ TEST_CASE("MemberProxy under memory constraints") {
SECTION("key allocation fails") {
killswitch.on();
doc[std::string("hello")] = "world";
doc["hello"_s] = "world";
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.size() == 0);

View File

@@ -9,6 +9,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
@@ -35,8 +36,8 @@ TEST_CASE("JsonDocument::add(T)") {
}
SECTION("std::string") {
doc.add(std::string("example"));
doc.add(std::string("example"));
doc.add("example"_s);
doc.add("example"_s);
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(spy.log() == AllocatorLog{
@@ -90,15 +91,57 @@ TEST_CASE("JsonDocument::add<T>()") {
REQUIRE(doc.as<std::string>() == "[[1,2]]");
}
SECTION("JsonObject") {
JsonObject object = doc.add<JsonObject>();
object["hello"] = "world";
REQUIRE(doc.as<std::string>() == "[{\"hello\":\"world\"}]");
}
SECTION("JsonVariant") {
JsonVariant variant = doc.add<JsonVariant>();
variant.set(42);
REQUIRE(doc.as<std::string>() == "[42]");
}
}
TEST_CASE("JsonObject::add(JsonObject) ") {
JsonDocument doc1;
doc1["hello"_s] = "world"_s;
TimebombAllocator allocator(10);
SpyingAllocator spy(&allocator);
JsonDocument doc2(&spy);
SECTION("success") {
bool result = doc2.add(doc1.as<JsonObject>());
REQUIRE(result == true);
REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("hello")),
Allocate(sizeofString("world")),
});
}
SECTION("partial failure") { // issue #2081
allocator.setCountdown(2);
bool result = doc2.add(doc1.as<JsonObject>());
REQUIRE(result == false);
REQUIRE(doc2.as<std::string>() == "[]");
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("hello")),
AllocateFail(sizeofString("world")),
Deallocate(sizeofString("hello")),
});
}
SECTION("complete failure") {
allocator.setCountdown(0);
bool result = doc2.add(doc1.as<JsonObject>());
REQUIRE(result == false);
REQUIRE(doc2.as<std::string>() == "[]");
REQUIRE(spy.log() == AllocatorLog{
AllocateFail(sizeofPool()),
});
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonDocument assignment") {
SpyingAllocator spyingAllocator;
@@ -62,7 +63,7 @@ TEST_CASE("JsonDocument assignment") {
SECTION("Move assign") {
{
JsonDocument doc1(&spyingAllocator);
doc1[std::string("hello")] = std::string("world");
doc1["hello"_s] = "world"_s;
JsonDocument doc2(&spyingAllocator);
doc2 = std::move(doc1);

View File

@@ -9,6 +9,7 @@
#include <string>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonDocument::clear()") {
SpyingAllocator spy;
@@ -22,7 +23,7 @@ TEST_CASE("JsonDocument::clear()") {
}
SECTION("releases resources") {
doc[std::string("hello")] = std::string("world");
doc["hello"_s] = "world"_s;
spy.clearLog();
doc.clear();

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::addPadding;
@@ -20,7 +21,7 @@ TEST_CASE("JsonDocument constructor") {
SECTION("JsonDocument(const JsonDocument&)") {
{
JsonDocument doc1(&spyingAllocator);
doc1.set(std::string("The size of this string is 32!!"));
doc1.set("The size of this string is 32!!"_s);
JsonDocument doc2(doc1);
@@ -38,7 +39,7 @@ TEST_CASE("JsonDocument constructor") {
SECTION("JsonDocument(JsonDocument&&)") {
{
JsonDocument doc1(&spyingAllocator);
doc1.set(std::string("The size of this string is 32!!"));
doc1.set("The size of this string is 32!!"_s);
JsonDocument doc2(std::move(doc1));
@@ -117,4 +118,31 @@ TEST_CASE("JsonDocument constructor") {
REQUIRE(doc2.as<std::string>() == "hello");
}
SECTION("JsonDocument(JsonVariantConst)") {
JsonDocument doc1;
deserializeJson(doc1, "\"hello\"");
JsonDocument doc2(doc1.as<JsonVariantConst>());
REQUIRE(doc2.as<std::string>() == "hello");
}
SECTION("JsonDocument(ElementProxy)") {
JsonDocument doc1;
deserializeJson(doc1, "[\"hello\",\"world\"]");
JsonDocument doc2(doc1[1]);
REQUIRE(doc2.as<std::string>() == "world");
}
SECTION("JsonDocument(MemberProxy)") {
JsonDocument doc1;
deserializeJson(doc1, "{\"hello\":\"world\"}");
JsonDocument doc2(doc1["hello"]);
REQUIRE(doc2.as<std::string>() == "world");
}
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonDocument::containsKey()") {
JsonDocument doc;
@@ -23,7 +25,7 @@ TEST_CASE("JsonDocument::containsKey()") {
SECTION("returns true when key is a std::string") {
doc["hello"] = "world";
REQUIRE(doc.containsKey(std::string("hello")) == true);
REQUIRE(doc.containsKey("hello"_s) == true);
}
SECTION("returns false on object") {
@@ -41,4 +43,12 @@ TEST_CASE("JsonDocument::containsKey()") {
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);
}
}

View File

@@ -2,6 +2,8 @@
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("Issue #1120") {
JsonDocument doc;
constexpr char str[] =
@@ -10,12 +12,12 @@ TEST_CASE("Issue #1120") {
SECTION("MemberProxy<std::string>::isNull()") {
SECTION("returns false") {
auto value = doc[std::string("contents")];
auto value = doc["contents"_s];
CHECK(value.isNull() == false);
}
SECTION("returns true") {
auto value = doc[std::string("zontents")];
auto value = doc["zontents"_s];
CHECK(value.isNull() == true);
}
}
@@ -46,12 +48,12 @@ TEST_CASE("Issue #1120") {
SECTION("MemberProxy<ElementProxy<MemberProxy>, std::string>::isNull()") {
SECTION("returns false") {
auto value = doc["contents"][1][std::string("module")];
auto value = doc["contents"][1]["module"_s];
CHECK(value.isNull() == false);
}
SECTION("returns true") {
auto value = doc["contents"][1][std::string("zodule")];
auto value = doc["contents"][1]["zodule"_s];
CHECK(value.isNull() == true);
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonDocument::overflowed()") {
TimebombAllocator timebomb(10);
@@ -30,13 +31,13 @@ TEST_CASE("JsonDocument::overflowed()") {
SECTION("returns true after a failed string copy") {
timebomb.setCountdown(0);
doc.add(std::string("example"));
doc.add("example"_s);
CHECK(doc.overflowed() == true);
}
SECTION("returns false after a successful string copy") {
timebomb.setCountdown(3);
doc.add(std::string("example"));
doc.add("example"_s);
CHECK(doc.overflowed() == false);
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonDocument::remove()") {
JsonDocument doc;
@@ -31,7 +33,7 @@ TEST_CASE("JsonDocument::remove()") {
doc["a"] = 1;
doc["b"] = 2;
doc.remove(std::string("b"));
doc.remove("b"_s);
REQUIRE(doc.as<std::string>() == "{\"a\":1}");
}
@@ -49,4 +51,25 @@ TEST_CASE("JsonDocument::remove()") {
REQUIRE(doc.as<std::string>() == "{\"a\":1}");
}
#endif
SECTION("remove(JsonVariant) from object") {
doc["a"] = 1;
doc["b"] = 2;
doc["c"] = "b";
doc.remove(doc["c"]);
REQUIRE(doc.as<std::string>() == "{\"a\":1,\"c\":\"b\"}");
}
SECTION("remove(JsonVariant) from array") {
doc[0] = 3;
doc[1] = 2;
doc[2] = 1;
doc.remove(doc[2]);
doc.remove(doc[3]); // noop
REQUIRE(doc.as<std::string>() == "[3,1]");
}
}

View File

@@ -9,6 +9,7 @@
#include <string>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
@@ -78,7 +79,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
}
SECTION("owned string") {
doc.set(std::string("abcdefg"));
doc.set("abcdefg"_s);
REQUIRE(doc.as<std::string>() == "abcdefg");
doc.shrinkToFit();
@@ -114,7 +115,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
}
SECTION("owned key") {
doc[std::string("abcdefg")] = 42;
doc["abcdefg"_s] = 42;
doc.shrinkToFit();
@@ -141,7 +142,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
}
SECTION("owned string in array") {
doc.add(std::string("abcdefg"));
doc.add("abcdefg"_s);
doc.shrinkToFit();
@@ -168,7 +169,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
}
SECTION("owned string in object") {
doc["key"] = std::string("abcdefg");
doc["key"] = "abcdefg"_s;
doc.shrinkToFit();

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonDocument::operator[]") {
JsonDocument doc;
const JsonDocument& cdoc = doc;
@@ -18,21 +20,35 @@ TEST_CASE("JsonDocument::operator[]") {
}
SECTION("std::string") {
REQUIRE(doc[std::string("hello")] == "world");
REQUIRE(cdoc[std::string("hello")] == "world");
REQUIRE(doc["hello"_s] == "world");
REQUIRE(cdoc["hello"_s] == "world");
}
SECTION("JsonVariant") {
doc["key"] = "hello";
REQUIRE(doc[doc["key"]] == "world");
REQUIRE(cdoc[cdoc["key"]] == "world");
}
SECTION("supports operator|") {
REQUIRE((doc["hello"] | "nope") == std::string("world"));
REQUIRE((doc["world"] | "nope") == std::string("nope"));
REQUIRE((doc["hello"] | "nope") == "world"_s);
REQUIRE((doc["world"] | "nope") == "nope"_s);
}
}
SECTION("array") {
deserializeJson(doc, "[\"hello\",\"world\"]");
REQUIRE(doc[1] == "world");
REQUIRE(cdoc[1] == "world");
SECTION("int") {
REQUIRE(doc[1] == "world");
REQUIRE(cdoc[1] == "world");
}
SECTION("JsonVariant") {
doc[2] = 1;
REQUIRE(doc[doc[2]] == "world");
REQUIRE(cdoc[doc[2]] == "world");
}
}
}

View File

@@ -6,12 +6,12 @@ add_executable(JsonObjectTests
clear.cpp
compare.cpp
containsKey.cpp
copy.cpp
equals.cpp
isNull.cpp
iterator.cpp
nesting.cpp
remove.cpp
set.cpp
size.cpp
std_string.cpp
subscript.cpp

View File

@@ -30,4 +30,10 @@ TEST_CASE("JsonObject::containsKey()") {
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"]));
}
}

View File

@@ -80,4 +80,10 @@ TEST_CASE("JsonObject::remove()") {
JsonObject unboundObject;
unboundObject.remove(unboundObject.begin());
}
SECTION("remove(JsonVariant)") {
obj["key"] = "b";
obj.remove(obj["key"]);
REQUIRE("{\"a\":0,\"c\":2,\"key\":\"b\"}" == doc.as<std::string>());
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonObject::set()") {
SpyingAllocator spy;
@@ -22,20 +23,20 @@ TEST_CASE("JsonObject::set()") {
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(obj2["hello"] == "world"_s);
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
});
}
SECTION("copy local string value") {
obj1["hello"] = std::string("world");
obj1["hello"] = "world"_s;
spy.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(obj2["hello"] == "world"_s);
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("world")),
@@ -43,13 +44,13 @@ TEST_CASE("JsonObject::set()") {
}
SECTION("copy local key") {
obj1[std::string("hello")] = "world";
obj1["hello"_s] = "world";
spy.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(obj2["hello"] == "world"_s);
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofString("hello")),
Allocate(sizeofPool()),
@@ -63,7 +64,7 @@ TEST_CASE("JsonObject::set()") {
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(obj2["hello"] == "world"_s);
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofString("hello")),
Allocate(sizeofPool()),
@@ -78,7 +79,7 @@ TEST_CASE("JsonObject::set()") {
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(obj2["hello"] == "world"_s);
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofString("hello")),
Allocate(sizeofPool()),
@@ -91,7 +92,7 @@ TEST_CASE("JsonObject::set()") {
obj2.set(static_cast<JsonObjectConst>(obj1));
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(obj2["hello"] == "world"_s);
}
SECTION("copy fails in the middle of an object") {
@@ -99,8 +100,8 @@ TEST_CASE("JsonObject::set()") {
JsonDocument doc3(&timebomb);
JsonObject obj3 = doc3.to<JsonObject>();
obj1[std::string("a")] = 1;
obj1[std::string("b")] = 2;
obj1["a"_s] = 1;
obj1["b"_s] = 2;
bool success = obj3.set(obj1);
@@ -113,12 +114,12 @@ TEST_CASE("JsonObject::set()") {
JsonDocument doc3(&timebomb);
JsonObject obj3 = doc3.to<JsonObject>();
obj1["hello"][0] = std::string("world");
obj1["hello"][0] = "world"_s;
bool success = obj3.set(obj1);
REQUIRE(success == false);
REQUIRE(doc3.as<std::string>() == "{\"hello\":[null]}");
REQUIRE(doc3.as<std::string>() == "{\"hello\":[]}");
}
SECTION("destination is null") {

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
static void eraseString(std::string& str) {
char* p = const_cast<char*>(str.c_str());
while (*p)
@@ -20,7 +22,7 @@ TEST_CASE("std::string") {
deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();
REQUIRE(std::string("value") == obj[std::string("key")]);
REQUIRE("value"_s == obj["key"_s]);
}
SECTION("operator[] const") {
@@ -29,21 +31,21 @@ TEST_CASE("std::string") {
deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();
REQUIRE(std::string("value") == obj[std::string("key")]);
REQUIRE("value"_s == obj["key"_s]);
}
SECTION("containsKey()") {
char json[] = "{\"key\":\"value\"}";
deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();
REQUIRE(true == obj.containsKey(std::string("key")));
REQUIRE(true == obj.containsKey("key"_s));
}
SECTION("remove()") {
JsonObject obj = doc.to<JsonObject>();
obj["key"] = "value";
obj.remove(std::string("key"));
obj.remove("key"_s);
REQUIRE(0 == obj.size());
}
@@ -53,7 +55,7 @@ TEST_CASE("std::string") {
JsonObject obj = doc.to<JsonObject>();
obj[key] = "world";
eraseString(key);
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
SECTION("operator[], set value") {
@@ -61,6 +63,6 @@ TEST_CASE("std::string") {
JsonObject obj = doc.to<JsonObject>();
obj["hello"] = value;
eraseString(value);
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonObject::operator[]") {
SpyingAllocator spy;
@@ -50,7 +51,7 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(true == obj["hello"].is<const char*>());
REQUIRE(false == obj["hello"].is<long>());
REQUIRE(std::string("h3110") == obj["hello"].as<const char*>());
REQUIRE("h3110"_s == obj["hello"].as<const char*>());
}
SECTION("array") {
@@ -132,7 +133,7 @@ TEST_CASE("JsonObject::operator[]") {
}
SECTION("should duplicate std::string value") {
obj["hello"] = std::string("world");
obj["hello"] = "world"_s;
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("world")),
@@ -140,7 +141,7 @@ TEST_CASE("JsonObject::operator[]") {
}
SECTION("should duplicate std::string key") {
obj[std::string("hello")] = "world";
obj["hello"_s] = "world";
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofString("hello")),
Allocate(sizeofPool()),
@@ -148,7 +149,7 @@ TEST_CASE("JsonObject::operator[]") {
}
SECTION("should duplicate std::string key&value") {
obj[std::string("hello")] = std::string("world");
obj["hello"_s] = "world"_s;
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofString("hello")),
Allocate(sizeofPool()),
@@ -197,7 +198,7 @@ TEST_CASE("JsonObject::operator[]") {
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
SECTION("obj[str] = VLA") { // issue #416
@@ -207,7 +208,7 @@ TEST_CASE("JsonObject::operator[]") {
obj["hello"] = vla;
REQUIRE(std::string("world") == obj["hello"].as<const char*>());
REQUIRE("world"_s == obj["hello"].as<const char*>());
}
SECTION("obj.set(VLA, str)") {
@@ -217,7 +218,7 @@ TEST_CASE("JsonObject::operator[]") {
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
SECTION("obj.set(str, VLA)") {
@@ -227,7 +228,7 @@ TEST_CASE("JsonObject::operator[]") {
obj["hello"].set(vla);
REQUIRE(std::string("world") == obj["hello"].as<const char*>());
REQUIRE("world"_s == obj["hello"].as<const char*>());
}
SECTION("obj[VLA]") {
@@ -238,7 +239,7 @@ TEST_CASE("JsonObject::operator[]") {
deserializeJson(doc, "{\"hello\":\"world\"}");
obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[vla]);
REQUIRE("world"_s == obj[vla]);
}
#endif
@@ -249,4 +250,12 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(true == obj["hello"]["world"].is<int>());
REQUIRE(false == obj["hello"]["world"].is<bool>());
}
SECTION("JsonVariant") {
obj["hello"] = "world";
doc["key"] = "hello";
REQUIRE(obj[obj["key"]] == "world");
REQUIRE(obj[obj["foo"]] == nullptr);
}
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonObjectConst::containsKey()") {
JsonDocument doc;
doc["hello"] = 42;
@@ -16,8 +18,8 @@ TEST_CASE("JsonObjectConst::containsKey()") {
}
SECTION("supports std::string") {
REQUIRE(false == obj.containsKey(std::string("world")));
REQUIRE(true == obj.containsKey(std::string("hello")));
REQUIRE(false == obj.containsKey("world"_s));
REQUIRE(true == obj.containsKey("hello"_s));
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
@@ -29,4 +31,10 @@ TEST_CASE("JsonObjectConst::containsKey()") {
REQUIRE(true == obj.containsKey(vla));
}
#endif
SECTION("supports JsonVariant") {
doc["key"] = "hello";
REQUIRE(true == obj.containsKey(obj["key"]));
REQUIRE(false == obj.containsKey(obj["hello"]));
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonObjectConst::operator[]") {
JsonDocument doc;
@@ -17,7 +18,7 @@ TEST_CASE("JsonObjectConst::operator[]") {
}
SECTION("supports std::string") {
REQUIRE(obj[std::string("hello")] == "world"); // issue #2019
REQUIRE(obj["hello"_s] == "world"); // issue #2019
}
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
@@ -27,7 +28,13 @@ TEST_CASE("JsonObjectConst::operator[]") {
char vla[i];
strcpy(vla, "hello");
REQUIRE(std::string("world") == obj[vla]);
REQUIRE("world"_s == obj[vla]);
}
#endif
SECTION("supports JsonVariant") {
doc["key"] = "hello";
REQUIRE(obj[obj["key"]] == "world");
REQUIRE(obj[obj["foo"]] == nullptr);
}
}

View File

@@ -6,6 +6,8 @@
#include <catch.hpp>
#include <limits>
#include "Literals.hpp"
template <typename T>
void check(T value, const std::string& expected) {
JsonDocument doc;
@@ -30,42 +32,42 @@ TEST_CASE("serializeJson(JsonVariant)") {
}
SECTION("string") {
check(std::string("hello"), "\"hello\"");
check("hello"_s, "\"hello\"");
SECTION("Escape quotation mark") {
check(std::string("hello \"world\""), "\"hello \\\"world\\\"\"");
check("hello \"world\""_s, "\"hello \\\"world\\\"\"");
}
SECTION("Escape reverse solidus") {
check(std::string("hello\\world"), "\"hello\\\\world\"");
check("hello\\world"_s, "\"hello\\\\world\"");
}
SECTION("Don't escape solidus") {
check(std::string("fifty/fifty"), "\"fifty/fifty\"");
check("fifty/fifty"_s, "\"fifty/fifty\"");
}
SECTION("Escape backspace") {
check(std::string("hello\bworld"), "\"hello\\bworld\"");
check("hello\bworld"_s, "\"hello\\bworld\"");
}
SECTION("Escape formfeed") {
check(std::string("hello\fworld"), "\"hello\\fworld\"");
check("hello\fworld"_s, "\"hello\\fworld\"");
}
SECTION("Escape linefeed") {
check(std::string("hello\nworld"), "\"hello\\nworld\"");
check("hello\nworld"_s, "\"hello\\nworld\"");
}
SECTION("Escape carriage return") {
check(std::string("hello\rworld"), "\"hello\\rworld\"");
check("hello\rworld"_s, "\"hello\\rworld\"");
}
SECTION("Escape tab") {
check(std::string("hello\tworld"), "\"hello\\tworld\"");
check("hello\tworld"_s, "\"hello\\tworld\"");
}
SECTION("NUL char") {
check(std::string("hello\0world", 11), "\"hello\\u0000world\"");
check("hello\0world"_s, "\"hello\\u0000world\"");
}
}
@@ -74,7 +76,7 @@ TEST_CASE("serializeJson(JsonVariant)") {
}
SECTION("SerializedValue<std::string>") {
check(serialized(std::string("[1,2]")), "[1,2]");
check(serialized("[1,2]"_s), "[1,2]");
}
SECTION("Double") {

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("serialize JsonArray to std::string") {
JsonDocument doc;
JsonArray array = doc.to<JsonArray>();
@@ -48,7 +50,7 @@ TEST_CASE("serialize JsonObject to std::string") {
TEST_CASE("serialize an std::string containing a NUL") {
JsonDocument doc;
doc.set(std::string("hello\0world", 11));
doc.set("hello\0world"_s);
std::string json = "erase me";
serializeJson(doc, json);

View File

@@ -6,6 +6,9 @@
#include <stdint.h>
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonVariant::add(T)") {
JsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
@@ -23,7 +26,7 @@ TEST_CASE("JsonVariant::add(T)") {
}
SECTION("add std::string to new variant") {
var.add(std::string("hello"));
var.add("hello"_s);
REQUIRE(var.as<std::string>() == "[\"hello\"]");
}
@@ -56,15 +59,58 @@ TEST_CASE("JsonVariant::add<T>()") {
REQUIRE(doc.as<std::string>() == "[[1,2]]");
}
SECTION("JsonObject") {
JsonObject object = var.add<JsonObject>();
object["hello"] = "world";
REQUIRE(doc.as<std::string>() == "[{\"hello\":\"world\"}]");
}
SECTION("JsonVariant") {
JsonVariant variant = var.add<JsonVariant>();
variant.set(42);
REQUIRE(doc.as<std::string>() == "[42]");
}
}
TEST_CASE("JsonObject::add(JsonObject) ") {
JsonDocument doc1;
doc1["hello"_s] = "world"_s;
TimebombAllocator allocator(10);
SpyingAllocator spy(&allocator);
JsonDocument doc2(&spy);
JsonVariant variant = doc2.to<JsonVariant>();
SECTION("success") {
bool result = variant.add(doc1.as<JsonObject>());
REQUIRE(result == true);
REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("hello")),
Allocate(sizeofString("world")),
});
}
SECTION("partial failure") { // issue #2081
allocator.setCountdown(2);
bool result = variant.add(doc1.as<JsonObject>());
REQUIRE(result == false);
REQUIRE(doc2.as<std::string>() == "[]");
REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()),
Allocate(sizeofString("hello")),
AllocateFail(sizeofString("world")),
Deallocate(sizeofString("hello")),
});
}
SECTION("complete failure") {
allocator.setCountdown(0);
bool result = variant.add(doc1.as<JsonObject>());
REQUIRE(result == false);
REQUIRE(doc2.as<std::string>() == "[]");
REQUIRE(spy.log() == AllocatorLog{
AllocateFail(sizeofPool()),
});
}
}

View File

@@ -6,6 +6,8 @@
#include <stdint.h>
#include <catch.hpp>
#include "Literals.hpp"
namespace my {
using ArduinoJson::detail::isinf;
} // namespace my
@@ -25,6 +27,8 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(0 == variant.as<const char*>());
REQUIRE("null" == variant.as<std::string>());
REQUIRE(variant.as<JsonString>().isNull());
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("set(4.2)") {
@@ -36,6 +40,8 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<long>() == 4L);
REQUIRE(variant.as<unsigned>() == 4U);
REQUIRE(variant.as<JsonString>().isNull());
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("set(0.0)") {
@@ -44,6 +50,8 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<bool>() == false);
REQUIRE(variant.as<long>() == 0L);
REQUIRE(variant.as<JsonString>().isNull());
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("set(false)") {
@@ -54,6 +62,8 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<long>() == 0L);
REQUIRE(variant.as<std::string>() == "false");
REQUIRE(variant.as<JsonString>().isNull());
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("set(true)") {
@@ -64,6 +74,8 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<long>() == 1L);
REQUIRE(variant.as<std::string>() == "true");
REQUIRE(variant.as<JsonString>().isNull());
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("set(42)") {
@@ -75,6 +87,8 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<unsigned int>() == 42U); // issue #1601
REQUIRE(variant.as<std::string>() == "42");
REQUIRE(variant.as<JsonString>().isNull());
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("set(42L)") {
@@ -144,20 +158,20 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<bool>() == true);
REQUIRE(variant.as<long>() == 0L);
REQUIRE(variant.as<const char*>() == std::string("hello"));
REQUIRE(variant.as<const char*>() == std::string("hello"));
REQUIRE(variant.as<std::string>() == std::string("hello"));
REQUIRE(variant.as<const char*>() == "hello"_s);
REQUIRE(variant.as<const char*>() == "hello"_s);
REQUIRE(variant.as<std::string>() == "hello"_s);
REQUIRE(variant.as<JsonString>() == "hello");
}
SECTION("set(std::string(\"4.2\"))") {
variant.set(std::string("4.2"));
variant.set("4.2"_s);
REQUIRE(variant.as<bool>() == true);
REQUIRE(variant.as<long>() == 4L);
REQUIRE(variant.as<double>() == 4.2);
REQUIRE(variant.as<const char*>() == std::string("4.2"));
REQUIRE(variant.as<std::string>() == std::string("4.2"));
REQUIRE(variant.as<const char*>() == "4.2"_s);
REQUIRE(variant.as<std::string>() == "4.2"_s);
REQUIRE(variant.as<JsonString>() == "4.2");
REQUIRE(variant.as<JsonString>().isLinked() == false);
}
@@ -199,6 +213,13 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<JsonString>().isNull());
}
SECTION("set(serialized(\"hello\"))") {
variant.set(serialized("hello"));
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
}
SECTION("to<JsonObject>()") {
JsonObject obj = variant.to<JsonObject>();
obj["key"] = "value";
@@ -208,13 +229,13 @@ TEST_CASE("JsonVariant::as()") {
}
SECTION("as<std::string>()") {
REQUIRE(variant.as<std::string>() == std::string("{\"key\":\"value\"}"));
REQUIRE(variant.as<std::string>() == "{\"key\":\"value\"}"_s);
}
SECTION("ObjectAsJsonObject") {
JsonObject o = variant.as<JsonObject>();
REQUIRE(o.size() == 1);
REQUIRE(o["key"] == std::string("value"));
REQUIRE(o["key"] == "value"_s);
}
}
@@ -228,7 +249,7 @@ TEST_CASE("JsonVariant::as()") {
}
SECTION("as<std::string>()") {
REQUIRE(variant.as<std::string>() == std::string("[4,2]"));
REQUIRE(variant.as<std::string>() == "[4,2]"_s);
}
SECTION("as<JsonArray>()") {
@@ -245,7 +266,7 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<long long>() == -9223372036854775807 - 1);
}
SECTION("Biggerst int64 positive") {
SECTION("Biggest int64 positive") {
variant.set("9223372036854775807");
REQUIRE(variant.as<long long>() == 9223372036854775807);
}

View File

@@ -7,6 +7,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonVariant::clear()") {
SpyingAllocator spy;
@@ -28,7 +29,7 @@ TEST_CASE("JsonVariant::clear()") {
}
SECTION("releases owned string") {
var.set(std::string("hello"));
var.set("hello"_s);
var.clear();
REQUIRE(spy.log() == AllocatorLog{

View File

@@ -113,6 +113,42 @@ TEST_CASE("Compare JsonVariant with JsonVariant") {
CHECK_FALSE(a == b);
}
SECTION("MsgPackBinary('abc') vs MsgPackBinary('abc')") {
a.set(MsgPackBinary("abc", 4));
b.set(MsgPackBinary("abc", 4));
CHECK(a == b);
CHECK(a <= b);
CHECK(a >= b);
CHECK_FALSE(a != b);
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
SECTION("MsgPackBinary('abc') vs MsgPackBinary('bcd')") {
a.set(MsgPackBinary("abc", 4));
b.set(MsgPackBinary("bcd", 4));
CHECK(a != b);
CHECK(a < b);
CHECK(a <= b);
CHECK_FALSE(a == b);
CHECK_FALSE(a > b);
CHECK_FALSE(a >= b);
}
SECTION("MsgPackBinary('bcd') vs MsgPackBinary('abc')") {
a.set(MsgPackBinary("bcd", 4));
b.set(MsgPackBinary("abc", 4));
CHECK(a != b);
CHECK(a > b);
CHECK(a >= b);
CHECK_FALSE(a < b);
CHECK_FALSE(a <= b);
CHECK_FALSE(a == b);
}
SECTION("false vs true") {
a.set(false);
b.set(true);

View File

@@ -6,6 +6,8 @@
#include <stdint.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonVariant::containsKey()") {
JsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
@@ -20,7 +22,15 @@ TEST_CASE("JsonVariant::containsKey()") {
SECTION("containsKey(std::string)") {
var["hello"] = "world";
REQUIRE(var.containsKey(std::string("hello")) == true);
REQUIRE(var.containsKey(std::string("world")) == false);
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);
}
}

View File

@@ -140,15 +140,3 @@ TEST_CASE("Custom converter with specialization") {
REQUIRE(doc["value"]["imag"] == 3);
}
}
TEST_CASE("ConverterNeedsWriteableRef") {
using namespace ArduinoJson::detail;
CHECK(ConverterNeedsWriteableRef<int>::value == false);
CHECK(ConverterNeedsWriteableRef<float>::value == false);
CHECK(ConverterNeedsWriteableRef<JsonVariant>::value == true);
CHECK(ConverterNeedsWriteableRef<JsonVariantConst>::value == false);
CHECK(ConverterNeedsWriteableRef<JsonObject>::value == true);
CHECK(ConverterNeedsWriteableRef<JsonObjectConst>::value == false);
CHECK(ConverterNeedsWriteableRef<JsonArray>::value == true);
CHECK(ConverterNeedsWriteableRef<JsonArrayConst>::value == false);
}

View File

@@ -6,6 +6,8 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
TEST_CASE("JsonVariant::set(JsonVariant)") {
KillswitchAllocator killswitch;
SpyingAllocator spyingAllocator(&killswitch);
@@ -72,7 +74,7 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
}
SECTION("stores std::string by copy") {
var1.set(std::string("hello!!"));
var1.set("hello!!"_s);
spyingAllocator.clearLog();
var2.set(var1);
@@ -106,7 +108,7 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
}
SECTION("stores Serialized<std::string> by copy") {
var1.set(serialized(std::string("hello!!")));
var1.set(serialized("hello!!"_s));
spyingAllocator.clearLog();
var2.set(var1);
@@ -117,7 +119,7 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
}
SECTION("fails gracefully if raw string allocation fails") {
var1.set(serialized(std::string("hello!!")));
var1.set(serialized("hello!!"_s));
killswitch.on();
spyingAllocator.clearLog();

View File

@@ -7,6 +7,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
@@ -15,9 +16,9 @@ TEST_CASE("JsonVariant::remove(int)") {
JsonDocument doc(&spy);
SECTION("release top level strings") {
doc.add(std::string("hello"));
doc.add(std::string("hello"));
doc.add(std::string("world"));
doc.add("hello"_s);
doc.add("hello"_s);
doc.add("world"_s);
JsonVariant var = doc.as<JsonVariant>();
REQUIRE(var.as<std::string>() == "[\"hello\",\"hello\",\"world\"]");
@@ -43,7 +44,7 @@ TEST_CASE("JsonVariant::remove(int)") {
}
SECTION("release strings in nested array") {
doc[0][0] = std::string("hello");
doc[0][0] = "hello"_s;
JsonVariant var = doc.as<JsonVariant>();
REQUIRE(var.as<std::string>() == "[[\"hello\"]]");
@@ -77,7 +78,34 @@ TEST_CASE("JsonVariant::remove(std::string)") {
var["a"] = 1;
var["b"] = 2;
var.remove(std::string("b"));
var.remove("b"_s);
REQUIRE(var.as<std::string>() == "{\"a\":1}");
}
TEST_CASE("JsonVariant::remove(JsonVariant) from object") {
JsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var["a"] = "a";
var["b"] = 2;
var["c"] = "b";
var.remove(var["c"]);
REQUIRE(var.as<std::string>() == "{\"a\":\"a\",\"c\":\"b\"}");
}
TEST_CASE("JsonVariant::remove(JsonVariant) from array") {
JsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var[0] = 3;
var[1] = 2;
var[2] = 1;
var.remove(var[2]);
var.remove(var[3]); // noop
REQUIRE(var.as<std::string>() == "[3,1]");
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofObject;
@@ -137,14 +138,14 @@ TEST_CASE("JsonVariant::set() with not enough memory") {
JsonVariant v = doc.to<JsonVariant>();
SECTION("std::string") {
bool result = v.set(std::string("hello world!!"));
bool result = v.set("hello world!!"_s);
REQUIRE(result == false);
REQUIRE(v.isNull());
}
SECTION("Serialized<std::string>") {
bool result = v.set(serialized(std::string("hello world!!")));
bool result = v.set(serialized("hello world!!"_s));
REQUIRE(result == false);
REQUIRE(v.isNull());
@@ -178,7 +179,7 @@ TEST_CASE("JsonVariant::set(JsonDocument)") {
TEST_CASE("JsonVariant::set() releases the previous value") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc["hello"] = std::string("world");
doc["hello"] = "world"_s;
spy.clearLog();
JsonVariant v = doc["hello"];

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonVariant::operator[]") {
JsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
@@ -31,9 +33,9 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(2 == var.size());
var[0].as<std::string>();
// REQUIRE(std::string("element at index 0") == );
REQUIRE(std::string("element at index 1") == var[1]);
REQUIRE(std::string("element at index 0") ==
// REQUIRE("element at index 0"_s == );
REQUIRE("element at index 1"_s == var[1]);
REQUIRE("element at index 0"_s ==
var[static_cast<unsigned char>(0)]); // issue #381
REQUIRE(var[666].isNull());
REQUIRE(var[3].isNull());
@@ -46,7 +48,7 @@ TEST_CASE("JsonVariant::operator[]") {
var[1] = "world";
REQUIRE(var.size() == 2);
REQUIRE(std::string("world") == var[1]);
REQUIRE("world"_s == var[1]);
}
SECTION("set value in a nested object") {
@@ -56,7 +58,7 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(1 == var.size());
REQUIRE(1 == var[0].size());
REQUIRE(std::string("world") == var[0]["hello"]);
REQUIRE("world"_s == var[0]["hello"]);
}
SECTION("variant[0] when variant contains an integer") {
@@ -67,6 +69,15 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(var.is<int>());
REQUIRE(var.as<int>() == 123);
}
SECTION("use JsonVariant as index") {
array.add("A");
array.add("B");
array.add(1);
REQUIRE(var[var[2]] == "B");
REQUIRE(var[var[3]].isNull());
}
}
SECTION("The JsonVariant is a JsonObject") {
@@ -77,8 +88,8 @@ TEST_CASE("JsonVariant::operator[]") {
object["b"] = "element at key \"b\"";
REQUIRE(2 == var.size());
REQUIRE(std::string("element at key \"a\"") == var["a"]);
REQUIRE(std::string("element at key \"b\"") == var["b"]);
REQUIRE("element at key \"a\""_s == var["a"]);
REQUIRE("element at key \"b\""_s == var["b"]);
REQUIRE(var["c"].isNull());
REQUIRE(var[0].isNull());
}
@@ -87,7 +98,7 @@ TEST_CASE("JsonVariant::operator[]") {
var["hello"] = "world";
REQUIRE(1 == var.size());
REQUIRE(std::string("world") == var["hello"]);
REQUIRE("world"_s == var["hello"]);
}
SECTION("set value, key is a char[]") {
@@ -96,13 +107,22 @@ TEST_CASE("JsonVariant::operator[]") {
key[0] = '!'; // make sure the key is duplicated
REQUIRE(1 == var.size());
REQUIRE(std::string("world") == var["hello"]);
REQUIRE("world"_s == var["hello"]);
}
SECTION("var[key].to<JsonArray>()") {
JsonArray arr = var["hello"].to<JsonArray>();
REQUIRE(arr.isNull() == false);
}
SECTION("use JsonVariant as key") {
object["a"] = "a";
object["b"] = "b";
object["c"] = "b";
REQUIRE(var[var["c"]] == "b");
REQUIRE(var[var["d"]].isNull());
}
}
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
@@ -115,7 +135,7 @@ TEST_CASE("JsonVariant::operator[]") {
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
REQUIRE("world"_s == variant[vla]);
}
SECTION("key is a VLA, const JsonVariant") {
@@ -126,7 +146,7 @@ TEST_CASE("JsonVariant::operator[]") {
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
REQUIRE("world"_s == variant[vla]);
}
#endif
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("Unbound JsonVariant") {
JsonVariant variant;
@@ -21,6 +23,10 @@ TEST_CASE("Unbound JsonVariant") {
CHECK(variant.as<JsonObject>().isNull());
CHECK(variant.as<JsonObjectConst>().isNull());
CHECK(variant.as<JsonString>().isNull());
CHECK(variant.as<MsgPackBinary>().data() == nullptr);
CHECK(variant.as<MsgPackBinary>().size() == 0);
CHECK(variant.as<MsgPackExtension>().data() == nullptr);
CHECK(variant.as<MsgPackExtension>().size() == 0);
}
SECTION("is<T>()") {
@@ -44,8 +50,10 @@ TEST_CASE("Unbound JsonVariant") {
CHECK_FALSE(variant.set(42L));
CHECK_FALSE(variant.set(42U));
CHECK_FALSE(variant.set(serialized("42")));
CHECK_FALSE(variant.set(serialized(std::string("42"))));
CHECK_FALSE(variant.set(serialized("42"_s)));
CHECK_FALSE(variant.set(true));
CHECK_FALSE(variant.set(MsgPackBinary("hello", 5)));
CHECK_FALSE(variant.set(MsgPackExtension(1, "hello", 5)));
}
SECTION("add()") {
@@ -62,7 +70,7 @@ TEST_CASE("Unbound JsonVariant") {
CHECK(variant["key"].isNull());
CHECK_FALSE(variant[0].set(1));
CHECK_FALSE(variant["key"].set(1));
CHECK_FALSE(variant[std::string("key")].set(1));
CHECK_FALSE(variant["key"_s].set(1));
}
SECTION("containsKey()") {

View File

@@ -6,6 +6,8 @@
#include <stdint.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonVariantConst::as<T>()") {
JsonDocument doc;
JsonVariantConst var = doc.to<JsonVariant>();
@@ -14,6 +16,27 @@ TEST_CASE("JsonVariantConst::as<T>()") {
REQUIRE(var.as<bool>() == true);
REQUIRE(var.as<long>() == 0L);
REQUIRE(var.as<const char*>() == std::string("hello"));
REQUIRE(var.as<std::string>() == std::string("hello"));
REQUIRE(var.as<const char*>() == "hello"_s);
REQUIRE(var.as<std::string>() == "hello"_s);
}
TEST_CASE("Invalid conversions") {
using namespace ArduinoJson::detail;
JsonVariantConst variant;
CHECK(is_same<decltype(variant.as<int>()), int>::value);
CHECK(is_same<decltype(variant.as<float>()), float>::value);
CHECK(is_same<decltype(variant.as<JsonVariantConst>()),
JsonVariantConst>::value);
CHECK(
is_same<decltype(variant.as<JsonObjectConst>()), JsonObjectConst>::value);
CHECK(is_same<decltype(variant.as<JsonArrayConst>()), JsonArrayConst>::value);
CHECK(is_same<decltype(variant.as<JsonVariant>()),
InvalidConversion<JsonVariantConst, JsonVariant>>::value);
CHECK(is_same<decltype(variant.as<JsonObject>()),
InvalidConversion<JsonVariantConst, JsonObject>>::value);
CHECK(is_same<decltype(variant.as<JsonArray>()),
InvalidConversion<JsonVariantConst, JsonArray>>::value);
}

View File

@@ -6,6 +6,8 @@
#include <stdint.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonVariantConst::containsKey()") {
JsonDocument doc;
doc["hello"] = "world";
@@ -17,8 +19,8 @@ TEST_CASE("JsonVariantConst::containsKey()") {
}
SECTION("support std::string") {
REQUIRE(var.containsKey(std::string("hello")) == true);
REQUIRE(var.containsKey(std::string("world")) == false);
REQUIRE(var.containsKey("hello"_s) == true);
REQUIRE(var.containsKey("world"_s) == false);
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
@@ -30,4 +32,10 @@ TEST_CASE("JsonVariantConst::containsKey()") {
REQUIRE(true == var.containsKey(vla));
}
#endif
SECTION("support JsonVariant") {
doc["key"] = "hello";
REQUIRE(var.containsKey(var["key"]) == true);
REQUIRE(var.containsKey(var["foo"]) == false);
}
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("JsonVariantConst::operator[]") {
JsonDocument doc;
JsonVariantConst var = doc.to<JsonVariant>();
@@ -27,13 +29,23 @@ TEST_CASE("JsonVariantConst::operator[]") {
array.add("A");
array.add("B");
REQUIRE(std::string("A") == var[0]);
REQUIRE(std::string("B") == var[1]);
REQUIRE(std::string("A") ==
var[static_cast<unsigned char>(0)]); // issue #381
REQUIRE(var[666].isNull());
REQUIRE(var[3].isNull());
REQUIRE(var["0"].isNull());
SECTION("int") {
REQUIRE("A"_s == var[0]);
REQUIRE("B"_s == var[1]);
REQUIRE("A"_s == var[static_cast<unsigned char>(0)]); // issue #381
REQUIRE(var[666].isNull());
REQUIRE(var[3].isNull());
}
SECTION("const char*") {
REQUIRE(var["0"].isNull());
}
SECTION("JsonVariant") {
array.add(1);
REQUIRE(var[var[2]] == "B"_s);
REQUIRE(var[var[3]].isNull());
}
}
SECTION("object") {
@@ -42,16 +54,16 @@ TEST_CASE("JsonVariantConst::operator[]") {
object["b"] = "B";
SECTION("supports const char*") {
REQUIRE(std::string("A") == var["a"]);
REQUIRE(std::string("B") == var["b"]);
REQUIRE("A"_s == var["a"]);
REQUIRE("B"_s == var["b"]);
REQUIRE(var["c"].isNull());
REQUIRE(var[0].isNull());
}
SECTION("supports std::string") {
REQUIRE(std::string("A") == var[std::string("a")]);
REQUIRE(std::string("B") == var[std::string("b")]);
REQUIRE(var[std::string("c")].isNull());
REQUIRE("A"_s == var["a"_s]);
REQUIRE("B"_s == var["b"_s]);
REQUIRE(var["c"_s].isNull());
}
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
@@ -61,8 +73,14 @@ TEST_CASE("JsonVariantConst::operator[]") {
char vla[i];
strcpy(vla, "a");
REQUIRE(std::string("A") == var[vla]);
REQUIRE("A"_s == var[vla]);
}
#endif
SECTION("supports JsonVariant") {
object["c"] = "b";
REQUIRE(var[var["c"]] == "B");
REQUIRE(var[var["d"]].isNull());
}
}
}

View File

@@ -9,6 +9,7 @@
#include <catch.hpp>
#include "Literals.hpp"
#include "custom_string.hpp"
using namespace ArduinoJson::detail;
@@ -36,13 +37,13 @@ void common_tests(StringWriter& writer, const String& output) {
SECTION("OneString") {
REQUIRE(4 == print(writer, "ABCD"));
REQUIRE(std::string("ABCD") == output);
REQUIRE("ABCD"_s == output);
}
SECTION("TwoStrings") {
REQUIRE(4 == print(writer, "ABCD"));
REQUIRE(4 == print(writer, "EFGH"));
REQUIRE(std::string("ABCDEFGH") == output);
REQUIRE("ABCDEFGH"_s == output);
}
}

View File

@@ -58,5 +58,10 @@
// issue #1914
#define V7 7
// STM32, Mbed, Particle
#define A0 16
#define A1 17
#define A2 18
// catch.hpp mutes several warnings, this file also allows to detect them
#include "ArduinoJson.h"

View File

@@ -7,6 +7,5 @@
#include <string>
struct custom_char_traits : std::char_traits<char> {};
struct custom_allocator : std::allocator<char> {};
typedef std::basic_string<char, custom_char_traits, custom_allocator>
custom_string;
typedef std::basic_string<char, custom_char_traits> custom_string;

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
#if defined(__clang__)
# define CONFLICTS_WITH_BUILTIN_OPERATOR
#endif
@@ -111,7 +113,7 @@ TEST_CASE("unsigned char[]") {
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[key]);
REQUIRE("world"_s == variant[key]);
}
#endif
@@ -122,7 +124,7 @@ TEST_CASE("unsigned char[]") {
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[key]);
REQUIRE("world"_s == variant[key]);
}
#endif
@@ -160,7 +162,7 @@ TEST_CASE("unsigned char[]") {
JsonObject obj = doc.to<JsonObject>();
obj[key] = "world";
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
SECTION("JsonObject::operator[] const") {
@@ -170,7 +172,7 @@ TEST_CASE("unsigned char[]") {
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[key]);
REQUIRE("world"_s == obj[key]);
}
#endif
@@ -203,7 +205,7 @@ TEST_CASE("unsigned char[]") {
JsonObject obj = doc.to<JsonObject>();
obj["hello"] = value;
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
SECTION("set()") {
@@ -213,7 +215,7 @@ TEST_CASE("unsigned char[]") {
JsonObject obj = doc.to<JsonObject>();
obj["hello"].set(value);
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE("world"_s == obj["hello"]);
}
}
@@ -225,7 +227,7 @@ TEST_CASE("unsigned char[]") {
JsonArray arr = doc.to<JsonArray>();
arr.add(value);
REQUIRE(std::string("world") == arr[0]);
REQUIRE("world"_s == arr[0]);
}
}
@@ -238,7 +240,7 @@ TEST_CASE("unsigned char[]") {
arr.add("hello");
arr[0].set(value);
REQUIRE(std::string("world") == arr[0]);
REQUIRE("world"_s == arr[0]);
}
SECTION("operator=") {
@@ -249,7 +251,7 @@ TEST_CASE("unsigned char[]") {
arr.add("hello");
arr[0] = value;
REQUIRE(std::string("world") == arr[0]);
REQUIRE("world"_s == arr[0]);
}
}
}

View File

@@ -15,6 +15,9 @@ add_executable(MixedConfigurationTests
enable_nan_1.cpp
enable_progmem_1.cpp
issue1707.cpp
string_length_size_1.cpp
string_length_size_2.cpp
string_length_size_4.cpp
use_double_0.cpp
use_double_1.cpp
use_long_long_0.cpp

View File

@@ -0,0 +1,131 @@
#define ARDUINOJSON_STRING_LENGTH_SIZE 1
#include <ArduinoJson.h>
#include <catch.hpp>
#include <string>
#include "Literals.hpp"
TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 1") {
JsonDocument doc;
SECTION("set(std::string)") {
SECTION("returns true if len <= 255") {
auto result = doc.set(std::string(255, '?'));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
SECTION("returns false if len >= 256") {
auto result = doc.set(std::string(256, '?'));
REQUIRE(result == false);
REQUIRE(doc.overflowed() == true);
}
}
SECTION("set(MsgPackBinary)") {
SECTION("returns true if size <= 253") {
auto str = std::string(253, '?');
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
SECTION("returns false if size >= 254") {
auto str = std::string(254, '?');
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
REQUIRE(result == false);
REQUIRE(doc.overflowed() == true);
}
}
SECTION("set(MsgPackExtension)") {
SECTION("returns true if size <= 252") {
auto str = std::string(252, '?');
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
SECTION("returns false if size >= 253") {
auto str = std::string(253, '?');
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
REQUIRE(result == false);
REQUIRE(doc.overflowed() == true);
}
}
SECTION("deserializeJson()") {
SECTION("returns Ok if string length <= 255") {
auto input = "\"" + std::string(255, '?') + "\"";
auto err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if string length >= 256") {
auto input = "\"" + std::string(256, '?') + "\"";
auto err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
}
SECTION("deserializeMsgPack()") {
SECTION("returns Ok if string length <= 255") {
auto input = "\xd9\xff" + std::string(255, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if string length >= 256") {
auto input = "\xda\x01\x00"_s + std::string(256, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("returns Ok if binary size <= 253") {
auto input = "\xc4\xfd" + std::string(253, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if binary size >= 254") {
auto input = "\xc4\xfe" + std::string(254, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("returns Ok if extension size <= 252") {
auto input = "\xc7\xfc\x01" + std::string(252, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if binary size >= 253") {
auto input = "\xc7\xfd\x01" + std::string(253, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
}
}

View File

@@ -0,0 +1,140 @@
#define ARDUINOJSON_STRING_LENGTH_SIZE 2
#include <ArduinoJson.h>
#include <catch.hpp>
#include <string>
#include "Literals.hpp"
TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 2") {
JsonDocument doc;
SECTION("set(std::string)") {
SECTION("returns true if len <= 65535") {
auto result = doc.set(std::string(65535, '?'));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
SECTION("returns false if len >= 65536") {
auto result = doc.set(std::string(65536, '?'));
REQUIRE(result == false);
REQUIRE(doc.overflowed() == true);
}
}
SECTION("set(MsgPackBinary)") {
SECTION("returns true if size <= 65532") {
auto str = std::string(65532, '?');
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
SECTION("returns false if size >= 65533") {
auto str = std::string(65533, '?');
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
REQUIRE(result == false);
REQUIRE(doc.overflowed() == true);
}
}
SECTION("set(MsgPackExtension)") {
SECTION("returns true if size <= 65531") {
auto str = std::string(65531, '?');
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
SECTION("returns false if size >= 65532") {
auto str = std::string(65532, '?');
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
REQUIRE(result == false);
REQUIRE(doc.overflowed() == true);
}
}
SECTION("deserializeJson()") {
SECTION("returns Ok if string length <= 65535") {
auto input = "\"" + std::string(65535, '?') + "\"";
auto err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if string length >= 65536") {
auto input = "\"" + std::string(65536, '?') + "\"";
auto err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
}
SECTION("deserializeMsgPack()") {
SECTION("returns Ok if string length <= 65535") {
auto input = "\xda\xff\xff" + std::string(65535, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if string length >= 65536") {
auto input = "\xdb\x00\x01\x00\x00"_s + std::string(65536, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("returns Ok if binary size <= 65532") {
auto input = "\xc5\xff\xfc" + std::string(65532, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if binary size >= 65534") {
auto input = "\xc5\xff\xfd" + std::string(65534, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
// https://oss-fuzz.com/testcase?key=5354792971993088
SECTION("doesn't overflow if binary size == 0xFFFF") {
auto input = "\xc5\xff\xff"_s;
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("returns Ok if extension size <= 65531") {
auto input = "\xc8\xff\xfb\x01" + std::string(65531, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns NoMemory if extension size >= 65532") {
auto input = "\xc8\xff\xfc\x01" + std::string(65532, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
}
}

View File

@@ -0,0 +1,146 @@
#define ARDUINOJSON_STRING_LENGTH_SIZE 4
#include <ArduinoJson.h>
#include <catch.hpp>
#include <string>
#include "Literals.hpp"
TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 4") {
JsonDocument doc;
SECTION("set(std::string)") {
SECTION("returns true if string length >= 65536") {
auto result = doc.set(std::string(65536, '?'));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
}
SECTION("set(MsgPackBinary)") {
SECTION("returns true if size >= 65536") {
auto str = std::string(65536, '?');
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
}
SECTION("set(MsgPackExtension)") {
SECTION("returns true if size >= 65532") {
auto str = std::string(65532, '?');
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
REQUIRE(result == true);
REQUIRE(doc.overflowed() == false);
}
}
SECTION("deserializeJson()") {
SECTION("returns Ok if string length >= 65536") {
auto input = "\"" + std::string(65536, '?') + "\"";
auto err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
}
SECTION("deserializeMsgPack()") {
SECTION("returns Ok if string size >= 65536") {
auto input = "\xda\xff\xff" + std::string(65536, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns Ok if binary size >= 65536") {
auto input = "\xc5\xff\xff" + std::string(65536, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("returns Ok if extension size >= 65532") {
auto input = "\xc8\xff\xfb\x01" + std::string(65532, '?');
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
// https://oss-fuzz.com/testcase?key=5354792971993088
SECTION("doesn't overflow if binary size == 0xFFFFFFFF") {
auto input = "\xc6\xff\xff\xff\xff"_s;
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("doesn't overflow if string size == 0xFFFFFFFF") {
auto input = "\xdb\xff\xff\xff\xff???????????????????"_s;
auto err = deserializeMsgPack(doc, input);
REQUIRE(err != DeserializationError::Ok);
}
}
SECTION("bin 32 deserialization") {
auto str = std::string(65536, '?');
auto input = "\xc6\x00\x01\x00\x00"_s + str;
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackBinary>());
auto binary = doc.as<MsgPackBinary>();
REQUIRE(binary.size() == 65536);
REQUIRE(binary.data() != nullptr);
REQUIRE(std::string(reinterpret_cast<const char*>(binary.data()),
binary.size()) == str);
}
SECTION("bin 32 serialization") {
auto str = std::string(65536, '?');
doc.set(MsgPackBinary(str.data(), str.size()));
std::string output;
auto result = serializeMsgPack(doc, output);
REQUIRE(result == 5 + str.size());
REQUIRE(output == "\xc6\x00\x01\x00\x00"_s + str);
}
SECTION("ext 32 deserialization") {
auto str = std::string(65536, '?');
auto input = "\xc9\x00\x01\x00\x00\x2a"_s + str;
auto err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto value = doc.as<MsgPackExtension>();
REQUIRE(value.type() == 42);
REQUIRE(value.size() == 65536);
REQUIRE(value.data() != nullptr);
REQUIRE(std::string(reinterpret_cast<const char*>(value.data()),
value.size()) == str);
}
SECTION("ext 32 serialization") {
auto str = std::string(65536, '?');
doc.set(MsgPackExtension(42, str.data(), str.size()));
std::string output;
auto result = serializeMsgPack(doc, output);
REQUIRE(result == 6 + str.size());
REQUIRE(output == "\xc9\x00\x01\x00\x00\x2a"_s + str);
}
}

View File

@@ -3,14 +3,40 @@
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("ARDUINOJSON_USE_LONG_LONG == 0") {
JsonDocument doc;
doc["A"] = 42;
doc["B"] = 84;
SECTION("smoke test") {
doc["A"] = 42;
doc["B"] = 84;
std::string json;
serializeJson(doc, json);
std::string json;
serializeJson(doc, json);
REQUIRE(json == "{\"A\":42,\"B\":84}");
REQUIRE(json == "{\"A\":42,\"B\":84}");
}
SECTION("deserializeMsgPack()") {
SECTION("cf 00 00 00 00 ff ff ff ff") {
auto err =
deserializeMsgPack(doc, "\xcf\x00\x00\x00\x00\xff\xff\xff\xff"_s);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.as<uint32_t>() == 0xFFFFFFFF);
}
SECTION("cf 00 00 00 01 00 00 00 00") {
auto err =
deserializeMsgPack(doc, "\xcf\x00\x00\x00\x01\x00\x00\x00\x00"_s);
REQUIRE(err == DeserializationError::Ok);
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8
REQUIRE(doc.as<JsonInteger>() == 0x100000000);
#else
REQUIRE(doc.isNull());
#endif
}
}
}

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "Allocators.hpp"
#include "Literals.hpp"
template <typename T>
static void checkValue(const char* input, T expected) {
@@ -123,21 +124,171 @@ TEST_CASE("deserialize MsgPack value") {
SECTION("fixstr") {
checkValue<std::string>("\xA0", std::string(""));
checkValue<std::string>("\xABhello world", std::string("hello world"));
checkValue<std::string>("\xABhello world", "hello world"_s);
checkValue<std::string>("\xBFhello world hello world hello !",
std::string("hello world hello world hello !"));
"hello world hello world hello !"_s);
}
SECTION("str 8") {
checkValue<std::string>("\xd9\x05hello", std::string("hello"));
checkValue<std::string>("\xd9\x05hello", "hello"_s);
}
SECTION("str 16") {
checkValue<std::string>("\xda\x00\x05hello", std::string("hello"));
checkValue<std::string>("\xda\x00\x05hello", "hello"_s);
}
SECTION("str 32") {
checkValue<std::string>("\xdb\x00\x00\x00\x05hello", std::string("hello"));
checkValue<std::string>("\xdb\x00\x00\x00\x05hello", "hello"_s);
}
SECTION("bin 8") {
JsonDocument doc;
DeserializationError error = deserializeMsgPack(doc, "\xc4\x01?");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackBinary>());
auto binary = doc.as<MsgPackBinary>();
REQUIRE(binary.size() == 1);
REQUIRE(binary.data() != nullptr);
REQUIRE(reinterpret_cast<const char*>(binary.data())[0] == '?');
}
SECTION("bin 16") {
JsonDocument doc;
auto str = std::string(256, '?');
auto input = "\xc5\x01\x00"_s + str;
DeserializationError error = deserializeMsgPack(doc, input);
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackBinary>());
auto binary = doc.as<MsgPackBinary>();
REQUIRE(binary.size() == 0x100);
REQUIRE(binary.data() != nullptr);
REQUIRE(std::string(reinterpret_cast<const char*>(binary.data()),
binary.size()) == str);
}
SECTION("fixext 1") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xd4\x01\x02");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 1);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == 2);
}
SECTION("fixext 2") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xd5\x01\x02\x03");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 2);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == 2);
REQUIRE(data[1] == 3);
}
SECTION("fixext 4") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xd6\x01\x02\x03\x04\x05");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 4);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == 2);
REQUIRE(data[1] == 3);
REQUIRE(data[2] == 4);
REQUIRE(data[3] == 5);
}
SECTION("fixext 8") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xd7\x01????????");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 8);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == '?');
REQUIRE(data[7] == '?');
}
SECTION("fixext 16") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xd8\x01?????????????????");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 16);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == '?');
REQUIRE(data[15] == '?');
}
SECTION("ext 8") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xc7\x02\x01\x03\x04");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 2);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == 3);
REQUIRE(data[1] == 4);
}
SECTION("ext 16") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xc8\x00\x02\x01\x03\x04");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 2);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == 3);
REQUIRE(data[1] == 4);
}
SECTION("ext 32") {
JsonDocument doc;
auto error = deserializeMsgPack(doc, "\xc9\x00\x00\x00\x02\x01\x03\x04");
REQUIRE(error == DeserializationError::Ok);
REQUIRE(doc.is<MsgPackExtension>());
auto ext = doc.as<MsgPackExtension>();
REQUIRE(ext.type() == 1);
REQUIRE(ext.size() == 2);
auto data = reinterpret_cast<const uint8_t*>(ext.data());
REQUIRE(data[0] == 3);
REQUIRE(data[1] == 4);
}
}
@@ -198,12 +349,12 @@ TEST_CASE("deserializeMsgPack() under memory constaints") {
checkError(0, "\x80", DeserializationError::Ok);
}
SECTION("{H:1}") {
checkError(0, "\x81\xA1H\x01", DeserializationError::NoMemory);
checkError(3, "\x81\xA1H\x01", DeserializationError::Ok);
checkError(1, "\x81\xA1H\x01", DeserializationError::NoMemory);
checkError(2, "\x81\xA1H\x01", DeserializationError::Ok);
}
SECTION("{H:1,W:2}") {
checkError(3, "\x82\xA1H\x01\xA1W\x02", DeserializationError::NoMemory);
checkError(5, "\x82\xA1H\x01\xA1W\x02", DeserializationError::Ok);
checkError(2, "\x82\xA1H\x01\xA1W\x02", DeserializationError::NoMemory);
checkError(3, "\x82\xA1H\x01\xA1W\x02", DeserializationError::Ok);
}
}
@@ -212,13 +363,13 @@ TEST_CASE("deserializeMsgPack() under memory constaints") {
checkError(0, "\xDE\x00\x00", DeserializationError::Ok);
}
SECTION("{H:1}") {
checkError(2, "\xDE\x00\x01\xA1H\x01", DeserializationError::NoMemory);
checkError(3, "\xDE\x00\x01\xA1H\x01", DeserializationError::Ok);
checkError(1, "\xDE\x00\x01\xA1H\x01", DeserializationError::NoMemory);
checkError(2, "\xDE\x00\x01\xA1H\x01", DeserializationError::Ok);
}
SECTION("{H:1,W:2}") {
checkError(3, "\xDE\x00\x02\xA1H\x01\xA1W\x02",
checkError(2, "\xDE\x00\x02\xA1H\x01\xA1W\x02",
DeserializationError::NoMemory);
checkError(5, "\xDE\x00\x02\xA1H\x01\xA1W\x02", DeserializationError::Ok);
checkError(3, "\xDE\x00\x02\xA1H\x01\xA1W\x02", DeserializationError::Ok);
}
}
@@ -227,14 +378,14 @@ TEST_CASE("deserializeMsgPack() under memory constaints") {
checkError(0, "\xDF\x00\x00\x00\x00", DeserializationError::Ok);
}
SECTION("{H:1}") {
checkError(2, "\xDF\x00\x00\x00\x01\xA1H\x01",
checkError(1, "\xDF\x00\x00\x00\x01\xA1H\x01",
DeserializationError::NoMemory);
checkError(3, "\xDF\x00\x00\x00\x01\xA1H\x01", DeserializationError::Ok);
checkError(2, "\xDF\x00\x00\x00\x01\xA1H\x01", DeserializationError::Ok);
}
SECTION("{H:1,W:2}") {
checkError(3, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
checkError(2, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
DeserializationError::NoMemory);
checkError(5, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
checkError(3, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
DeserializationError::Ok);
}
}

View File

@@ -8,6 +8,7 @@
#include <string>
#include "Allocators.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
@@ -15,7 +16,7 @@ using ArduinoJson::detail::sizeofObject;
TEST_CASE("deserializeMsgPack(JsonDocument&)") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc.add(std::string("hello"));
doc.add("hello"_s);
spy.clearLog();
auto err = deserializeMsgPack(doc, "\x91\x2A");
@@ -34,7 +35,7 @@ TEST_CASE("deserializeMsgPack(JsonVariant)") {
SECTION("variant is bound") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc.add(std::string("hello"));
doc.add("hello"_s);
spy.clearLog();
JsonVariant variant = doc[0];
@@ -60,7 +61,7 @@ TEST_CASE("deserializeMsgPack(JsonVariant)") {
TEST_CASE("deserializeMsgPack(ElementProxy)") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc.add(std::string("hello"));
doc.add("hello"_s);
spy.clearLog();
SECTION("element already exists") {
@@ -85,7 +86,7 @@ TEST_CASE("deserializeMsgPack(ElementProxy)") {
TEST_CASE("deserializeMsgPack(MemberProxy)") {
SpyingAllocator spy;
JsonDocument doc(&spy);
doc[std::string("hello")] = std::string("world");
doc["hello"_s] = "world"_s;
spy.clearLog();
SECTION("member already exists") {

View File

@@ -13,7 +13,7 @@ static void check(const char* input, T expected) {
uint8_t* f = reinterpret_cast<uint8_t*>(&actual);
const uint8_t* d = reinterpret_cast<const uint8_t*>(input);
doubleToFloat(d, f);
fixEndianess(actual);
fixEndianness(actual);
CHECK(actual == expected);
}

View File

@@ -7,6 +7,8 @@
#include <sstream>
#include "Allocators.hpp"
TEST_CASE("deserializeMsgPack() returns InvalidInput") {
JsonDocument doc;
@@ -182,84 +184,18 @@ TEST_CASE("deserializeMsgPack() returns IncompleteInput") {
}
}
static std::string msgPackToJson(const char* input, size_t inputSize) {
JsonDocument doc;
auto err = deserializeMsgPack(doc, input, inputSize);
REQUIRE(err == DeserializationError::Ok);
return doc.as<std::string>();
}
TEST_CASE(
"deserializeMsgPack() returns NoMemory when string allocation fails") {
TimebombAllocator allocator(0);
JsonDocument doc(&allocator);
SECTION("fixstr") {
DeserializationError err = deserializeMsgPack(doc, "\xA5hello", 9);
REQUIRE(err == DeserializationError::NoMemory);
}
TEST_CASE("deserializeMsgPack() replaces unsupported types by null") {
SECTION("bin 8") {
REQUIRE(msgPackToJson("\x92\xc4\x01X\x2A", 5) == "[null,42]");
}
SECTION("bin 16") {
REQUIRE(msgPackToJson("\x92\xc5\x00\x01X\x2A", 6) == "[null,42]");
}
SECTION("bin 32") {
REQUIRE(msgPackToJson("\x92\xc6\x00\x00\x00\x01X\x2A", 8) == "[null,42]");
}
SECTION("ext 8") {
REQUIRE(msgPackToJson("\x92\xc7\x01\x01\x01\x2A", 6) == "[null,42]");
}
SECTION("ext 16") {
REQUIRE(msgPackToJson("\x92\xc8\x00\x01\x01\x01\x2A", 7) == "[null,42]");
}
SECTION("ext 32") {
REQUIRE(msgPackToJson("\x92\xc9\x00\x00\x00\x01\x01\x01\x2A", 9) ==
"[null,42]");
}
SECTION("fixext 1") {
REQUIRE(msgPackToJson("\x92\xd4\x01\x01\x2A", 5) == "[null,42]");
}
SECTION("fixext 2") {
REQUIRE(msgPackToJson("\x92\xd5\x01\x01\x02\x2A", 6) == "[null,42]");
}
SECTION("fixext 4") {
REQUIRE(msgPackToJson("\x92\xd6\x01\x01\x02\x03\x04\x2A", 8) ==
"[null,42]");
}
SECTION("fixext 8") {
REQUIRE(msgPackToJson("\x92\xd7\x01\x01\x02\x03\x04\x05\x06\x07\x08\x2A",
12) == "[null,42]");
}
SECTION("fixext 16") {
REQUIRE(msgPackToJson("\x92\xd8\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"
"\x0B\x0C\x0D\x0E"
"\x0F\x10\x2A",
20) == "[null,42]");
}
}
TEST_CASE("deserializeMsgPack() returns NoMemory is string length overflows") {
JsonDocument doc;
auto maxLength = ArduinoJson::detail::StringNode::maxLength;
SECTION("max length should succeed") {
auto len = maxLength;
std::string prefix = {'\xdb', char(len >> 24), char(len >> 16),
char(len >> 8), char(len)};
auto err = deserializeMsgPack(doc, prefix + std::string(len, 'a'));
REQUIRE(err == DeserializationError::Ok);
}
SECTION("one above max length should fail") {
auto len = maxLength + 1;
std::string prefix = {'\xdb', char(len >> 24), char(len >> 16),
char(len >> 8), char(len)};
auto err = deserializeMsgPack(doc, prefix + std::string(len, 'a'));
DeserializationError err = deserializeMsgPack(doc, "\xC4\x01X", 3);
REQUIRE(err == DeserializationError::NoMemory);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
#include <catch.hpp>
#include "CustomReader.hpp"
#include "Literals.hpp"
using ArduinoJson::detail::sizeofObject;
@@ -21,8 +22,7 @@ TEST_CASE("deserializeMsgPack(const std::string&)") {
}
SECTION("should accept temporary string") {
DeserializationError err =
deserializeMsgPack(doc, std::string("\x92\x01\x02"));
DeserializationError err = deserializeMsgPack(doc, "\x92\x01\x02"_s);
REQUIRE(err == DeserializationError::Ok);
}
@@ -35,12 +35,11 @@ TEST_CASE("deserializeMsgPack(const std::string&)") {
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
REQUIRE("hello"_s == array[0]);
}
SECTION("should accept a zero in input") {
DeserializationError err =
deserializeMsgPack(doc, std::string("\x92\x00\x02", 3));
DeserializationError err = deserializeMsgPack(doc, "\x92\x00\x02"_s);
REQUIRE(err == DeserializationError::Ok);
JsonArray arr = doc.as<JsonArray>();
@@ -53,7 +52,7 @@ TEST_CASE("deserializeMsgPack(std::istream&)") {
JsonDocument doc;
SECTION("should accept a zero in input") {
std::istringstream input(std::string("\x92\x00\x02", 3));
std::istringstream input("\x92\x00\x02"_s);
DeserializationError err = deserializeMsgPack(doc, input);

View File

@@ -7,6 +7,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
static void check(const JsonArray array, const char* expected_data,
size_t expected_len) {
std::string expected(expected_data, expected_data + expected_len);
@@ -57,7 +59,6 @@ TEST_CASE("serialize MsgPack array") {
array.add(nil);
REQUIRE(array.size() == 65536);
check(array,
std::string("\xDD\x00\x01\x00\x00", 5) + std::string(65536, '\xc0'));
check(array, "\xDD\x00\x01\x00\x00"_s + std::string(65536, '\xc0'));
}
}

View File

@@ -6,6 +6,8 @@
#include <stdio.h>
#include <catch.hpp>
#include "Literals.hpp"
static void check(const JsonObject object, const char* expected_data,
size_t expected_len) {
std::string expected(expected_data, expected_data + expected_len);
@@ -44,7 +46,7 @@ TEST_CASE("serialize MsgPack object") {
SECTION("map 16") {
for (int i = 0; i < 16; ++i) {
char key[16];
sprintf(key, "i%X", i);
snprintf(key, sizeof(key), "i%X", i);
object[key] = i;
}
@@ -60,7 +62,7 @@ TEST_CASE("serialize MsgPack object") {
//
// for (int i = 0; i < 65536; ++i) {
// char kv[16];
// sprintf(kv, "%04x", i);
// snprintf(kv, sizeof(kv), "%04x", i);
// object[kv] = kv;
// expected += '\xA4';
// expected += kv;
@@ -77,7 +79,7 @@ TEST_CASE("serialize MsgPack object") {
}
SECTION("serialized(std::string)") {
object["hello"] = serialized(std::string("\xDB\x00\x01\x00\x00", 5));
object["hello"] = serialized("\xDB\x00\x01\x00\x00"_s);
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
}
}

View File

@@ -5,6 +5,8 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Literals.hpp"
template <typename T>
static void checkVariant(T value, const char* expected_data,
size_t expected_len) {
@@ -129,16 +131,15 @@ TEST_CASE("serialize MsgPack value") {
SECTION("str 16") {
std::string shortest(256, '?');
checkVariant(shortest.c_str(), std::string("\xDA\x01\x00", 3) + shortest);
checkVariant(shortest.c_str(), "\xDA\x01\x00"_s + shortest);
std::string longest(65535, '?');
checkVariant(longest.c_str(), std::string("\xDA\xFF\xFF", 3) + longest);
checkVariant(longest.c_str(), "\xDA\xFF\xFF"_s + longest);
}
SECTION("str 32") {
std::string shortest(65536, '?');
checkVariant(shortest.c_str(),
std::string("\xDB\x00\x01\x00\x00", 5) + shortest);
checkVariant(shortest.c_str(), "\xDB\x00\x01\x00\x00"_s + shortest);
}
SECTION("serialized(const char*)") {
@@ -146,6 +147,56 @@ TEST_CASE("serialize MsgPack value") {
checkVariant(serialized("\xDB\x00\x01\x00\x00", 5), "\xDB\x00\x01\x00\x00");
}
SECTION("bin 8") {
checkVariant(MsgPackBinary("?", 1), "\xC4\x01?");
}
SECTION("bin 16") {
auto str = std::string(256, '?');
checkVariant(MsgPackBinary(str.data(), str.size()), "\xC5\x01\x00"_s + str);
}
// bin 32 is tested in string_length_size_4.cpp
SECTION("fixext 1") {
checkVariant(MsgPackExtension(1, "\x02", 1), "\xD4\x01\x02");
}
SECTION("fixext 2") {
checkVariant(MsgPackExtension(1, "\x03\x04", 2), "\xD5\x01\x03\x04");
}
SECTION("fixext 4") {
checkVariant(MsgPackExtension(1, "\x05\x06\x07\x08", 4),
"\xD6\x01\x05\x06\x07\x08");
}
SECTION("fixext 8") {
checkVariant(MsgPackExtension(1, "????????", 8), "\xD7\x01????????");
}
SECTION("fixext 16") {
checkVariant(MsgPackExtension(1, "????????????????", 16),
"\xD8\x01????????????????");
}
SECTION("ext 8") {
checkVariant(MsgPackExtension(2, "???", 3), "\xC7\x03\x02???");
checkVariant(MsgPackExtension(2, "?????", 5), "\xC7\x05\x02?????");
checkVariant(MsgPackExtension(2, "???????", 7), "\xC7\x07\x02???????");
checkVariant(MsgPackExtension(2, "?????????", 9), "\xC7\x09\x02?????????");
checkVariant(MsgPackExtension(2, "???????????????", 15),
"\xC7\x0F\x02???????????????");
checkVariant(MsgPackExtension(2, "?????????????????", 17),
"\xC7\x11\x02?????????????????");
}
SECTION("ext 16") {
auto str = std::string(256, '?');
checkVariant(MsgPackExtension(2, str.data(), str.size()),
"\xC8\x01\x00\x02"_s + str);
}
SECTION("serialize round double as integer") { // Issue #1718
checkVariant(-32768.0, "\xD1\x80\x00");
checkVariant(-129.0, "\xD1\xFF\x7F");

View File

@@ -3,6 +3,7 @@
// MIT License
#include <ArduinoJson/Memory/StringBuilder.hpp>
#include <ArduinoJson/Memory/VariantPoolImpl.hpp>
#include <catch.hpp>
#include "Allocators.hpp"

View File

@@ -2,9 +2,7 @@
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Memory/VariantPoolImpl.hpp>
#include <ArduinoJson.hpp>
#include <catch.hpp>
#include "Allocators.hpp"

View File

@@ -3,6 +3,7 @@
// MIT License
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Memory/VariantPoolImpl.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <catch.hpp>

View File

@@ -1,7 +1,7 @@
version: "7.0.4"
version: "7.1.0"
description: >-
A simple and efficient JSON library for embedded C++.
⭐ 6503 stars on GitHub!
⭐ 6624 stars on GitHub!
Supports serialization, deserialization, MessagePack, streams, filtering, and more.
Fully tested and documented.
url: https://arduinojson.org/

View File

@@ -1,13 +1,13 @@
{
"name": "ArduinoJson",
"keywords": "json, rest, http, web",
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6503 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++. ⭐ 6624 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.0.4",
"version": "7.1.0",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"

View File

@@ -1,9 +1,9 @@
name=ArduinoJson
version=7.0.4
version=7.1.0
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=A simple and efficient JSON library for embedded C++.
paragraph=⭐ 6503 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
paragraph=⭐ 6624 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=*

View File

@@ -36,6 +36,7 @@
#include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Memory/ResourceManagerImpl.hpp"
#include "ArduinoJson/Memory/VariantPoolImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
@@ -47,7 +48,9 @@
#include "ArduinoJson/Json/JsonDeserializer.hpp"
#include "ArduinoJson/Json/JsonSerializer.hpp"
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
#include "ArduinoJson/MsgPack/MsgPackBinary.hpp"
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
#include "ArduinoJson/MsgPack/MsgPackExtension.hpp"
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
#include "ArduinoJson/compatibility.hpp"

View File

@@ -20,6 +20,17 @@ class ArrayData : public CollectionData {
return array->addElement(resources);
}
template <typename T>
bool addValue(T&& value, ResourceManager* resources);
template <typename T>
static bool addValue(ArrayData* array, T&& value,
ResourceManager* resources) {
if (!array)
return false;
return array->addValue(value, resources);
}
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
VariantData* getElement(size_t index, const ResourceManager* resources) const;

View File

@@ -47,4 +47,19 @@ inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
remove(at(index, resources), resources);
}
template <typename T>
inline bool ArrayData::addValue(T&& value, ResourceManager* resources) {
ARDUINOJSON_ASSERT(resources != nullptr);
auto slot = resources->allocSlot();
if (!slot)
return false;
JsonVariant variant(slot->data(), resources);
if (!variant.set(detail::forward<T>(value))) {
resources->freeSlot(slot);
return false;
}
addSlot(slot, resources);
return true;
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -44,8 +44,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() const {
detail::enable_if_t<!detail::is_same<T, JsonVariant>::value, T> add() const {
return add<JsonVariant>().to<T>();
}
@@ -53,8 +52,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
add() const {
detail::enable_if_t<detail::is_same<T, JsonVariant>::value, T> add() const {
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
resources_);
}
@@ -63,14 +61,14 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
bool add(const T& value) const {
return add<JsonVariant>().set(value);
return detail::ArrayData::addValue(data_, value, resources_);
}
// Appends a value to the array.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
bool add(T* value) const {
return add<JsonVariant>().set(value);
return detail::ArrayData::addValue(data_, value, resources_);
}
// Returns an iterator to the first element of the array.
@@ -114,6 +112,15 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
detail::ArrayData::removeElement(data_, index, resources_);
}
// Removes the element at the specified index.
// https://arduinojson.org/v7/api/jsonarray/remove/
template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value> remove(
TVariant variant) const {
if (variant.template is<size_t>())
remove(variant.template as<size_t>());
}
// Removes all the elements of the array.
// https://arduinojson.org/v7/api/jsonarray/clear/
void clear() const {
@@ -122,8 +129,23 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Gets or sets the element at the specified index.
// https://arduinojson.org/v7/api/jsonarray/subscript/
detail::ElementProxy<JsonArray> operator[](size_t index) const {
return {*this, index};
template <typename T>
detail::enable_if_t<detail::is_integral<T>::value,
detail::ElementProxy<JsonArray>>
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 <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value,
detail::ElementProxy<JsonArray>>
operator[](const TVariant& variant) const {
if (variant.template is<size_t>())
return operator[](variant.template as<size_t>());
else
return {*this, size_t(-1)};
}
operator JsonVariantConst() const {

View File

@@ -36,7 +36,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
}
// Creates an unbound reference.
JsonArrayConst() : data_(0) {}
JsonArrayConst() : data_(0), resources_(0) {}
// INTERNAL USE ONLY
JsonArrayConst(const detail::ArrayData* data,
@@ -45,9 +45,23 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
// Returns the element at the specified index.
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
JsonVariantConst operator[](size_t index) const {
template <typename T>
detail::enable_if_t<detail::is_integral<T>::value, JsonVariantConst>
operator[](T index) const {
return JsonVariantConst(
detail::ArrayData::getElement(data_, index, resources_), resources_);
detail::ArrayData::getElement(data_, size_t(index), resources_),
resources_);
}
// Returns the element at the specified index.
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
operator[](const TVariant& variant) const {
if (variant.template is<size_t>())
return operator[](variant.template as<size_t>());
else
return JsonVariantConst();
}
operator JsonVariantConst() const {

View File

@@ -12,16 +12,16 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Copies a value to a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T>
inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type
copyArray(const T& src, JsonVariant dst) {
inline detail::enable_if_t<!detail::is_array<T>::value, 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 <typename T, size_t N, typename TDestination>
inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
inline detail::enable_if_t<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>
copyArray(T (&src)[N], const TDestination& dst) {
return copyArray(src, N, dst);
}
@@ -29,8 +29,8 @@ copyArray(T (&src)[N], const TDestination& dst) {
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, typename TDestination>
inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
inline detail::enable_if_t<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>
copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true;
for (size_t i = 0; i < len; i++) {
@@ -63,8 +63,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 <typename T>
inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type
copyArray(JsonVariantConst src, T& dst) {
inline detail::enable_if_t<!detail::is_array<T>::value, size_t> copyArray(
JsonVariantConst src, T& dst) {
dst = src.as<T>();
return 1;
}
@@ -103,10 +103,9 @@ 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 <typename TSource, typename T>
inline typename detail::enable_if<
detail::is_array<T>::value &&
detail::is_base_of<JsonDocument, TSource>::value,
size_t>::type
inline detail::enable_if_t<detail::is_array<T>::value &&
detail::is_base_of<JsonDocument, TSource>::value,
size_t>
copyArray(const TSource& src, T& dst) {
return copyArray(src.template as<JsonArrayConst>(), dst);
}

View File

@@ -111,12 +111,13 @@ class CollectionData {
return head_;
}
void addSlot(SlotWithId slot, ResourceManager* resources);
protected:
iterator addSlot(ResourceManager*);
private:
SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
void releaseSlot(SlotWithId, ResourceManager*);
};
inline const VariantData* collectionToVariant(

View File

@@ -63,13 +63,25 @@ inline CollectionData::iterator CollectionData::addSlot(
return iterator(slot, slot.id());
}
inline void CollectionData::addSlot(SlotWithId slot,
ResourceManager* resources) {
if (tail_ != NULL_SLOT) {
auto tail = resources->getSlot(tail_);
tail->setNext(slot.id());
tail_ = slot.id();
} else {
head_ = slot.id();
tail_ = slot.id();
}
}
inline void CollectionData::clear(ResourceManager* resources) {
auto next = head_;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = resources->getSlot(next);
next = slot->next();
releaseSlot(SlotWithId(slot, currId), resources);
resources->freeSlot(SlotWithId(slot, currId));
}
head_ = NULL_SLOT;
@@ -102,7 +114,7 @@ inline void CollectionData::remove(iterator it, ResourceManager* resources) {
head_ = next;
if (next == NULL_SLOT)
tail_ = prev.id();
releaseSlot({it.slot_, it.currentId_}, resources);
resources->freeSlot({it.slot_, it.currentId_});
}
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
@@ -122,12 +134,4 @@ inline size_t CollectionData::size(const ResourceManager* resources) const {
return count;
}
inline void CollectionData::releaseSlot(SlotWithId slot,
ResourceManager* resources) {
if (slot->ownsKey())
resources->dereferenceString(slot->key());
slot->data()->setNull(resources);
resources->freeSlot(slot);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -93,11 +93,14 @@
// https://arduinojson.org/v7/config/slot_id_size/
#ifndef ARDUINOJSON_SLOT_ID_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_SLOT_ID_SIZE 1 // up to 255 slots
// 8-bit and 16-bit archs => up to 255 slots
# define ARDUINOJSON_SLOT_ID_SIZE 1
# elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_SLOT_ID_SIZE 2 // up to 65535 slots
// 32-bit arch => up to 65535 slots
# define ARDUINOJSON_SLOT_ID_SIZE 2
# else
# define ARDUINOJSON_SLOT_ID_SIZE 4 // up to 4294967295 slots
// 64-bit arch => up to 4294967295 slots
# define ARDUINOJSON_SLOT_ID_SIZE 4
# endif
#endif

View File

@@ -62,9 +62,8 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TInput>
Reader<typename remove_reference<TInput>::type> makeReader(TInput&& input) {
return Reader<typename remove_reference<TInput>::type>{
detail::forward<TInput>(input)};
Reader<remove_reference_t<TInput>> makeReader(TInput&& input) {
return Reader<remove_reference_t<TInput>>{detail::forward<TInput>(input)};
}
template <typename TChar>

View File

@@ -9,8 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TSource>
struct Reader<TSource,
typename enable_if<is_base_of<Stream, TSource>::value>::type> {
struct Reader<TSource, enable_if_t<is_base_of<Stream, TSource>::value>> {
public:
explicit Reader(Stream& stream) : stream_(&stream) {}

View File

@@ -9,8 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TSource>
struct Reader<TSource,
typename enable_if<is_base_of<::String, TSource>::value>::type>
struct Reader<TSource, enable_if_t<is_base_of<::String, TSource>::value>>
: BoundedReader<const char*> {
explicit Reader(const ::String& s)
: BoundedReader<const char*>(s.c_str(), s.length()) {}

View File

@@ -4,6 +4,8 @@
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TIterator>
@@ -29,13 +31,8 @@ class IteratorReader {
}
};
template <typename T>
struct void_ {
typedef void type;
};
template <typename TSource>
struct Reader<TSource, typename void_<typename TSource::const_iterator>::type>
struct Reader<TSource, void_t<typename TSource::const_iterator>>
: IteratorReader<typename TSource::const_iterator> {
explicit Reader(const TSource& source)
: IteratorReader<typename TSource::const_iterator>(source.begin(),

View File

@@ -19,8 +19,7 @@ template <typename T>
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
template <typename TSource>
struct Reader<TSource*,
typename enable_if<IsCharOrVoid<TSource>::value>::type> {
struct Reader<TSource*, enable_if_t<IsCharOrVoid<TSource>::value>> {
const char* ptr_;
public:
@@ -39,8 +38,7 @@ struct Reader<TSource*,
};
template <typename TSource>
struct BoundedReader<TSource*,
typename enable_if<IsCharOrVoid<TSource>::value>::type>
struct BoundedReader<TSource*, enable_if_t<IsCharOrVoid<TSource>::value>>
: public IteratorReader<const char*> {
public:
explicit BoundedReader(const void* ptr, size_t len)

View File

@@ -9,8 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TSource>
struct Reader<TSource, typename enable_if<
is_base_of<std::istream, TSource>::value>::type> {
struct Reader<TSource, enable_if_t<is_base_of<std::istream, TSource>::value>> {
public:
explicit Reader(std::istream& stream) : stream_(&stream) {}

View File

@@ -10,7 +10,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TVariant>
struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
struct Reader<TVariant, enable_if_t<IsVariant<TVariant>::value>>
: Reader<char*, void> {
explicit Reader(const TVariant& x)
: Reader<char*, void>(x.template as<const char*>()) {}

View File

@@ -29,10 +29,9 @@ struct is_deserialize_destination : false_type {};
template <class T>
struct is_deserialize_destination<
T, typename enable_if<is_same<decltype(VariantAttorney::getResourceManager(
detail::declval<T&>())),
ResourceManager*>::value>::type> : true_type {
};
T, enable_if_t<is_same<decltype(VariantAttorney::getResourceManager(
detail::declval<T&>())),
ResourceManager*>::value>> : true_type {};
template <typename TDestination>
inline void shrinkJsonDocument(TDestination&) {
@@ -62,8 +61,8 @@ DeserializationError doDeserialize(TDestination&& dst, TReader reader,
template <template <typename> class TDeserializer, typename TDestination,
typename TStream, typename... Args,
typename = typename enable_if< // issue #1897
!is_integral<typename first_or_void<Args...>::type>::value>::type>
typename = enable_if_t< // issue #1897
!is_integral<typename first_or_void<Args...>::type>::value>>
DeserializationError deserialize(TDestination&& dst, TStream&& input,
Args... args) {
return doDeserialize<TDeserializer>(
@@ -73,7 +72,7 @@ DeserializationError deserialize(TDestination&& dst, TStream&& input,
template <template <typename> class TDeserializer, typename TDestination,
typename TChar, typename Size, typename... Args,
typename = typename enable_if<is_integral<Size>::value>::type>
typename = enable_if_t<is_integral<Size>::value>>
DeserializationError deserialize(TDestination&& dst, TChar* input,
Size inputSize, Args... args) {
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),

View File

@@ -37,15 +37,13 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Construct from variant, array, or object
template <typename T>
JsonDocument(const T& src,
Allocator* alloc = detail::DefaultAllocator::instance(),
typename detail::enable_if<
detail::is_same<T, JsonVariant>::value ||
detail::is_same<T, JsonVariantConst>::value ||
detail::is_same<T, JsonArray>::value ||
detail::is_same<T, JsonArrayConst>::value ||
detail::is_same<T, JsonObject>::value ||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
JsonDocument(
const T& src, Allocator* alloc = detail::DefaultAllocator::instance(),
detail::enable_if_t<detail::IsVariant<T>::value ||
detail::is_same<T, JsonArray>::value ||
detail::is_same<T, JsonArrayConst>::value ||
detail::is_same<T, JsonObject>::value ||
detail::is_same<T, JsonObjectConst>::value>* = 0)
: JsonDocument(alloc) {
set(src);
}
@@ -139,9 +137,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Replaces the root with the specified value.
// https://arduinojson.org/v7/api/jsondocument/set/
template <typename T>
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
bool>::type
set(const T& src) {
detail::enable_if_t<!detail::is_base_of<JsonDocument, T>::value, bool> set(
const T& src) {
return to<JsonVariant>().set(src);
}
@@ -163,15 +160,24 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Returns true if the root object contains the specified key.
// https://arduinojson.org/v7/api/jsondocument/containskey/
template <typename TString>
bool containsKey(const TString& key) const {
detail::enable_if_t<detail::IsString<TString>::value, bool> containsKey(
const TString& key) const {
return data_.getMember(detail::adaptString(key), &resources_) != 0;
}
// Returns true if the root object contains the specified key.
// https://arduinojson.org/v7/api/jsondocument/containskey/
template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value, bool> containsKey(
const TVariant& key) const {
return containsKey(key.template as<const char*>());
}
// Gets or sets a root object's member.
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TString>
typename detail::enable_if<detail::IsString<TString>::value,
detail::MemberProxy<JsonDocument&, TString>>::type
detail::enable_if_t<detail::IsString<TString>::value,
detail::MemberProxy<JsonDocument&, TString>>
operator[](const TString& key) {
return {*this, key};
}
@@ -179,8 +185,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Gets or sets a root object's member.
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TChar>
typename detail::enable_if<detail::IsString<TChar*>::value,
detail::MemberProxy<JsonDocument&, TChar*>>::type
detail::enable_if_t<detail::IsString<TChar*>::value,
detail::MemberProxy<JsonDocument&, TChar*>>
operator[](TChar* key) {
return {*this, key};
}
@@ -188,8 +194,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Gets a root object's member.
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TString>
typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type
detail::enable_if_t<detail::IsString<TString>::value, JsonVariantConst>
operator[](const TString& key) const {
return JsonVariantConst(
data_.getMember(detail::adaptString(key), &resources_), &resources_);
@@ -198,8 +203,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Gets a root object's member.
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TChar>
typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type
detail::enable_if_t<detail::IsString<TChar*>::value, JsonVariantConst>
operator[](TChar* key) const {
return JsonVariantConst(
data_.getMember(detail::adaptString(key), &resources_), &resources_);
@@ -207,8 +211,11 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Gets or sets a root array's element.
// https://arduinojson.org/v7/api/jsondocument/subscript/
detail::ElementProxy<JsonDocument&> operator[](size_t index) {
return {*this, index};
template <typename T>
detail::enable_if_t<detail::is_integral<T>::value,
detail::ElementProxy<JsonDocument&>>
operator[](T index) {
return {*this, size_t(index)};
}
// Gets a root array's member.
@@ -217,12 +224,23 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
}
// Gets or sets a root object's member.
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value, JsonVariantConst>
operator[](const TVariant& key) const {
if (key.template is<const char*>())
return operator[](key.template as<const char*>());
if (key.template is<size_t>())
return operator[](key.template as<size_t>());
return {};
}
// Appends a new (empty) element to the root array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() {
detail::enable_if_t<!detail::is_same<T, JsonVariant>::value, T> add() {
return add<JsonVariant>().to<T>();
}
@@ -230,8 +248,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename T>
typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
add() {
detail::enable_if_t<detail::is_same<T, JsonVariant>::value, T> add() {
return JsonVariant(data_.addElement(&resources_), &resources_);
}
@@ -239,27 +256,28 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename TValue>
bool add(const TValue& value) {
return add<JsonVariant>().set(value);
return data_.addValue(value, &resources_);
}
// Appends a value to the root array.
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename TChar>
bool add(TChar* value) {
return add<JsonVariant>().set(value);
return data_.addValue(value, &resources_);
}
// Removes an element of the root array.
// https://arduinojson.org/v7/api/jsondocument/remove/
void remove(size_t index) {
detail::VariantData::removeElement(getData(), index, getResourceManager());
template <typename T>
detail::enable_if_t<detail::is_integral<T>::value> remove(T index) {
detail::VariantData::removeElement(getData(), size_t(index),
getResourceManager());
}
// Removes a member of the root object.
// https://arduinojson.org/v7/api/jsondocument/remove/
template <typename TChar>
typename detail::enable_if<detail::IsString<TChar*>::value>::type remove(
TChar* key) {
detail::enable_if_t<detail::IsString<TChar*>::value> remove(TChar* key) {
detail::VariantData::removeMember(getData(), detail::adaptString(key),
getResourceManager());
}
@@ -267,13 +285,23 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Removes a member of the root object.
// https://arduinojson.org/v7/api/jsondocument/remove/
template <typename TString>
typename detail::enable_if<detail::IsString<TString>::value>::type remove(
detail::enable_if_t<detail::IsString<TString>::value> remove(
const TString& key) {
detail::VariantData::removeMember(getData(), detail::adaptString(key),
getResourceManager());
}
// Removes a member of the root object or an element of the root array.
// https://arduinojson.org/v7/api/jsondocument/remove/
template <typename TVariant>
detail::enable_if_t<detail::IsVariant<TVariant>::value> remove(
const TVariant& key) {
if (key.template is<const char*>())
remove(key.template as<const char*>());
if (key.template is<size_t>())
remove(key.template as<size_t>());
}
operator JsonVariant() {
return getVariant();
}

View File

@@ -671,9 +671,8 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v7/api/json/deserializejson/
template <typename TDestination, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
DeserializationError>
deserializeJson(TDestination&& dst, Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
@@ -683,9 +682,8 @@ deserializeJson(TDestination&& dst, Args&&... args) {
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v7/api/json/deserializejson/
template <typename TDestination, typename TChar, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
DeserializationError>
deserializeJson(TDestination&& dst, TChar* input, Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),

Some files were not shown because too many files have changed in this diff Show More