Fixed duplication of char*

This commit is contained in:
Benoit Blanchon
2018-08-22 14:37:17 +02:00
parent 7683667b3c
commit 6d290bd001
25 changed files with 601 additions and 531 deletions

View File

@ -127,23 +127,28 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
} }
} }
// set(char*)
template <typename T>
bool set(T *value,
typename Internals::enable_if<Internals::IsString<T *>::value>::type
* = 0) {
if (!_data) return false;
const char *dup = Internals::makeString(value).save(_buffer);
if (dup) {
_data->setString(dup);
return true;
} else {
_data->setNull();
return false;
}
}
// set(const char*); // set(const char*);
// set(const char[n]); // VLA
bool set(const char *value) { bool set(const char *value) {
if (!_data) return false; if (!_data) return false;
_data->setString(value); _data->setString(value);
return true; return true;
} }
// set(const unsigned char*);
// set(const unsigned char[n]); // VLA
bool set(const unsigned char *value) {
return set(reinterpret_cast<const char *>(value));
}
// set(const signed char*);
// set(const signed char[n]); // VLA
bool set(const signed char *value) {
return set(reinterpret_cast<const char *>(value));
}
bool set(const JsonVariant &value) { bool set(const JsonVariant &value) {
if (!_data) return false; if (!_data) return false;

View File

@ -38,7 +38,9 @@ endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options( add_compile_options(
-Wstrict-null-sentinel -Wstrict-null-sentinel
-Wno-vla # Allow VLA in tests
) )
add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5) if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
@ -53,6 +55,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options( add_compile_options(
-Wc++11-compat -Wc++11-compat
-Wdeprecated-register -Wdeprecated-register
-Wno-vla-extension # Allow VLA in tests
)
add_definitions(
-DHAS_VARIABLE_LENGTH_ARRAY
-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
) )
endif() endif()

View File

@ -7,57 +7,69 @@
TEST_CASE("JsonArray::add()") { TEST_CASE("JsonArray::add()") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>(); JsonArray array = doc.to<JsonArray>();
SECTION("int") { SECTION("int") {
_array.add(123); array.add(123);
REQUIRE(123 == _array[0].as<int>()); REQUIRE(123 == array[0].as<int>());
REQUIRE(_array[0].is<int>()); REQUIRE(array[0].is<int>());
REQUIRE(_array[0].is<double>()); REQUIRE(array[0].is<double>());
} }
SECTION("double") { SECTION("double") {
_array.add(123.45); array.add(123.45);
REQUIRE(123.45 == _array[0].as<double>()); REQUIRE(123.45 == array[0].as<double>());
REQUIRE(_array[0].is<double>()); REQUIRE(array[0].is<double>());
REQUIRE_FALSE(_array[0].is<bool>()); REQUIRE_FALSE(array[0].is<bool>());
} }
SECTION("bool") { SECTION("bool") {
_array.add(true); array.add(true);
REQUIRE(true == _array[0].as<bool>()); REQUIRE(true == array[0].as<bool>());
REQUIRE(_array[0].is<bool>()); REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("const char*") { SECTION("const char*") {
const char* str = "hello"; const char* str = "hello";
_array.add(str); array.add(str);
REQUIRE(str == _array[0].as<std::string>()); REQUIRE(str == array[0].as<std::string>());
REQUIRE(_array[0].is<const char*>()); REQUIRE(array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("vla") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add(vla);
REQUIRE(std::string("world") == array[0]);
}
#endif
SECTION("nested array") { SECTION("nested array") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr = doc2.to<JsonArray>();
_array.add(arr); array.add(arr);
REQUIRE(arr == _array[0].as<JsonArray>()); REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(_array[0].is<JsonArray>()); REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("nested object") { SECTION("nested object") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>(); JsonObject obj = doc2.to<JsonObject>();
_array.add(obj); array.add(obj);
REQUIRE(obj == _array[0].as<JsonObject>()); REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(_array[0].is<JsonObject>()); REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("array subscript") { SECTION("array subscript") {
@ -66,9 +78,9 @@ TEST_CASE("JsonArray::add()") {
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr = doc2.to<JsonArray>();
arr.add(str); arr.add(str);
_array.add(arr[0]); array.add(arr[0]);
REQUIRE(str == _array[0]); REQUIRE(str == array[0]);
} }
SECTION("object subscript") { SECTION("object subscript") {
@ -77,49 +89,49 @@ TEST_CASE("JsonArray::add()") {
JsonObject obj = doc2.to<JsonObject>(); JsonObject obj = doc2.to<JsonObject>();
obj["x"] = str; obj["x"] = str;
_array.add(obj["x"]); array.add(obj["x"]);
REQUIRE(str == _array[0]); REQUIRE(str == array[0]);
} }
SECTION("should not duplicate const char*") { SECTION("should not duplicate const char*") {
_array.add("world"); array.add("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1); const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate char*") { SECTION("should duplicate char*") {
_array.add(const_cast<char*>("world")); array.add(const_cast<char*>("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string") { SECTION("should duplicate std::string") {
_array.add(std::string("world")); array.add(std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should not duplicate serialized(const char*)") { SECTION("should not duplicate serialized(const char*)") {
_array.add(serialized("{}")); array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1); const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate serialized(char*)") { SECTION("should duplicate serialized(char*)") {
_array.add(serialized(const_cast<char*>("{}"))); array.add(serialized(const_cast<char*>("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate serialized(std::string)") { SECTION("should duplicate serialized(std::string)") {
_array.add(serialized(std::string("{}"))); array.add(serialized(std::string("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate serialized(std::string)") { SECTION("should duplicate serialized(std::string)") {
_array.add(serialized(std::string("\0XX", 3))); array.add(serialized(std::string("\0XX", 3)));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }

View File

@ -9,57 +9,70 @@ using namespace Catch::Matchers;
TEST_CASE("JsonArray::set()") { TEST_CASE("JsonArray::set()") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>(); JsonArray array = doc.to<JsonArray>();
_array.add(0); array.add(0);
SECTION("int") { SECTION("int") {
_array.set(0, 123); array.set(0, 123);
REQUIRE(123 == _array[0].as<int>()); REQUIRE(123 == array[0].as<int>());
REQUIRE(_array[0].is<int>()); REQUIRE(array[0].is<int>());
REQUIRE_FALSE(_array[0].is<bool>()); REQUIRE_FALSE(array[0].is<bool>());
} }
SECTION("double") { SECTION("double") {
_array.set(0, 123.45); array.set(0, 123.45);
REQUIRE(123.45 == _array[0].as<double>()); REQUIRE(123.45 == array[0].as<double>());
REQUIRE(_array[0].is<double>()); REQUIRE(array[0].is<double>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("bool") { SECTION("bool") {
_array.set(0, true); array.set(0, true);
REQUIRE(true == _array[0].as<bool>()); REQUIRE(true == array[0].as<bool>());
REQUIRE(_array[0].is<bool>()); REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("const char*") { SECTION("const char*") {
_array.set(0, "hello"); array.set(0, "hello");
REQUIRE_THAT(_array[0].as<const char*>(), Equals("hello")); REQUIRE_THAT(array[0].as<const char*>(), Equals("hello"));
REQUIRE(_array[0].is<const char*>()); REQUIRE(array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array.set(0, vla);
REQUIRE(std::string("world") == array[0]);
}
#endif
SECTION("nested array") { SECTION("nested array") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr = doc2.to<JsonArray>();
_array.set(0, arr); array.set(0, arr);
REQUIRE(arr == _array[0].as<JsonArray>()); REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(_array[0].is<JsonArray>()); REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("nested object") { SECTION("nested object") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>(); JsonObject obj = doc2.to<JsonObject>();
_array.set(0, obj); array.set(0, obj);
REQUIRE(obj == _array[0].as<JsonObject>()); REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(_array[0].is<JsonObject>()); REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(_array[0].is<int>()); REQUIRE_FALSE(array[0].is<int>());
} }
SECTION("array subscript") { SECTION("array subscript") {
@ -67,9 +80,9 @@ TEST_CASE("JsonArray::set()") {
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr = doc2.to<JsonArray>();
arr.add("hello"); arr.add("hello");
_array.set(0, arr[0]); array.set(0, arr[0]);
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello")); REQUIRE_THAT(array[0].as<char*>(), Equals("hello"));
} }
SECTION("object subscript") { SECTION("object subscript") {
@ -77,25 +90,25 @@ TEST_CASE("JsonArray::set()") {
JsonObject obj = doc2.to<JsonObject>(); JsonObject obj = doc2.to<JsonObject>();
obj["x"] = "hello"; obj["x"] = "hello";
_array.set(0, obj["x"]); array.set(0, obj["x"]);
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello")); REQUIRE_THAT(array[0].as<char*>(), Equals("hello"));
} }
SECTION("should not duplicate const char*") { SECTION("should not duplicate const char*") {
_array.set(0, "world"); array.set(0, "world");
const size_t expectedSize = JSON_ARRAY_SIZE(1); const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate char*") { SECTION("should duplicate char*") {
_array.set(0, const_cast<char*>("world")); array.set(0, const_cast<char*>("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string") { SECTION("should duplicate std::string") {
_array.set(0, std::string("world")); array.set(0, std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }

View File

@ -8,85 +8,85 @@
TEST_CASE("JsonArray::operator[]") { TEST_CASE("JsonArray::operator[]") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>(); JsonArray array = doc.to<JsonArray>();
_array.add(0); array.add(0);
SECTION("int") { SECTION("int") {
_array[0] = 123; array[0] = 123;
REQUIRE(123 == _array[0].as<int>()); REQUIRE(123 == array[0].as<int>());
REQUIRE(true == _array[0].is<int>()); REQUIRE(true == array[0].is<int>());
REQUIRE(false == _array[0].is<bool>()); REQUIRE(false == array[0].is<bool>());
} }
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
SECTION("long long") { SECTION("long long") {
_array[0] = 9223372036854775807; array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == _array[0].as<long long>()); REQUIRE(9223372036854775807 == array[0].as<long long>());
REQUIRE(true == _array[0].is<int>()); REQUIRE(true == array[0].is<int>());
REQUIRE(false == _array[0].is<bool>()); REQUIRE(false == array[0].is<bool>());
} }
#endif #endif
SECTION("double") { SECTION("double") {
_array[0] = 123.45; array[0] = 123.45;
REQUIRE(123.45 == _array[0].as<double>()); REQUIRE(123.45 == array[0].as<double>());
REQUIRE(true == _array[0].is<double>()); REQUIRE(true == array[0].is<double>());
REQUIRE(false == _array[0].is<int>()); REQUIRE(false == array[0].is<int>());
} }
SECTION("bool") { SECTION("bool") {
_array[0] = true; array[0] = true;
REQUIRE(true == _array[0].as<bool>()); REQUIRE(true == array[0].as<bool>());
REQUIRE(true == _array[0].is<bool>()); REQUIRE(true == array[0].is<bool>());
REQUIRE(false == _array[0].is<int>()); REQUIRE(false == array[0].is<int>());
} }
SECTION("const char*") { SECTION("const char*") {
const char* str = "hello"; const char* str = "hello";
_array[0] = str; array[0] = str;
REQUIRE(str == _array[0].as<const char*>()); REQUIRE(str == array[0].as<const char*>());
REQUIRE(str == _array[0].as<char*>()); // <- short hand REQUIRE(str == array[0].as<char*>()); // <- short hand
REQUIRE(true == _array[0].is<const char*>()); REQUIRE(true == array[0].is<const char*>());
REQUIRE(false == _array[0].is<int>()); REQUIRE(false == array[0].is<int>());
} }
SECTION("nested array") { SECTION("nested array") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr2 = doc2.to<JsonArray>();
_array[0] = arr; array[0] = arr2;
REQUIRE(arr == _array[0].as<JsonArray>()); REQUIRE(arr2 == array[0].as<JsonArray>());
REQUIRE(arr == _array[0].as<JsonArray>()); // <- short hand REQUIRE(arr2 == array[0].as<JsonArray>()); // <- short hand
// REQUIRE(arr == _array[0].as<const JsonArray>()); // REQUIRE(arr2 == array[0].as<const JsonArray>());
// REQUIRE(arr == _array[0].as<const JsonArray>()); // <- short hand // REQUIRE(arr2 == array[0].as<const JsonArray>()); // <- short hand
REQUIRE(true == _array[0].is<JsonArray>()); REQUIRE(true == array[0].is<JsonArray>());
REQUIRE(false == _array[0].is<int>()); REQUIRE(false == array[0].is<int>());
} }
SECTION("nested object") { SECTION("nested object") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>(); JsonObject obj = doc2.to<JsonObject>();
_array[0] = obj; array[0] = obj;
REQUIRE(obj == _array[0].as<JsonObject>()); REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(obj == _array[0].as<const JsonObject>()); // <- short hand REQUIRE(obj == array[0].as<const JsonObject>()); // <- short hand
REQUIRE(true == _array[0].is<JsonObject>()); REQUIRE(true == array[0].is<JsonObject>());
REQUIRE(false == _array[0].is<int>()); REQUIRE(false == array[0].is<int>());
} }
SECTION("array subscript") { SECTION("array subscript") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr2 = doc2.to<JsonArray>();
const char* str = "hello"; const char* str = "hello";
arr.add(str); arr2.add(str);
_array[0] = arr[0]; array[0] = arr2[0];
REQUIRE(str == _array[0]); REQUIRE(str == array[0]);
} }
SECTION("object subscript") { SECTION("object subscript") {
@ -96,26 +96,50 @@ TEST_CASE("JsonArray::operator[]") {
obj["x"] = str; obj["x"] = str;
_array[0] = obj["x"]; array[0] = obj["x"];
REQUIRE(str == _array[0]); REQUIRE(str == array[0]);
} }
SECTION("should not duplicate const char*") { SECTION("should not duplicate const char*") {
_array[0] = "world"; array[0] = "world";
const size_t expectedSize = JSON_ARRAY_SIZE(1); const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate char*") { SECTION("should duplicate char*") {
_array[0] = const_cast<char*>("world"); array[0] = const_cast<char*>("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string") { SECTION("should duplicate std::string") {
_array[0] = std::string("world"); array[0] = std::string("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("set(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array[0].set(vla);
REQUIRE(std::string("world") == array[0]);
}
SECTION("operator=(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array[0] = vla;
REQUIRE(std::string("world") == array[0]);
}
#endif
} }

View File

@ -3,15 +3,14 @@
# MIT License # MIT License
add_executable(JsonDeserializerTests add_executable(JsonDeserializerTests
DeserializationError.cpp
deserializeJsonArray.cpp deserializeJsonArray.cpp
deserializeJsonArrayStatic.cpp deserializeJsonArrayStatic.cpp
deserializeJsonObject.cpp deserializeJsonObject.cpp
deserializeJsonObjectStatic.cpp deserializeJsonObjectStatic.cpp
deserializeJsonValue.cpp deserializeJsonValue.cpp
DeserializationError.cpp input_types.cpp
nestingLimit.cpp nestingLimit.cpp
std_istream.cpp
std_string.cpp
) )
target_link_libraries(JsonDeserializerTests catch) target_link_libraries(JsonDeserializerTests catch)

View File

@ -6,6 +6,35 @@
#include <catch.hpp> #include <catch.hpp>
#include <sstream> #include <sstream>
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc;
SECTION("should accept const string") {
const std::string input("[42]");
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should accept temporary string") {
DeserializationError err = deserializeJson(doc, std::string("[42]"));
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should duplicate content") {
std::string input("[\"hello\"]");
DeserializationError err = deserializeJson(doc, input);
input[2] = 'X'; // alter the string tomake sure we made a copy
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
}
}
TEST_CASE("deserializeJson(std::istream&)") { TEST_CASE("deserializeJson(std::istream&)") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -71,3 +100,16 @@ TEST_CASE("deserializeJson(std::istream&)") {
REQUIRE('1' == char(json.get())); REQUIRE('1' == char(json.get()));
} }
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
TEST_CASE("deserializeJson(VLA)") {
int i = 9;
char vla[i];
strcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeJson(doc, vla);
REQUIRE(err == DeserializationError::Ok);
}
#endif

View File

@ -1,35 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc;
SECTION("should accept const string") {
const std::string input("[42]");
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should accept temporary string") {
DeserializationError err = deserializeJson(doc, std::string("[42]"));
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should duplicate content") {
std::string input("[\"hello\"]");
DeserializationError err = deserializeJson(doc, input);
input[2] = 'X'; // alter the string tomake sure we made a copy
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
}
}

View File

@ -4,8 +4,11 @@
add_executable(JsonObjectTests add_executable(JsonObjectTests
containsKey.cpp containsKey.cpp
createNestedArray.cpp
createNestedObject.cpp
get.cpp get.cpp
invalid.cpp invalid.cpp
is.cpp
isNull.cpp isNull.cpp
iterator.cpp iterator.cpp
remove.cpp remove.cpp

View File

@ -8,23 +8,29 @@
TEST_CASE("JsonObject::containsKey()") { TEST_CASE("JsonObject::containsKey()") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>(); JsonObject obj = doc.to<JsonObject>();
obj.set("hello", 42);
SECTION("ContainsKeyReturnsFalseForNonExistingKey") { SECTION("returns false if key not present") {
obj.set("hello", 42);
REQUIRE(false == obj.containsKey("world")); REQUIRE(false == obj.containsKey("world"));
} }
SECTION("ContainsKeyReturnsTrueForDefinedValue") { SECTION("returns true if key present") {
obj.set("hello", 42);
REQUIRE(true == obj.containsKey("hello")); REQUIRE(true == obj.containsKey("hello"));
} }
SECTION("ContainsKeyReturnsFalseAfterRemove") { SECTION("returns false after remove()") {
obj.set("hello", 42);
obj.remove("hello"); obj.remove("hello");
REQUIRE(false == obj.containsKey("hello")); REQUIRE(false == obj.containsKey("hello"));
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
REQUIRE(true == obj.containsKey(vla));
}
#endif
} }

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::createNestedArray()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("key is a const char*") {
obj.createNestedArray("hello");
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.createNestedArray(vla);
}
#endif
}

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::createNestedObject()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("key is a const char*") {
obj.createNestedObject("hello");
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.createNestedObject(vla);
}
#endif
}

View File

@ -11,9 +11,20 @@ TEST_CASE("JsonObject::get()") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>(); JsonObject obj = doc.to<JsonObject>();
SECTION("GetConstCharPointer_GivenStringLiteral") { SECTION("get<const char*>(const char*)") {
obj.set("hello", "world"); obj.set("hello", "world");
const char* value = obj.get<const char*>("hello"); const char* value = obj.get<const char*>("hello");
REQUIRE_THAT(value, Equals("world")); REQUIRE_THAT(value, Equals("world"));
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("get<const char*>(VLA)") {
obj.set("hello", "world");
int i = 16;
char vla[i];
strcpy(vla, "hello");
REQUIRE(std::string("world") == obj.get<char*>(vla));
}
#endif
} }

28
test/JsonObject/is.cpp Normal file
View File

@ -0,0 +1,28 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::is<T>()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj["int"] = 42;
obj["str"] = "hello";
SECTION("is<int>(const char*)") {
REQUIRE(true == obj.is<int>("int"));
REQUIRE(false == obj.is<int>("str"));
}
#if HAS_VARIABLE_LENGTH_ARRAY
SECTION("is<T>(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "int");
REQUIRE(true == obj.is<int>(vla));
}
#endif
}

View File

@ -39,4 +39,17 @@ TEST_CASE("JsonObject::remove()") {
serializeJson(obj, result); serializeJson(obj, result);
REQUIRE("{\"a\":0,\"c\":2}" == result); REQUIRE("{\"a\":0,\"c\":2}" == result);
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a vla") {
obj["hello"] = 1;
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.remove(vla);
REQUIRE(0 == obj.size());
}
#endif
} }

View File

@ -42,6 +42,38 @@ TEST_CASE("JsonObject::set()") {
REQUIRE_FALSE(obj["hello"].is<long>()); REQUIRE_FALSE(obj["hello"].is<long>());
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.set(vla, "world");
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("value is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "world");
obj.set("hello", vla);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("key and value are VLAs") {
int i = 16;
char vla[i];
strcpy(vla, "world");
obj.set(vla, vla);
REQUIRE(std::string("world") == obj["world"]);
}
#endif
SECTION("nested array") { SECTION("nested array") {
DynamicJsonDocument doc2; DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>(); JsonArray arr = doc2.to<JsonArray>();

View File

@ -159,4 +159,58 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(obj.size() == 1); REQUIRE(obj.size() == 1);
REQUIRE(obj[null] == 0); REQUIRE(obj[null] == 0);
} }
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
SECTION("obj[VLA] = str") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("obj[str] = VLA") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
obj["hello"] = vla;
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("obj.set(VLA, str)") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("obj.set(str, VLA)") {
int i = 32;
char vla[i];
strcpy(vla, "world");
obj["hello"].set(vla);
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("obj[VLA]") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[vla]);
}
#endif
} }

View File

@ -179,6 +179,38 @@ TEST_CASE("JsonVariant comparisons") {
REQUIRE_FALSE(null == variant); REQUIRE_FALSE(null == variant);
} }
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("VLA equals") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonVariant variant = doc.to<JsonVariant>();
variant.set("hello");
REQUIRE((vla == variant));
REQUIRE((variant == vla));
REQUIRE_FALSE((vla != variant));
REQUIRE_FALSE((variant != vla));
}
SECTION("VLA differs") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonVariant variant = doc.to<JsonVariant>();
variant.set("world");
REQUIRE((vla != variant));
REQUIRE((variant != vla));
REQUIRE_FALSE((vla == variant));
REQUIRE_FALSE((variant == vla));
}
#endif
DynamicJsonDocument doc1, doc2, doc3; DynamicJsonDocument doc1, doc2, doc3;
JsonVariant variant1 = doc1.to<JsonVariant>(); JsonVariant variant1 = doc1.to<JsonVariant>();
JsonVariant variant2 = doc2.to<JsonVariant>(); JsonVariant variant2 = doc2.to<JsonVariant>();

View File

@ -138,3 +138,74 @@ TEST_CASE("JsonVariant set()/get()") {
checkValue<JsonObject>(object); checkValue<JsonObject>(object);
} }
} }
TEST_CASE("JsonVariant and strings") {
DynamicJsonDocument doc;
JsonVariant variant = doc.to<JsonVariant>();
SECTION("stores const char* by reference") {
char str[16];
strcpy(str, "hello");
variant.set(static_cast<const char *>(str));
strcpy(str, "world");
REQUIRE(variant == "world");
}
SECTION("stores char* by copy") {
char str[16];
strcpy(str, "hello");
variant.set(str);
strcpy(str, "world");
REQUIRE(variant == "hello");
}
SECTION("stores unsigned char* by copy") {
char str[16];
strcpy(str, "hello");
variant.set(reinterpret_cast<unsigned char *>(str));
strcpy(str, "world");
REQUIRE(variant == "hello");
}
SECTION("stores signed char* by copy") {
char str[16];
strcpy(str, "hello");
variant.set(reinterpret_cast<signed char *>(str));
strcpy(str, "world");
REQUIRE(variant == "hello");
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("stores VLA by copy") {
int n = 16;
char str[n];
strcpy(str, "hello");
variant.set(str);
strcpy(str, "world");
REQUIRE(variant == "hello");
}
#endif
SECTION("stores std::string by copy") {
std::string str;
str = "hello";
variant.set(str);
str.replace(0, 5, "world");
REQUIRE(variant == "hello");
}
// TODO: string
// TODO: serialized()
}

View File

@ -93,4 +93,29 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(std::string("world") == var["hello"]); REQUIRE(std::string("world") == var["hello"]);
} }
} }
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
}
SECTION("key is a VLA, const JsonVariant") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
}
#endif
} }

View File

@ -8,7 +8,6 @@ add_executable(MiscTests
TypeTraits.cpp TypeTraits.cpp
unsigned_char.cpp unsigned_char.cpp
version.cpp version.cpp
vla.cpp
) )
target_link_libraries(MiscTests catch) target_link_libraries(MiscTests catch)

View File

@ -1,327 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wvla-extension"
#define CONFLICTS_WITH_BUILTIN_OPERATOR
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wvla"
#else
#define VLA_NOT_SUPPORTED
#endif
#ifndef VLA_NOT_SUPPORTED
TEST_CASE("Variable Length Array") {
SECTION("deserializeJson()") {
int i = 9;
char vla[i];
strcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeJson(doc, vla);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("deserializeMsgPack()") {
int i = 16;
char vla[i];
memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15);
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeMsgPack(doc, vla);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("JsonVariant") {
DynamicJsonDocument doc;
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "42");
JsonVariant variant = doc.to<JsonVariant>();
variant.set(vla);
REQUIRE(42 == variant.as<int>());
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("operator[]") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
}
#endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("operator[] const") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
}
#endif
SECTION("operator==") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
JsonVariant variant = doc.to<JsonVariant>();
variant.set("hello");
REQUIRE((vla == variant));
REQUIRE((variant == vla));
REQUIRE_FALSE((vla != variant));
REQUIRE_FALSE((variant != vla));
}
SECTION("operator!=") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
JsonVariant variant;
variant.set("world");
REQUIRE((vla != variant));
REQUIRE((variant != vla));
REQUIRE_FALSE((vla == variant));
REQUIRE_FALSE((variant == vla));
}
}
SECTION("JsonObject") {
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("operator[]") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
}
#endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("operator[] const") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[vla]);
}
#endif
SECTION("get()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj.get<char*>(vla));
}
SECTION("set() key") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj.set(vla, "world");
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set() value") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj.set("hello", vla);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set() key&value") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj.set(vla, vla);
REQUIRE(std::string("world") == obj["world"]);
}
SECTION("containsKey()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(true == obj.containsKey(vla));
}
SECTION("remove()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject obj = doc.as<JsonObject>();
obj.remove(vla);
REQUIRE(0 == obj.size());
}
SECTION("is<T>()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":42}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(true == obj.is<int>(vla));
}
SECTION("createNestedArray()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj.createNestedArray(vla);
}
SECTION("createNestedObject()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj.createNestedObject(vla);
}
}
SECTION("JsonObjectSubscript") {
SECTION("operator=") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj["hello"] = vla;
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("set()") {
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj["hello"].set(vla);
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
}
SECTION("JsonArray") {
SECTION("add()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray arr = doc.to<JsonArray>();
arr.add(vla);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray arr = doc.to<JsonArray>();
arr.add("hello");
arr.set(0, vla);
REQUIRE(std::string("world") == arr[0]);
}
}
SECTION("JsonArraySubscript") {
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray arr = doc.to<JsonArray>();
arr.add("hello");
arr[0].set(vla);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("operator=") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray arr = doc.to<JsonArray>();
arr.add("hello");
arr[0] = vla;
REQUIRE(std::string("world") == arr[0]);
}
}
}
#endif

View File

@ -9,10 +9,9 @@ add_executable(MsgPackDeserializerTests
deserializeVariant.cpp deserializeVariant.cpp
doubleToFloat.cpp doubleToFloat.cpp
incompleteInput.cpp incompleteInput.cpp
input_types.cpp
nestingLimit.cpp nestingLimit.cpp
notSupported.cpp notSupported.cpp
std_string.cpp
std_istream.cpp
) )
target_link_libraries(MsgPackDeserializerTests catch) target_link_libraries(MsgPackDeserializerTests catch)

View File

@ -44,3 +44,39 @@ TEST_CASE("deserializeMsgPack(const std::string&)") {
REQUIRE(arr[1] == 2); REQUIRE(arr[1] == 2);
} }
} }
TEST_CASE("deserializeMsgPack(std::istream&)") {
DynamicJsonDocument doc;
SECTION("should accept a zero in input") {
std::istringstream input(std::string("\x92\x00\x02", 3));
DeserializationError err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr[0] == 0);
REQUIRE(arr[1] == 2);
}
SECTION("should detect incomplete input") {
std::istringstream input("\x92\x00\x02");
DeserializationError err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
TEST_CASE("deserializeMsgPack(VLA)") {
int i = 16;
char vla[i];
memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15);
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeMsgPack(doc, vla);
REQUIRE(err == DeserializationError::Ok);
}
#endif

View File

@ -1,29 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserializeMsgPack(std::istream&)") {
DynamicJsonDocument doc;
SECTION("should accept a zero in input") {
std::istringstream input(std::string("\x92\x00\x02", 3));
DeserializationError err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::Ok);
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr[0] == 0);
REQUIRE(arr[1] == 2);
}
SECTION("should detect incomplete input") {
std::istringstream input("\x92\x00\x02");
DeserializationError err = deserializeMsgPack(doc, input);
REQUIRE(err == DeserializationError::IncompleteInput);
}
}