Add JsonVariant::link() (resolves #1343)

This commit is contained in:
Benoit Blanchon
2022-04-27 15:06:58 +02:00
parent 5577d18377
commit 3d6c328a4f
35 changed files with 649 additions and 51 deletions

View File

@ -13,6 +13,7 @@ add_executable(JsonVariantTests
createNested.cpp
is.cpp
isnull.cpp
link.cpp
memoryUsage.cpp
misc.cpp
nesting.cpp

View File

@ -43,4 +43,14 @@ TEST_CASE("JsonVariant::add()") {
REQUIRE(var.as<std::string>() == "{\"val\":123}");
}
SECTION("add to linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
var.add(666); // no-op
CHECK(var.as<std::string>() == "[42]");
}
}

View File

@ -267,4 +267,97 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<MY_ENUM>() == ONE);
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
SECTION("as<std::string>()") {
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
}
SECTION("as<JsonArray>()") {
JsonArray a = variant.as<JsonArray>();
CHECK(a.isNull() == true);
}
SECTION("as<JsonObject>()") {
JsonObject o = variant.as<JsonObject>();
CHECK(o.isNull() == true);
}
SECTION("as<JsonObjectConst>()") {
JsonObjectConst o = variant.as<JsonObjectConst>();
CHECK(o.isNull() == false);
CHECK(o.size() == 1);
CHECK(o["hello"] == "world");
}
}
SECTION("linked array") {
StaticJsonDocument<128> doc2;
doc2.add("hello");
doc2.add("world");
variant.link(doc2);
SECTION("as<std::string>()") {
CHECK(variant.as<std::string>() == "[\"hello\",\"world\"]");
}
SECTION("as<JsonArray>()") {
JsonArray a = variant.as<JsonArray>();
CHECK(a.isNull() == true);
}
SECTION("as<JsonArrayConst>()") {
JsonArrayConst a = variant.as<JsonArrayConst>();
CHECK(a.isNull() == false);
CHECK(a.size() == 2);
CHECK(a[0] == "hello");
CHECK(a[1] == "world");
}
SECTION("as<JsonObject>()") {
JsonObject o = variant.as<JsonObject>();
CHECK(o.isNull() == true);
}
}
SECTION("linked int") {
StaticJsonDocument<128> doc2;
doc2.set(42);
variant.link(doc2);
CHECK(variant.as<int>() == 42);
CHECK(variant.as<double>() == 42.0);
}
SECTION("linked double") {
StaticJsonDocument<128> doc2;
doc2.set(42.0);
variant.link(doc2);
CHECK(variant.as<int>() == 42);
CHECK(variant.as<double>() == 42.0);
}
SECTION("linked string") {
StaticJsonDocument<128> doc2;
doc2.set("hello");
variant.link(doc2);
CHECK(variant.as<std::string>() == "hello");
}
SECTION("linked bool") {
StaticJsonDocument<128> doc2;
variant.link(doc2);
doc2.set(true);
CHECK(variant.as<bool>() == true);
doc2.set(false);
CHECK(variant.as<bool>() == false);
}
}

View File

@ -23,4 +23,15 @@ TEST_CASE("JsonVariant::clear()") {
REQUIRE(var.isNull() == true);
}
SECTION("doesn't alter linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
var.clear();
CHECK(var.isNull() == true);
CHECK(doc2.as<std::string>() == "{\"hello\":\"world\"}");
}
}

View File

