Added JsonArrayConst, JsonObjectConst, and JsonVariantConst

This commit is contained in:
Benoit Blanchon
2018-10-12 12:00:27 +02:00
parent d1003ff6c9
commit b0560cbd99
47 changed files with 1909 additions and 1063 deletions

View File

@ -7,6 +7,7 @@ add_executable(JsonArrayTests
copyFrom.cpp
copyTo.cpp
createNested.cpp
equals.cpp
isNull.cpp
iterator.cpp
remove.cpp

32
test/JsonArray/equals.cpp Normal file
View File

@ -0,0 +1,32 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::operator==()") {
DynamicJsonDocument doc1;
JsonArray array1 = doc1.to<JsonArray>();
JsonArrayConst array1c = array1;
DynamicJsonDocument doc2;
JsonArray array2 = doc2.to<JsonArray>();
JsonArrayConst array2c = array2;
SECTION("should return false when arrays differ") {
array1.add("coucou");
array2.add(1);
REQUIRE_FALSE(array1 == array2);
REQUIRE_FALSE(array1c == array2c);
}
SECTION("should return false when arrays differ") {
array1.add("coucou");
array2.add("coucou");
REQUIRE(array1 == array2);
REQUIRE(array1c == array2c);
}
}

View File

@ -23,3 +23,22 @@ TEST_CASE("JsonArray::isNull()") {
REQUIRE(array.isNull() == true);
}*/
}
TEST_CASE("JsonArrayConst::isNull()") {
SECTION("returns true for undefined JsonArray") {
JsonArrayConst array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
JsonArrayConst array = doc.to<JsonArray>();
REQUIRE(array.isNull() == false);
}
/* SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == true);
}*/
}

View File

@ -5,15 +5,16 @@
#include <ArduinoJson.h>
#include <catch.hpp>
template <typename TIterator>
template <typename TArray>
static void run_iterator_test() {
StaticJsonDocument<JSON_ARRAY_SIZE(2)> doc;
JsonArray array = doc.to<JsonArray>();
array.add(12);
array.add(34);
JsonArray tmp = doc.to<JsonArray>();
tmp.add(12);
tmp.add(34);
TIterator it = array.begin();
TIterator end = array.end();
TArray array = tmp;
typename TArray::iterator it = array.begin();
typename TArray::iterator end = array.end();
REQUIRE(end != it);
REQUIRE(12 == it->template as<int>());
@ -27,7 +28,9 @@ static void run_iterator_test() {
}
TEST_CASE("JsonArray::begin()/end()") {
SECTION("Mutable") {
run_iterator_test<JsonArray::iterator>();
}
run_iterator_test<JsonArray>();
}
TEST_CASE("JsonArrayConst::begin()/end()") {
run_iterator_test<JsonArrayConst>();
}

View File

@ -58,9 +58,6 @@ TEST_CASE("JsonArray::operator[]") {
array[0] = arr2;
REQUIRE(arr2 == array[0].as<JsonArray>());
REQUIRE(arr2 == array[0].as<JsonArray>()); // <- short hand
// REQUIRE(arr2 == array[0].as<const JsonArray>());
// REQUIRE(arr2 == array[0].as<const JsonArray>()); // <- short hand
REQUIRE(true == array[0].is<JsonArray>());
REQUIRE(false == array[0].is<int>());
}
@ -72,7 +69,6 @@ TEST_CASE("JsonArray::operator[]") {
array[0] = obj;
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(obj == array[0].as<const JsonObject>()); // <- short hand
REQUIRE(true == array[0].is<JsonObject>());
REQUIRE(false == array[0].is<int>());
}
@ -148,3 +144,18 @@ TEST_CASE("JsonArray::operator[]") {
}
#endif
}
TEST_CASE("JsonArrayConst::operator[]") {
DynamicJsonDocument doc;
JsonArray array = doc.to<JsonArray>();
array.add(0);
SECTION("int") {
array[0] = 123;
JsonArrayConst carr = array;
REQUIRE(123 == carr[0].as<int>());
REQUIRE(true == carr[0].is<int>());
REQUIRE(false == carr[0].is<bool>());
}
}

