Copy JsonArray and JsonObject, instead of storing pointers (fixes #780)

This commit is contained in:
Benoit Blanchon
2018-09-11 16:05:56 +02:00
parent 2998a55f0b
commit b106b1ed14
52 changed files with 971 additions and 978 deletions

View File

@ -5,6 +5,7 @@
add_executable(JsonVariantTests
as.cpp
compare.cpp
copy.cpp
is.cpp
isnull.cpp
or.cpp

View File

@ -12,223 +12,150 @@ TEST_CASE("JsonVariant::as()") {
DynamicJsonDocument doc;
JsonVariant variant = doc.to<JsonVariant>();
SECTION("DoubleAsBool") {
SECTION("not set") {
REQUIRE(false == variant.as<bool>());
REQUIRE(0 == variant.as<int>());
REQUIRE(0.0f == variant.as<float>());
REQUIRE(0 == variant.as<char*>());
REQUIRE("null" == variant.as<std::string>());
}
SECTION("set(4.2)") {
variant.set(4.2);
REQUIRE(variant.as<bool>());
REQUIRE(0 == variant.as<const char*>());
REQUIRE(variant.as<std::string>() == "4.2");
REQUIRE(variant.as<long>() == 4L);
REQUIRE(variant.as<unsigned>() == 4U);
}
SECTION("DoubleAsCstr") {
variant.set(4.2);
REQUIRE_FALSE(variant.as<const char*>());
}
SECTION("DoubleAsString") {
variant.set(4.2);
REQUIRE(std::string("4.2") == variant.as<std::string>());
}
SECTION("DoubleAsLong") {
variant.set(4.2);
REQUIRE(4L == variant.as<long>());
}
SECTION("DoubleAsUnsigned") {
variant.set(4.2);
REQUIRE(4U == variant.as<unsigned>());
}
SECTION("DoubleZeroAsBool") {
SECTION("set(0.0)") {
variant.set(0.0);
REQUIRE_FALSE(variant.as<bool>());
REQUIRE(variant.as<bool>() == false);
REQUIRE(variant.as<long>() == 0L);
}
SECTION("DoubleZeroAsLong") {
variant.set(0.0);
REQUIRE(0L == variant.as<long>());
}
SECTION("FalseAsBool") {
SECTION("set(false)") {
variant.set(false);
REQUIRE_FALSE(variant.as<bool>());
REQUIRE(false == variant.as<bool>());
REQUIRE(variant.as<double>() == 0.0);
REQUIRE(variant.as<long>() == 0L);
REQUIRE(variant.as<std::string>() == "false");
}
SECTION("FalseAsDouble") {
variant.set(false);
REQUIRE(0.0 == variant.as<double>());
}
SECTION("FalseAsLong") {
variant.set(false);
REQUIRE(0L == variant.as<long>());
}
SECTION("FalseAsString") {
variant.set(false);
REQUIRE(std::string("false") == variant.as<std::string>());
}
SECTION("TrueAsBool") {
SECTION("set(true)") {
variant.set(true);
REQUIRE(variant.as<bool>());
REQUIRE(variant.as<double>() == 1.0);
REQUIRE(variant.as<long>() == 1L);
REQUIRE(variant.as<std::string>() == "true");
}
SECTION("TrueAsDouble") {
variant.set(true);
REQUIRE(1.0 == variant.as<double>());
}
SECTION("TrueAsLong") {
variant.set(true);
REQUIRE(1L == variant.as<long>());
}
SECTION("TrueAsString") {
variant.set(true);
REQUIRE(std::string("true") == variant.as<std::string>());
}
SECTION("LongAsBool") {
SECTION("set(42L)") {
variant.set(42L);
REQUIRE(variant.as<bool>());
REQUIRE(variant.as<bool>() == true);
REQUIRE(variant.as<double>() == 42.0);
REQUIRE(variant.as<std::string>() == "42");
}
SECTION("LongZeroAsBool") {
variant.set(0L);
REQUIRE_FALSE(variant.as<bool>());
}
SECTION("PositiveLongAsDouble") {
variant.set(42L);
REQUIRE(42.0 == variant.as<double>());
}
SECTION("NegativeLongAsDouble") {
SECTION("set(-42L)") {
variant.set(-42L);
REQUIRE(-42.0 == variant.as<double>());
REQUIRE(variant.as<double>() == -42.0);
REQUIRE(variant.as<std::string>() == "-42");
}
SECTION("LongAsString") {
variant.set(42L);
REQUIRE(std::string("42") == variant.as<std::string>());
}
SECTION("LongZeroAsDouble") {
SECTION("set(0L)") {
variant.set(0L);
REQUIRE(0.0 == variant.as<double>());
SECTION("as<bool>()") {
REQUIRE(false == variant.as<bool>());
}
SECTION("as<double>()") {
REQUIRE(variant.as<double>() == 0.0);
}
}
SECTION("NullAsBool") {
SECTION("set(null)") {
variant.set(null);
REQUIRE_FALSE(variant.as<bool>());
REQUIRE(variant.as<bool>() == false);
REQUIRE(variant.as<double>() == 0.0);
REQUIRE(variant.as<long>() == 0L);
REQUIRE(variant.as<std::string>() == "null");
}
SECTION("NullAsDouble") {
variant.set(null);
REQUIRE(0.0 == variant.as<double>());
}
SECTION("NullAsLong") {
variant.set(null);
REQUIRE(0L == variant.as<long>());
}
SECTION("NullAsString") {
variant.set(null);
REQUIRE(std::string("null") == variant.as<std::string>());
}
SECTION("NumberStringAsBool") {
SECTION("set(\"42\")") {
variant.set("42");
REQUIRE(variant.as<bool>());
REQUIRE(variant.as<long>() == 42L);
}
SECTION("NumberStringAsLong") {
variant.set("42");
REQUIRE(42L == variant.as<long>());
}
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
SECTION("NumberStringAsInt64Negative") {
variant.set("-9223372036854775808");
REQUIRE(-9223372036854775807 - 1 == variant.as<long long>());
}
SECTION("NumberStringAsInt64Positive") {
variant.set("9223372036854775807");
REQUIRE(9223372036854775807 == variant.as<long long>());
}
#endif
SECTION("RandomStringAsBool") {
SECTION("set(\"hello\")") {
variant.set("hello");
REQUIRE_FALSE(variant.as<bool>());
REQUIRE(variant.as<bool>() == false);
REQUIRE(variant.as<long>() == 0L);
REQUIRE(variant.as<const char*>() == std::string("hello"));
REQUIRE(variant.as<char*>() == std::string("hello"));
REQUIRE(variant.as<std::string>() == std::string("hello"));
}
SECTION("RandomStringAsLong") {
variant.set("hello");
REQUIRE(0L == variant.as<long>());
}
SECTION("RandomStringAsConstCharPtr") {
variant.set("hello");
REQUIRE(std::string("hello") == variant.as<const char*>());
}
SECTION("RandomStringAsCharPtr") {
variant.set("hello");
REQUIRE(std::string("hello") == variant.as<char*>());
}
SECTION("RandomStringAsString") {
variant.set("hello");
REQUIRE(std::string("hello") == variant.as<std::string>());
}
SECTION("TrueStringAsBool") {
SECTION("set(\"true\")") {
variant.set("true");
REQUIRE(variant.as<bool>());
REQUIRE(variant.as<long>() == 1L);
}
SECTION("TrueStringAsLong") {
variant.set("true");
REQUIRE(1L == variant.as<long>());
}
SECTION("ObjectAsString") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
SECTION("to<JsonObject>()") {
JsonObject obj = variant.to<JsonObject>();
obj["key"] = "value";
variant.set(obj);
REQUIRE(std::string("{\"key\":\"value\"}") == variant.as<std::string>());
SECTION("as<std::string>()") {
REQUIRE(variant.as<std::string>() == std::string("{\"key\":\"value\"}"));
}
SECTION("ObjectAsJsonObject") {
JsonObject o = variant.as<JsonObject>();
REQUIRE(o.size() == 1);
REQUIRE(o["key"] == std::string("value"));
}
}
SECTION("ArrayAsString") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
SECTION("to<JsonArray>()") {
JsonArray arr = variant.to<JsonArray>();
arr.add(4);
arr.add(2);
variant.set(arr);
REQUIRE(std::string("[4,2]") == variant.as<std::string>());
SECTION("as<std::string>()") {
REQUIRE(variant.as<std::string>() == std::string("[4,2]"));
}
SECTION("as<JsonArray>()") {
JsonArray a = variant.as<JsonArray>();
REQUIRE(a.size() == 2);
REQUIRE(a[0] == 4);
REQUIRE(a[1] == 2);
}
}
SECTION("ArrayAsJsonArray") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
variant.set(arr);
REQUIRE(arr == variant.as<JsonArray>());
REQUIRE(arr == variant.as<JsonArray>()); // <- shorthand
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
SECTION("Smallest int64 negative") {
variant.set("-9223372036854775808");
REQUIRE(variant.as<long long>() == -9223372036854775807 - 1);
}
SECTION("ObjectAsJsonObject") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
variant.set(obj);
REQUIRE(obj == variant.as<JsonObject>());
REQUIRE(obj == variant.as<JsonObject>()); // <- shorthand
SECTION("Biggerst int64 positive") {
variant.set("9223372036854775807");
REQUIRE(variant.as<long long>() == 9223372036854775807);
}
#endif
}

View File

@ -265,13 +265,11 @@ TEST_CASE("JsonVariant comparisons") {
}
SECTION("ArrayInVariant") {
DynamicJsonDocument docArr1, docArr2;
JsonArray array1 = docArr1.to<JsonArray>();
JsonArray array2 = docArr2.to<JsonArray>();
JsonArray array1 = variant1.to<JsonArray>();
JsonArray array2 = variant2.to<JsonArray>();
variant1.set(array1);
variant2.set(array1);
variant3.set(array2);
array1.add(42);
array2.add(42);
REQUIRE(variant1 == variant2);
REQUIRE_FALSE(variant1 != variant2);
@ -281,13 +279,11 @@ TEST_CASE("JsonVariant comparisons") {
}
SECTION("ObjectInVariant") {
DynamicJsonDocument docObj1, docObj2;
JsonObject obj1 = docObj1.to<JsonObject>();
JsonObject obj2 = docObj2.to<JsonObject>();
JsonObject obj1 = variant1.to<JsonObject>();
JsonObject obj2 = variant2.to<JsonObject>();
variant1.set(obj1);
variant2.set(obj1);
variant3.set(obj2);
obj1["hello"] = "world";
obj2["hello"] = "world";
REQUIRE(variant1 == variant2);
REQUIRE_FALSE(variant1 != variant2);

84
test/JsonVariant/copy.cpp Normal file
View File

@ -0,0 +1,84 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonVariant::set(JsonVariant)") {
DynamicJsonDocument doc1;
DynamicJsonDocument doc2;
JsonVariant var1 = doc1.to<JsonVariant>();
JsonVariant var2 = doc2.to<JsonVariant>();
SECTION("stores JsonArray by copy") {
JsonArray arr = doc2.to<JsonArray>();
arr.add(42);
var1.set(doc2.as<JsonVariant>());
arr[0] = 666;
REQUIRE(var1.as<std::string>() == "[42]");
}
SECTION("stores JsonObject by copy") {
JsonObject obj = doc2.to<JsonObject>();
obj["value"] = 42;
var1.set(doc2.as<JsonVariant>());
obj["value"] = 666;
REQUIRE(var1.as<std::string>() == "{\"value\":42}");
}
SECTION("stores const char* by reference") {
var1.set("hello!!");
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 0);
REQUIRE(doc2.memoryUsage() == 0);
}
SECTION("stores char* by copy") {
char str[] = "hello!!";
var1.set(str);
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 8);
REQUIRE(doc2.memoryUsage() == 8);
}
SECTION("stores std::string by copy") {
var1.set(std::string("hello!!"));
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 8);
REQUIRE(doc2.memoryUsage() == 8);
}
SECTION("stores Serialized<const char*> by reference") {
var1.set(serialized("hello!!", 8));
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 0);
REQUIRE(doc2.memoryUsage() == 0);
}
SECTION("stores Serialized<char*> by copy") {
char str[] = "hello!!";
var1.set(serialized(str, 8));
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 8);
REQUIRE(doc2.memoryUsage() == 8);
}
SECTION("stores Serialized<std::string> by copy") {
var1.set(serialized(std::string("hello!!!")));
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 8);
REQUIRE(doc2.memoryUsage() == 8);
}
}

View File

@ -35,13 +35,13 @@ TEST_CASE("JsonVariant::isNull()") {
REQUIRE(variant.isNull() == false);
}
SECTION("return true when InvalidArray") {
variant.set(JsonArray());
REQUIRE(variant.isNull() == true);
}
SECTION("return true when InvalidObject") {
variant.set(JsonObject());
REQUIRE(variant.isNull() == true);
}
/* SECTION("return true when InvalidArray") {
variant.set(JsonArray());
REQUIRE(variant.isNull() == true);
}
*/
/* SECTION("return true when InvalidObject") {
variant.set(JsonObject());
REQUIRE(variant.isNull() == true);
}*/
}

View File

@ -23,9 +23,7 @@ TEST_CASE("JsonVariant::operator[]") {
}
SECTION("The JsonVariant is a JsonArray") {
DynamicJsonDocument doc2;
JsonArray array = doc2.to<JsonArray>();
var.set(array);
JsonArray array = var.to<JsonArray>();
SECTION("get value") {
array.add("element at index 0");
@ -62,9 +60,7 @@ TEST_CASE("JsonVariant::operator[]") {
}
SECTION("The JsonVariant is a JsonObject") {
DynamicJsonDocument doc2;
JsonObject object = doc2.to<JsonObject>();
var.set(object);
JsonObject object = var.to<JsonObject>();
SECTION("get value") {
object["a"] = "element at key \"a\"";
@ -92,6 +88,11 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(1 == var.size());
REQUIRE(std::string("world") == var["hello"]);
}
SECTION("var[key].to<JsonArray>()") {
JsonArray arr = var["hello"].to<JsonArray>();
REQUIRE(arr.isNull() == false);
}
}
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \

View File

@ -8,47 +8,39 @@
TEST_CASE("JsonVariant undefined") {
JsonVariant variant;
SECTION("AsLongReturns0") {
SECTION("as<long>()") {
REQUIRE(0 == variant.as<long>());
}
SECTION("AsUnsignedReturns0") {
SECTION("as<unsigned>()") {
REQUIRE(0 == variant.as<unsigned>());
}
SECTION("AsStringReturnsNull") {
SECTION("as<char*>()") {
REQUIRE(0 == variant.as<char*>());
}
SECTION("AsDoubleReturns0") {
SECTION("as<double>()") {
REQUIRE(0 == variant.as<double>());
}
SECTION("AsBoolReturnsFalse") {
SECTION("as<bool>()") {
REQUIRE(false == variant.as<bool>());
}
SECTION("AsArrayReturnInvalid") {
REQUIRE(JsonArray() == variant.as<JsonArray>());
SECTION("as<JsonArray>()") {
REQUIRE(variant.as<JsonArray>().isNull());
}
SECTION("AsConstArrayReturnInvalid") {
REQUIRE(JsonArray() == variant.as<const JsonArray>());
SECTION("as<const JsonArray>()") {
REQUIRE(variant.as<const JsonArray>().isNull());
}
SECTION("AsObjectReturnInvalid") {
REQUIRE(JsonObject() == variant.as<JsonObject>());
SECTION("as<JsonObject>()") {
REQUIRE(variant.as<JsonObject>().isNull());
}
SECTION("AsConstObjectReturnInvalid") {
REQUIRE(JsonObject() == variant.as<const JsonObject>());
}
SECTION("AsArrayWrapperReturnInvalid") {
REQUIRE(JsonArray() == variant.as<JsonArray>());
}
SECTION("AsObjectWrapperReturnInvalid") {
REQUIRE(JsonObject() == variant.as<JsonObject>());
SECTION("as<const JsonObject>()") {
REQUIRE(variant.as<const JsonObject>().isNull());
}
}