@ -34,6 +34,20 @@ TEST_CASE("Compare JsonVariant with value") {
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
SECTION("linked 42 vs 42") {
StaticJsonDocument<128> doc2;
doc2.set(42);
a.link(doc2);
int b = 42;
CHECK(a == b);
CHECK(a <= b);
CHECK(a >= b);
CHECK_FALSE(a != b);
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
}
TEST_CASE("Compare JsonVariant with JsonVariant") {
@ -313,4 +327,19 @@ TEST_CASE("Compare JsonVariant with JsonVariant") {
CHECK_FALSE(a > b);
CHECK_FALSE(a >= b);
}
SECTION("linked 42 vs link 42") {
StaticJsonDocument<128> doc2, doc3;
doc2.set(42);
doc3.set(42);
a.link(doc2);
b.link(doc3);
CHECK(a == b);
CHECK(a <= b);
CHECK(a >= b);
CHECK_FALSE(a != b);
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
}

View File

@ -12,19 +12,28 @@ TEST_CASE("JsonVariant::containsKey()") {
DynamicJsonDocument doc(4096);
JsonVariant var = doc.to<JsonVariant>();
SECTION("containsKey(const char*) returns true") {
SECTION("containsKey(const char*)") {
var["hello"] = "world";
REQUIRE(var.containsKey("hello") == true);
REQUIRE(var.containsKey("world") == false);
}
SECTION("containsKey(std::string) returns true") {
SECTION("containsKey(std::string)") {
var["hello"] = "world";
REQUIRE(var.containsKey(std::string("hello")) == true);
REQUIRE(var.containsKey(std::string("world")) == false);
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(var.containsKey("hello") == true);
CHECK(var.containsKey("world") == false);
}
}
TEST_CASE("JsonVariantConst::containsKey()") {

View File

@ -84,6 +84,16 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(7));
}
SECTION("stores linked object by pointer") {
StaticJsonDocument<128> doc3;
doc3["hello"] = "world";
var1.link(doc3);
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 0);
REQUIRE(doc2.memoryUsage() == 0);
}
SECTION("destination is unbound") {
JsonVariant unboundVariant;

View File

@ -18,6 +18,17 @@ TEST_CASE("JsonVariant::createNestedObject()") {
REQUIRE(variant[0]["value"] == 42);
REQUIRE(obj.isNull() == false);
}
SECTION("does nothing on linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.link(doc2);
variant.createNestedObject();
CHECK(variant.size() == 1);
CHECK(variant[0] == 42);
}
}
TEST_CASE("JsonVariant::createNestedArray()") {
@ -30,6 +41,17 @@ TEST_CASE("JsonVariant::createNestedArray()") {
REQUIRE(variant.is<JsonArray>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("does nothing on linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.link(doc2);
variant.createNestedArray();
CHECK(variant.size() == 1);
CHECK(variant[0] == 42);
}
}
TEST_CASE("JsonVariant::createNestedObject(key)") {
@ -43,6 +65,17 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(variant["weather"]["temp"] == 42);
}
SECTION("does nothing on linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
variant.createNestedObject("weather");
CHECK(variant.size() == 1);
CHECK(variant["hello"] == "world");
}
}
TEST_CASE("JsonVariant::createNestedArray(key)") {
@ -55,4 +88,15 @@ TEST_CASE("JsonVariant::createNestedArray(key)") {
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("does nothing on linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
variant.createNestedArray("items");
CHECK(variant.size() == 1);
CHECK(variant["hello"] == "world");
}
}

View File

@ -144,6 +144,24 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<MYENUM2>() == false);
}
SECTION("linked array") {
StaticJsonDocument<1024> doc2;
doc2[0] = "world";
variant.link(doc2);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<JsonArrayConst>() == true);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonObjectConst>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == false);
}
SECTION("JsonObject") {
variant.to<JsonObject>();
@ -161,6 +179,44 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
}
SECTION("linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
variant.link(doc2);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonObjectConst>() == true);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<JsonArrayConst>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == false);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
}
SECTION("linked int") {
StaticJsonDocument<1024> doc2;
doc2.set(42);
variant.link(doc2);
CHECK(variant.is<JsonObjectConst>() == false);
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<JsonArrayConst>() == false);
CHECK(variant.is<int>() == true);
CHECK(variant.is<float>() == true);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == true);
}
}
TEST_CASE("JsonVariantConst::is<T>()") {
@ -316,4 +372,58 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
SECTION("linked array") {
StaticJsonDocument<1024> doc2;
doc2[0] = "world";
variant.link(doc2);
CHECK(cvariant.is<JsonArrayConst>() == true);
CHECK(cvariant.is<JsonVariantConst>() == true);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonObjectConst>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
SECTION("linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
variant.link(doc2);
CHECK(cvariant.is<JsonObjectConst>() == true);
CHECK(cvariant.is<JsonVariantConst>() == true);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonArrayConst>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
SECTION("linked int") {
StaticJsonDocument<1024> doc2;
doc2.set(42);
variant.link(doc2);
CHECK(cvariant.is<JsonObjectConst>() == false);
CHECK(cvariant.is<JsonVariantConst>() == true);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonArrayConst>() == false);
CHECK(cvariant.is<int>() == true);
CHECK(cvariant.is<float>() == true);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == true);
}
}