View File

@ -7,6 +7,7 @@ add_executable(JsonObjectTests
copy.cpp
createNestedArray.cpp
createNestedObject.cpp
equals.cpp
get.cpp
invalid.cpp
is.cpp

View File

@ -10,12 +10,15 @@ TEST_CASE("JsonObject::containsKey()") {
JsonObject obj = doc.to<JsonObject>();
obj.set("hello", 42);
SECTION("returns false if key not present") {
SECTION("returns true only if key is present") {
REQUIRE(false == obj.containsKey("world"));
REQUIRE(true == obj.containsKey("hello"));
}
SECTION("returns true if key present") {
REQUIRE(true == obj.containsKey("hello"));
SECTION("works with JsonObjectConst") {
JsonObjectConst cobj = obj;
REQUIRE(false == cobj.containsKey("world"));
REQUIRE(true == cobj.containsKey("hello"));
}
SECTION("returns false after remove()") {

View File

@ -56,4 +56,13 @@ TEST_CASE("JsonObject::copyFrom()") {
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
}
SECTION("should work with JsonObjectConst") {
obj1["hello"] = "world";
obj2.copyFrom(static_cast<JsonObjectConst>(obj1));
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
}
}

View File

@ -0,0 +1,35 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::operator==()") {
DynamicJsonDocument doc1;
JsonObject obj1 = doc1.to<JsonObject>();
JsonObjectConst obj1c = obj1;
DynamicJsonDocument doc2;
JsonObject obj2 = doc2.to<JsonObject>();
JsonObjectConst obj2c = obj2;
SECTION("should return false when objs differ") {
obj1["hello"] = "coucou";
obj2["world"] = 1;
REQUIRE_FALSE(obj1 == obj2);
REQUIRE_FALSE(obj1c == obj2c);
}
SECTION("should return false when objs differ") {
obj1["hello"] = "world";
obj1["anwser"] = 42;
// insert in different order
obj2["anwser"] = 42;
obj2["hello"] = "world";
REQUIRE(obj1 == obj2);
REQUIRE(obj1c == obj2c);
}
}

View File

@ -27,4 +27,11 @@ TEST_CASE("JsonObject::get()") {
REQUIRE(std::string("world") == obj.get<char*>(vla));
}
#endif
SECTION("works on JsonObjectConst") {
obj.set("hello", "world");
const char* value =
static_cast<JsonObjectConst>(obj).get<const char*>("hello");
REQUIRE_THAT(value, Equals("world"));
}
}

View File

@ -26,23 +26,35 @@ TEST_CASE("JsonObject::begin()/end()") {
REQUIRE(obj.end() == it);
}
// SECTION("ConstIterator") {
// const JsonObject const_object = obj;
// JsonObject::iterator it = const_object.begin();
// REQUIRE(const_object.end() != it);
// REQUIRE_THAT(it->key(), Equals("ab"));
// REQUIRE(12 == it->value());
// ++it;
// REQUIRE(const_object.end() != it);
// REQUIRE_THAT(it->key(), Equals("cd"));
// REQUIRE(34 == it->value());
// ++it;
// REQUIRE(const_object.end() == it);
// }
SECTION("Dereferencing end() is safe") {
REQUIRE(obj.end()->key().isNull());
REQUIRE(obj.end()->value().isNull());
}
}
TEST_CASE("JsonObjectConst::begin()/end()") {
StaticJsonDocument<JSON_OBJECT_SIZE(2)> doc;
JsonObject obj = doc.to<JsonObject>();
obj["ab"] = 12;
obj["cd"] = 34;
JsonObjectConst cobj = obj;
SECTION("NonConstIterator") {
JsonObjectConst::iterator it = cobj.begin();
REQUIRE(cobj.end() != it);
REQUIRE(it->key() == "ab");
REQUIRE(12 == it->value());
++it;
REQUIRE(cobj.end() != it);
REQUIRE(it->key() == "cd");
REQUIRE(34 == it->value());
++it;
REQUIRE(cobj.end() == it);
}
SECTION("Dereferencing end() is safe") {
REQUIRE(cobj.end()->key().isNull());
REQUIRE(cobj.end()->value().isNull());
}
}

View File

@ -58,13 +58,7 @@ TEST_CASE("JsonObject::operator[]") {
obj["hello"] = arr;
REQUIRE(arr == obj["hello"].as<JsonArray>());
REQUIRE(arr == obj["hello"].as<JsonArray>()); // <- short hand
// REQUIRE(arr == obj["hello"].as<const JsonArray>());
// REQUIRE(arr == obj["hello"].as<const JsonArray>()); // <- short hand
REQUIRE(true == obj["hello"].is<JsonArray>());
REQUIRE(true == obj["hello"].is<JsonArray>());
REQUIRE(true == obj["hello"].is<const JsonArray>());
REQUIRE(true == obj["hello"].is<const JsonArray>());
REQUIRE(false == obj["hello"].is<JsonObject>());
}
@ -75,9 +69,7 @@ TEST_CASE("JsonObject::operator[]") {
obj["hello"] = obj2;
REQUIRE(obj2 == obj["hello"].as<JsonObject>());
REQUIRE(obj2 == obj["hello"].as<const JsonObject>());
REQUIRE(true == obj["hello"].is<JsonObject>());
REQUIRE(true == obj["hello"].is<const JsonObject>());
REQUIRE(false == obj["hello"].is<JsonArray>());
}
@ -219,4 +211,12 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(std::string("world") == obj[vla]);
}
#endif
SECTION("chain") {
obj.createNestedObject("hello")["world"] = 123;
REQUIRE(123 == obj["hello"]["world"].as<int>());
REQUIRE(true == obj["hello"]["world"].is<int>());
REQUIRE(false == obj["hello"]["world"].is<bool>());
}
}

