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[n]); // VLA
bool set(const char *value) {
if (!_data) return false;
_data->setString(value);
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) {
if (!_data) return false;

View File

@ -38,7 +38,9 @@ endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(
-Wstrict-null-sentinel
-Wno-vla # Allow VLA in tests
)
add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
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(
-Wc++11-compat
-Wdeprecated-register
-Wno-vla-extension # Allow VLA in tests
)
add_definitions(
-DHAS_VARIABLE_LENGTH_ARRAY
-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
)
endif()

View File

@ -7,57 +7,69 @@
TEST_CASE("JsonArray::add()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
JsonArray array = doc.to<JsonArray>();
SECTION("int") {
_array.add(123);
REQUIRE(123 == _array[0].as<int>());
REQUIRE(_array[0].is<int>());
REQUIRE(_array[0].is<double>());
array.add(123);
REQUIRE(123 == array[0].as<int>());
REQUIRE(array[0].is<int>());
REQUIRE(array[0].is<double>());
}
SECTION("double") {
_array.add(123.45);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<bool>());
array.add(123.45);
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(array[0].is<double>());
REQUIRE_FALSE(array[0].is<bool>());
}
SECTION("bool") {
_array.add(true);
REQUIRE(true == _array[0].as<bool>());
REQUIRE(_array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>());
array.add(true);
REQUIRE(true == array[0].as<bool>());
REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("const char*") {
const char* str = "hello";
_array.add(str);
REQUIRE(str == _array[0].as<std::string>());
REQUIRE(_array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>());
array.add(str);
REQUIRE(str == array[0].as<std::string>());
REQUIRE(array[0].is<const char*>());
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") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
_array.add(arr);
array.add(arr);
REQUIRE(arr == _array[0].as<JsonArray>());
REQUIRE(_array[0].is<JsonArray>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
_array.add(obj);
array.add(obj);
REQUIRE(obj == _array[0].as<JsonObject>());
REQUIRE(_array[0].is<JsonObject>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("array subscript") {
@ -66,9 +78,9 @@ TEST_CASE("JsonArray::add()") {
JsonArray arr = doc2.to<JsonArray>();
arr.add(str);
_array.add(arr[0]);
array.add(arr[0]);
REQUIRE(str == _array[0]);
REQUIRE(str == array[0]);
}
SECTION("object subscript") {
@ -77,49 +89,49 @@ TEST_CASE("JsonArray::add()") {
JsonObject obj = doc2.to<JsonObject>();
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*") {
_array.add("world");
array.add("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
_array.add(std::string("world"));
array.add(std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should not duplicate serialized(const char*)") {
_array.add(serialized("{}"));
array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}

View File

@ -9,57 +9,70 @@ using namespace Catch::Matchers;
TEST_CASE("JsonArray::set()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
_array.add(0);
JsonArray array = doc.to<JsonArray>();
array.add(0);
SECTION("int") {
_array.set(0, 123);
REQUIRE(123 == _array[0].as<int>());
REQUIRE(_array[0].is<int>());
REQUIRE_FALSE(_array[0].is<bool>());
array.set(0, 123);
REQUIRE(123 == array[0].as<int>());
REQUIRE(array[0].is<int>());
REQUIRE_FALSE(array[0].is<bool>());
}
SECTION("double") {
_array.set(0, 123.45);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<int>());
array.set(0, 123.45);
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(array[0].is<double>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("bool") {
_array.set(0, true);
REQUIRE(true == _array[0].as<bool>());
REQUIRE(_array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>());
array.set(0, true);
REQUIRE(true == array[0].as<bool>());
REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("const char*") {
_array.set(0, "hello");
REQUIRE_THAT(_array[0].as<const char*>(), Equals("hello"));
REQUIRE(_array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>());
array.set(0, "hello");
REQUIRE_THAT(array[0].as<const char*>(), Equals("hello"));
REQUIRE(array[0].is<const char*>());
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") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
_array.set(0, arr);
array.set(0, arr);
REQUIRE(arr == _array[0].as<JsonArray>());
REQUIRE(_array[0].is<JsonArray>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
_array.set(0, obj);
array.set(0, obj);
REQUIRE(obj == _array[0].as<JsonObject>());
REQUIRE(_array[0].is<JsonObject>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("array subscript") {
@ -67,9 +80,9 @@ TEST_CASE("JsonArray::set()") {
JsonArray arr = doc2.to<JsonArray>();
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") {
@ -77,25 +90,25 @@ TEST_CASE("JsonArray::set()") {
JsonObject obj = doc2.to<JsonObject>();
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*") {
_array.set(0, "world");
array.set(0, "world");
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}

View File

@ -8,85 +8,85 @@
TEST_CASE("JsonArray::operator[]") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
_array.add(0);
JsonArray array = doc.to<JsonArray>();
array.add(0);
SECTION("int") {
_array[0] = 123;
REQUIRE(123 == _array[0].as<int>());
REQUIRE(true == _array[0].is<int>());
REQUIRE(false == _array[0].is<bool>());
array[0] = 123;
REQUIRE(123 == array[0].as<int>());
REQUIRE(true == array[0].is<int>());
REQUIRE(false == array[0].is<bool>());
}
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
SECTION("long long") {
_array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == _array[0].as<long long>());
REQUIRE(true == _array[0].is<int>());
REQUIRE(false == _array[0].is<bool>());
array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == array[0].as<long long>());
REQUIRE(true == array[0].is<int>());
REQUIRE(false == array[0].is<bool>());
}
#endif
SECTION("double") {
_array[0] = 123.45;
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(true == _array[0].is<double>());
REQUIRE(false == _array[0].is<int>());
array[0] = 123.45;
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(true == array[0].is<double>());
REQUIRE(false == array[0].is<int>());
}
SECTION("bool") {
_array[0] = true;
REQUIRE(true == _array[0].as<bool>());
REQUIRE(true == _array[0].is<bool>());
REQUIRE(false == _array[0].is<int>());
array[0] = true;
REQUIRE(true == array[0].as<bool>());
REQUIRE(true == array[0].is<bool>());
REQUIRE(false == array[0].is<int>());
}
SECTION("const char*") {
const char* str = "hello";
_array[0] = str;
REQUIRE(str == _array[0].as<const char*>());
REQUIRE(str == _array[0].as<char*>()); // <- short hand
REQUIRE(true == _array[0].is<const char*>());
REQUIRE(false == _array[0].is<int>());
array[0] = str;
REQUIRE(str == array[0].as<const char*>());
REQUIRE(str == array[0].as<char*>()); // <- short hand
REQUIRE(true == array[0].is<const char*>());
REQUIRE(false == array[0].is<int>());
}
SECTION("nested array") {
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(arr == _array[0].as<JsonArray>()); // <- short hand
// REQUIRE(arr == _array[0].as<const JsonArray>());
// REQUIRE(arr == _array[0].as<const JsonArray>()); // <- short hand
REQUIRE(true == _array[0].is<JsonArray>());
REQUIRE(false == _array[0].is<int>());
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>());
}
SECTION("nested object") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
_array[0] = obj;
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>());
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>());
}
SECTION("array subscript") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
JsonArray arr2 = doc2.to<JsonArray>();
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") {
@ -96,26 +96,50 @@ TEST_CASE("JsonArray::operator[]") {
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*") {
_array[0] = "world";
array[0] = "world";
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
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;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
_array[0] = std::string("world");
array[0] = std::string("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
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
add_executable(JsonDeserializerTests
DeserializationError.cpp
deserializeJsonArray.cpp
deserializeJsonArrayStatic.cpp
deserializeJsonObject.cpp
deserializeJsonObjectStatic.cpp
deserializeJsonValue.cpp
DeserializationError.cpp
input_types.cpp
nestingLimit.cpp
std_istream.cpp
std_string.cpp
)
target_link_libraries(JsonDeserializerTests catch)

View File

@ -6,6 +6,35 @@
#include <catch.hpp>
#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&)") {
DynamicJsonDocument doc;
@ -71,3 +100,16 @@ TEST_CASE("deserializeJson(std::istream&)") {
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
containsKey.cpp
createNestedArray.cpp
createNestedObject.cpp
get.cpp
invalid.cpp
is.cpp
isNull.cpp
iterator.cpp
remove.cpp

View File

@ -8,23 +8,29 @@
TEST_CASE("JsonObject::containsKey()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("ContainsKeyReturnsFalseForNonExistingKey") {
obj.set("hello", 42);
SECTION("returns false if key not present") {
REQUIRE(false == obj.containsKey("world"));
}
SECTION("ContainsKeyReturnsTrueForDefinedValue") {
obj.set("hello", 42);
SECTION("returns true if key present") {
REQUIRE(true == obj.containsKey("hello"));
}
SECTION("ContainsKeyReturnsFalseAfterRemove") {
obj.set("hello", 42);
SECTION("returns false after remove()") {
obj.remove("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;
JsonObject obj = doc.to<JsonObject>();
SECTION("GetConstCharPointer_GivenStringLiteral") {
SECTION("get<const char*>(const char*)") {
obj.set("hello", "world");
const char* value = obj.get<const char*>("hello");
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);
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>());
}
#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") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();

View File

@ -159,4 +159,58 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(obj.size() == 1);
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);
}
#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;
JsonVariant variant1 = doc1.to<JsonVariant>();
JsonVariant variant2 = doc2.to<JsonVariant>();

View File

@ -138,3 +138,74 @@ TEST_CASE("JsonVariant set()/get()") {
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"]);
}
}
#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
unsigned_char.cpp
version.cpp
vla.cpp
)
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
doubleToFloat.cpp
incompleteInput.cpp
input_types.cpp
nestingLimit.cpp
notSupported.cpp
std_string.cpp
std_istream.cpp
)
target_link_libraries(MsgPackDeserializerTests catch)

View File

@ -44,3 +44,39 @@ TEST_CASE("deserializeMsgPack(const std::string&)") {
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);
}
}