View File

@ -9,17 +9,17 @@ TEST_CASE("JsonVariant::isNull()") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("return true when Undefined") {
SECTION("returns true when Undefined") {
REQUIRE(variant.isNull() == true);
}
SECTION("return false when Integer") {
SECTION("returns false when Integer") {
variant.set(42);
REQUIRE(variant.isNull() == false);
}
SECTION("return false when EmptyArray") {
SECTION("returns false when EmptyArray") {
DynamicJsonDocument doc2(4096);
JsonArray array = doc2.to<JsonArray>();
@ -27,7 +27,7 @@ TEST_CASE("JsonVariant::isNull()") {
REQUIRE(variant.isNull() == false);
}
SECTION("return false when EmptyObject") {
SECTION("returns false when EmptyObject") {
DynamicJsonDocument doc2(4096);
JsonObject obj = doc2.to<JsonObject>();
@ -35,41 +35,54 @@ TEST_CASE("JsonVariant::isNull()") {
REQUIRE(variant.isNull() == false);
}
SECTION("return true after set(JsonArray())") {
SECTION("returns true after set(JsonArray())") {
variant.set(JsonArray());
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set(JsonObject())") {
SECTION("returns true after set(JsonObject())") {
variant.set(JsonObject());
REQUIRE(variant.isNull() == true);
}
SECTION("return false after set('hello')") {
SECTION("returns false after set('hello')") {
variant.set("hello");
REQUIRE(variant.isNull() == false);
}
SECTION("return true after set((char*)0)") {
SECTION("returns true after set((char*)0)") {
variant.set(static_cast<char*>(0));
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set((const char*)0)") {
SECTION("returns true after set((const char*)0)") {
variant.set(static_cast<const char*>(0));
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set(serialized((char*)0))") {
SECTION("returns true after set(serialized((char*)0))") {
variant.set(serialized(static_cast<char*>(0)));
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set(serialized((const char*)0))") {
SECTION("returns true after set(serialized((const char*)0))") {
variant.set(serialized(static_cast<const char*>(0)));
REQUIRE(variant.isNull() == true);
}
SECTION("returns true for a linked null") {
StaticJsonDocument<128> doc2;
variant.link(doc2);
CHECK(variant.isNull() == true);
}
SECTION("returns false for a linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.link(doc2);
CHECK(variant.isNull() == false);
}
SECTION("works with JsonVariantConst") {
variant.set(42);

View File

@ -0,0 +1,77 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonVariant::link()") {
StaticJsonDocument<1024> doc1, doc2;
JsonVariant variant = doc1.to<JsonVariant>();
SECTION("JsonVariant::link(JsonDocument&)") {
doc2["hello"] = "world";
variant.link(doc2);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(variant.memoryUsage() == 0);
// altering the linked document should change the result
doc2["hello"] = "WORLD!";
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("JsonVariant::link(MemberProxy)") {
doc2["obj"]["hello"] = "world";
variant.link(doc2["obj"]);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(variant.memoryUsage() == 0);
// altering the linked document should change the result
doc2["obj"]["hello"] = "WORLD!";
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("JsonVariant::link(ElementProxy)") {
doc2[0]["hello"] = "world";
variant.link(doc2[0]);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(variant.memoryUsage() == 0);
// altering the linked document should change the result
doc2[0]["hello"] = "WORLD!";
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("target is unbound") {
JsonVariant unbound;
variant["hello"] = "world";
variant.link(unbound);
CHECK(variant.isUnbound() == false);
CHECK(variant.isNull() == true);
CHECK(variant.memoryUsage() == 0);
CHECK(variant.size() == 0);
}
SECTION("variant is unbound") {
JsonVariant unbound;
doc2["hello"] = "world";
unbound.link(doc2);
CHECK(unbound.isUnbound() == true);
CHECK(unbound.isNull() == true);
CHECK(unbound.memoryUsage() == 0);
CHECK(unbound.size() == 0);
}
}

View File

@ -38,4 +38,12 @@ TEST_CASE("JsonVariant::memoryUsage()") {
REQUIRE(var.memoryUsage() == 6);
REQUIRE(var.memoryUsage() == doc.memoryUsage());
}
SECTION("ignore size of linked document") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(var.memoryUsage() == 0);
CHECK(var.memoryUsage() == doc.memoryUsage());
}
}

View File

@ -28,4 +28,12 @@ TEST_CASE("JsonVariant::nesting()") {
var.to<JsonArray>();
REQUIRE(var.nesting() == 1);
}
SECTION("returns depth of linked array") {
StaticJsonDocument<128> doc2;
doc2[0][0] = 42;
var.link(doc2);
CHECK(var.nesting() == 2);
}
}

View File

@ -156,4 +156,12 @@ TEST_CASE("JsonVariant::operator|()") {
int result = variant | 42;
REQUIRE(result == 42);
}
SECTION("linked int | int") {
StaticJsonDocument<128> doc2;
doc2.set(42);
variant.link(doc2);
int result = variant | 666;
CHECK(result == 42);
}
}

View File

@ -39,4 +39,24 @@ TEST_CASE("JsonVariant::remove()") {
REQUIRE(var.as<std::string>() == "{\"a\":1}");
}
SECTION("linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
var.link(doc2);
var.remove(0);
CHECK(var.as<std::string>() == "[42]");
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
var.remove("hello");
CHECK(var.as<std::string>() == "{\"hello\":\"world\"}");
}
}

View File

@ -41,4 +41,13 @@ TEST_CASE("JsonVariant::size()") {
CHECK(variant.size() == 1);
}
SECTION("linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(1);
doc2.add(2);
variant.link(doc2);
CHECK(variant.size() == 2);
}
}

View File

@ -129,6 +129,44 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(std::string("world") == variant[vla]);
}
#endif
SECTION("get value from linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(var["hello"].as<std::string>() == "world");
}
SECTION("set value to linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
var.link(doc2);
var["tutu"] = "toto"; // no-op
CHECK(doc.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(doc2.as<std::string>() == "{\"hello\":\"world\"}");
}
SECTION("get value from linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
CHECK(var[0].as<int>() == 42);
}
SECTION("set value to linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
var[0] = 666; // no-op
CHECK(doc.as<std::string>() == "[42]");
CHECK(doc2.as<std::string>() == "[42]");
}
}
TEST_CASE("JsonVariantConst::operator[]") {
@ -201,4 +239,20 @@ TEST_CASE("JsonVariantConst::operator[]") {
REQUIRE(var.is<JsonObject>() == false);
REQUIRE(value == 0);
}
SECTION("get value from linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(cvar["hello"].as<std::string>() == "world");
}
SECTION("get value from linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
CHECK(cvar[0].as<int>() == 42);
}
}