View File

@ -158,4 +158,16 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<long long>() == 9223372036854775807);
}
#endif
SECTION("should work on JsonVariantConst") {
variant.set("hello");
JsonVariantConst cvar = variant;
REQUIRE(cvar.as<bool>() == false);
REQUIRE(cvar.as<long>() == 0L);
REQUIRE(cvar.as<const char*>() == std::string("hello"));
REQUIRE(cvar.as<char*>() == std::string("hello"));
// REQUIRE(cvar.as<std::string>() == std::string("hello"));
}
}

View File

@ -5,116 +5,146 @@
#include <ArduinoJson.h>
#include <catch.hpp>
void checkIsArray(JsonArray value) {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var.set(value);
template <typename TVariant>
void checkIsArray(TVariant var) {
REQUIRE(var.template is<JsonArray>());
REQUIRE(var.is<JsonArray>());
REQUIRE(var.is<JsonArray>());
REQUIRE(var.is<const JsonArray>());
REQUIRE(var.is<const JsonArray>());
REQUIRE_FALSE(var.is<bool>());
REQUIRE_FALSE(var.is<double>());
REQUIRE_FALSE(var.is<float>());
REQUIRE_FALSE(var.is<int>());
REQUIRE_FALSE(var.is<long>());
REQUIRE_FALSE(var.is<const char *>());
REQUIRE_FALSE(var.is<JsonObject>());
REQUIRE_FALSE(var.template is<bool>());
REQUIRE_FALSE(var.template is<double>());
REQUIRE_FALSE(var.template is<float>());
REQUIRE_FALSE(var.template is<int>());
REQUIRE_FALSE(var.template is<long>());
REQUIRE_FALSE(var.template is<const char *>());
REQUIRE_FALSE(var.template is<JsonObject>());
}
void checkIsBool(bool value) {
void testArray(JsonArray value) {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var.set(value);
REQUIRE(var.is<bool>());
checkIsArray(var);
REQUIRE_FALSE(var.is<double>());
REQUIRE_FALSE(var.is<float>());
REQUIRE_FALSE(var.is<int>());
REQUIRE_FALSE(var.is<long>());
REQUIRE_FALSE(var.is<const char *>());
REQUIRE_FALSE(var.is<JsonArray>());
REQUIRE_FALSE(var.is<JsonObject>());
JsonVariantConst cvar = var;
checkIsArray(cvar);
}
void checkIsFloat(double value) {
template <typename TVariant>
void checkIsBool(TVariant var) {
REQUIRE(var.template is<bool>());
REQUIRE_FALSE(var.template is<double>());
REQUIRE_FALSE(var.template is<float>());
REQUIRE_FALSE(var.template is<int>());
REQUIRE_FALSE(var.template is<long>());
REQUIRE_FALSE(var.template is<const char *>());
REQUIRE_FALSE(var.template is<JsonArray>());
REQUIRE_FALSE(var.template is<JsonObject>());
}
void testBool(bool value) {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var.set(value);
REQUIRE(var.is<double>());
REQUIRE(var.is<float>());
checkIsBool(var);
checkIsBool(JsonVariantConst(var));
}
REQUIRE_FALSE(var.is<bool>());
REQUIRE_FALSE(var.is<int>());
REQUIRE_FALSE(var.is<long>());
REQUIRE_FALSE(var.is<const char *>());
REQUIRE_FALSE(var.is<JsonArray>());
REQUIRE_FALSE(var.is<JsonObject>());
template <typename TVariant>
void checkIsFloat(TVariant var) {
REQUIRE(var.template is<double>());
REQUIRE(var.template is<float>());
REQUIRE_FALSE(var.template is<bool>());
REQUIRE_FALSE(var.template is<int>());
REQUIRE_FALSE(var.template is<long>());
REQUIRE_FALSE(var.template is<const char *>());
REQUIRE_FALSE(var.template is<JsonArray>());
REQUIRE_FALSE(var.template is<JsonObject>());
}
void testFloat(double value) {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var.set(value);
checkIsFloat(var);
checkIsFloat(JsonVariantConst(var));
}
template <typename TVariant>
void checkIsInteger(TVariant var) {
REQUIRE(var.template is<long>());
REQUIRE(var.template is<int>());
REQUIRE(var.template is<float>());
REQUIRE(var.template is<double>());
REQUIRE_FALSE(var.template is<bool>());
REQUIRE_FALSE(var.template is<const char *>());
REQUIRE_FALSE(var.template is<JsonArray>());
REQUIRE_FALSE(var.template is<JsonObject>());
}
template <typename T>
void checkIsInteger(T value) {
void testInteger(T value) {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var.set(value);
REQUIRE(var.is<long>());
REQUIRE(var.is<int>());
REQUIRE(var.is<float>());
REQUIRE(var.is<double>());
REQUIRE_FALSE(var.is<bool>());
REQUIRE_FALSE(var.is<const char *>());
REQUIRE_FALSE(var.is<JsonArray>());
REQUIRE_FALSE(var.is<JsonObject>());
checkIsInteger(var);
checkIsInteger(JsonVariantConst(var));
}
void checkIsString(const char *value) {
template <typename TVariant>
void checkIsString(TVariant var) {
REQUIRE(var.template is<const char *>());
REQUIRE(var.template is<std::string>());
REQUIRE_FALSE(var.template is<bool>());
REQUIRE_FALSE(var.template is<int>());
REQUIRE_FALSE(var.template is<double>());
REQUIRE_FALSE(var.template is<float>());
REQUIRE_FALSE(var.template is<long>());
REQUIRE_FALSE(var.template is<JsonArray>());
REQUIRE_FALSE(var.template is<JsonObject>());
}
void testString(const char *value) {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
var.set(value);
REQUIRE(var.is<const char *>());
REQUIRE(var.is<std::string>());
REQUIRE_FALSE(var.is<bool>());
REQUIRE_FALSE(var.is<int>());
REQUIRE_FALSE(var.is<double>());
REQUIRE_FALSE(var.is<float>());
REQUIRE_FALSE(var.is<long>());
REQUIRE_FALSE(var.is<JsonArray>());
REQUIRE_FALSE(var.is<JsonObject>());
checkIsString(var);
checkIsString(JsonVariantConst(var));
}
TEST_CASE("JsonVariant::is()") {
SECTION("JsonArray") {
DynamicJsonDocument doc;
JsonArray array = doc.to<JsonArray>();
checkIsArray(array);
testArray(array);
}
SECTION("bool") {
checkIsBool(true);
checkIsBool(false);
testBool(true);
testBool(false);
}
SECTION("double") {
checkIsFloat(4.2);
testFloat(4.2);
}
SECTION("int") {
checkIsInteger(42);
testInteger(42);
}
SECTION("long") {
checkIsInteger(42L);
testInteger(42L);
}
SECTION("string") {
checkIsString("42");
testString("42");
}
}

View File

@ -44,4 +44,12 @@ TEST_CASE("JsonVariant::isNull()") {
variant.set(JsonObject());
REQUIRE(variant.isNull() == true);
}*/
SECTION("works with JsonVariantConst") {
variant.set(42);
JsonVariantConst cvar = variant;
REQUIRE(cvar.isNull() == false);
}
}

View File

@ -120,3 +120,55 @@ TEST_CASE("JsonVariant::operator[]") {
}
#endif
}
TEST_CASE("JsonVariantConst::operator[]") {
DynamicJsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
JsonVariantConst cvar = var;
SECTION("The JsonVariant is undefined") {
REQUIRE(0 == cvar.size());
REQUIRE(cvar["0"].isNull());
REQUIRE(cvar[0].isNull());
}
SECTION("The JsonVariant is a string") {
var.set("hello world");
REQUIRE(0 == cvar.size());
REQUIRE(cvar["0"].isNull());
REQUIRE(cvar[0].isNull());
}
SECTION("The JsonVariant is a JsonArray") {
JsonArray array = var.to<JsonArray>();
SECTION("get value") {
array.add("element at index 0");
array.add("element at index 1");
REQUIRE(2 == cvar.size());
REQUIRE(std::string("element at index 0") == cvar[0]);
REQUIRE(std::string("element at index 1") == cvar[1]);
REQUIRE(std::string("element at index 0") ==
var[static_cast<unsigned char>(0)]); // issue #381
REQUIRE(cvar[666].isNull());
REQUIRE(cvar[3].isNull());
REQUIRE(cvar["0"].isNull());
}
}
SECTION("The JsonVariant is a JsonObject") {
JsonObject object = var.to<JsonObject>();
SECTION("get value") {
object["a"] = "element at key \"a\"";
object["b"] = "element at key \"b\"";
REQUIRE(2 == cvar.size());
REQUIRE(std::string("element at key \"a\"") == cvar["a"]);
REQUIRE(std::string("element at key \"b\"") == cvar["b"]);
REQUIRE(cvar["c"].isNull());
REQUIRE(cvar[0].isNull());
}
}
}

View File

@ -32,15 +32,7 @@ TEST_CASE("JsonVariant undefined") {
REQUIRE(variant.as<JsonArray>().isNull());
}
SECTION("as<const JsonArray>()") {
REQUIRE(variant.as<const JsonArray>().isNull());
}
SECTION("as<JsonObject>()") {
REQUIRE(variant.as<JsonObject>().isNull());
}
SECTION("as<const JsonObject>()") {
REQUIRE(variant.as<const JsonObject>().isNull());
}
}

View File

@ -24,12 +24,6 @@ TEST_CASE("Polyfills/type_traits") {
REQUIRE((is_array<const char[10]>::value));
}
SECTION("IsVariant") {
REQUIRE(
static_cast<bool>(IsVariant<JsonObjectSubscript<const char*> >::value));
REQUIRE(static_cast<bool>(IsVariant<JsonVariant>::value));
}
SECTION("is_const") {
CHECK(is_const<char>::value == false);
CHECK(is_const<const char>::value == true);