diff --git a/src/ArduinoJson/JsonVariant.hpp b/src/ArduinoJson/JsonVariant.hpp index 6bed8d84..5c08af85 100644 --- a/src/ArduinoJson/JsonVariant.hpp +++ b/src/ArduinoJson/JsonVariant.hpp @@ -127,23 +127,28 @@ class JsonVariant : public Internals::JsonVariantBase { } } + // set(char*) + template + bool set(T *value, + typename Internals::enable_if::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(value)); - } - // set(const signed char*); - // set(const signed char[n]); // VLA - bool set(const signed char *value) { - return set(reinterpret_cast(value)); - } bool set(const JsonVariant &value) { if (!_data) return false; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 82e90a31..8c8cd6ff 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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() diff --git a/test/JsonArray/add.cpp b/test/JsonArray/add.cpp index dd79134f..50fd77d4 100644 --- a/test/JsonArray/add.cpp +++ b/test/JsonArray/add.cpp @@ -7,57 +7,69 @@ TEST_CASE("JsonArray::add()") { DynamicJsonDocument doc; - JsonArray _array = doc.to(); + JsonArray array = doc.to(); SECTION("int") { - _array.add(123); - REQUIRE(123 == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE(_array[0].is()); + array.add(123); + REQUIRE(123 == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE(array[0].is()); } SECTION("double") { - _array.add(123.45); - REQUIRE(123.45 == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.add(123.45); + REQUIRE(123.45 == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("bool") { - _array.add(true); - REQUIRE(true == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.add(true); + REQUIRE(true == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("const char*") { const char* str = "hello"; - _array.add(str); - REQUIRE(str == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.add(str); + REQUIRE(str == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } +#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(); - _array.add(arr); + array.add(arr); - REQUIRE(arr == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + REQUIRE(arr == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("nested object") { DynamicJsonDocument doc2; JsonObject obj = doc2.to(); - _array.add(obj); + array.add(obj); - REQUIRE(obj == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + REQUIRE(obj == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("array subscript") { @@ -66,9 +78,9 @@ TEST_CASE("JsonArray::add()") { JsonArray arr = doc2.to(); 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(); 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("world")); + array.add(const_cast("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("{}"))); + array.add(serialized(const_cast("{}"))); 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()); } diff --git a/test/JsonArray/set.cpp b/test/JsonArray/set.cpp index b434bf13..50466db6 100644 --- a/test/JsonArray/set.cpp +++ b/test/JsonArray/set.cpp @@ -9,57 +9,70 @@ using namespace Catch::Matchers; TEST_CASE("JsonArray::set()") { DynamicJsonDocument doc; - JsonArray _array = doc.to(); - _array.add(0); + JsonArray array = doc.to(); + array.add(0); SECTION("int") { - _array.set(0, 123); - REQUIRE(123 == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.set(0, 123); + REQUIRE(123 == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("double") { - _array.set(0, 123.45); - REQUIRE(123.45 == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.set(0, 123.45); + REQUIRE(123.45 == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("bool") { - _array.set(0, true); - REQUIRE(true == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.set(0, true); + REQUIRE(true == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("const char*") { - _array.set(0, "hello"); - REQUIRE_THAT(_array[0].as(), Equals("hello")); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + array.set(0, "hello"); + REQUIRE_THAT(array[0].as(), Equals("hello")); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } +#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(); - _array.set(0, arr); + array.set(0, arr); - REQUIRE(arr == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + REQUIRE(arr == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("nested object") { DynamicJsonDocument doc2; JsonObject obj = doc2.to(); - _array.set(0, obj); + array.set(0, obj); - REQUIRE(obj == _array[0].as()); - REQUIRE(_array[0].is()); - REQUIRE_FALSE(_array[0].is()); + REQUIRE(obj == array[0].as()); + REQUIRE(array[0].is()); + REQUIRE_FALSE(array[0].is()); } SECTION("array subscript") { @@ -67,9 +80,9 @@ TEST_CASE("JsonArray::set()") { JsonArray arr = doc2.to(); arr.add("hello"); - _array.set(0, arr[0]); + array.set(0, arr[0]); - REQUIRE_THAT(_array[0].as(), Equals("hello")); + REQUIRE_THAT(array[0].as(), Equals("hello")); } SECTION("object subscript") { @@ -77,25 +90,25 @@ TEST_CASE("JsonArray::set()") { JsonObject obj = doc2.to(); obj["x"] = "hello"; - _array.set(0, obj["x"]); + array.set(0, obj["x"]); - REQUIRE_THAT(_array[0].as(), Equals("hello")); + REQUIRE_THAT(array[0].as(), 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("world")); + array.set(0, const_cast("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()); } diff --git a/test/JsonArray/subscript.cpp b/test/JsonArray/subscript.cpp index 35040d10..6f06741c 100644 --- a/test/JsonArray/subscript.cpp +++ b/test/JsonArray/subscript.cpp @@ -8,85 +8,85 @@ TEST_CASE("JsonArray::operator[]") { DynamicJsonDocument doc; - JsonArray _array = doc.to(); - _array.add(0); + JsonArray array = doc.to(); + array.add(0); SECTION("int") { - _array[0] = 123; - REQUIRE(123 == _array[0].as()); - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + array[0] = 123; + REQUIRE(123 == array[0].as()); + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 SECTION("long long") { - _array[0] = 9223372036854775807; - REQUIRE(9223372036854775807 == _array[0].as()); - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + array[0] = 9223372036854775807; + REQUIRE(9223372036854775807 == array[0].as()); + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } #endif SECTION("double") { - _array[0] = 123.45; - REQUIRE(123.45 == _array[0].as()); - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + array[0] = 123.45; + REQUIRE(123.45 == array[0].as()); + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } SECTION("bool") { - _array[0] = true; - REQUIRE(true == _array[0].as()); - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + array[0] = true; + REQUIRE(true == array[0].as()); + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } SECTION("const char*") { const char* str = "hello"; - _array[0] = str; - REQUIRE(str == _array[0].as()); - REQUIRE(str == _array[0].as()); // <- short hand - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + array[0] = str; + REQUIRE(str == array[0].as()); + REQUIRE(str == array[0].as()); // <- short hand + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } SECTION("nested array") { DynamicJsonDocument doc2; - JsonArray arr = doc2.to(); + JsonArray arr2 = doc2.to(); - _array[0] = arr; + array[0] = arr2; - REQUIRE(arr == _array[0].as()); - REQUIRE(arr == _array[0].as()); // <- short hand - // REQUIRE(arr == _array[0].as()); - // REQUIRE(arr == _array[0].as()); // <- short hand - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + REQUIRE(arr2 == array[0].as()); + REQUIRE(arr2 == array[0].as()); // <- short hand + // REQUIRE(arr2 == array[0].as()); + // REQUIRE(arr2 == array[0].as()); // <- short hand + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } SECTION("nested object") { DynamicJsonDocument doc2; JsonObject obj = doc2.to(); - _array[0] = obj; + array[0] = obj; - REQUIRE(obj == _array[0].as()); - REQUIRE(obj == _array[0].as()); // <- short hand - REQUIRE(true == _array[0].is()); - REQUIRE(false == _array[0].is()); + REQUIRE(obj == array[0].as()); + REQUIRE(obj == array[0].as()); // <- short hand + REQUIRE(true == array[0].is()); + REQUIRE(false == array[0].is()); } SECTION("array subscript") { DynamicJsonDocument doc2; - JsonArray arr = doc2.to(); + JsonArray arr2 = doc2.to(); 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("world"); + array[0] = const_cast("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 } diff --git a/test/JsonDeserializer/CMakeLists.txt b/test/JsonDeserializer/CMakeLists.txt index 5624ffdd..9508082a 100644 --- a/test/JsonDeserializer/CMakeLists.txt +++ b/test/JsonDeserializer/CMakeLists.txt @@ -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) diff --git a/test/JsonDeserializer/std_istream.cpp b/test/JsonDeserializer/input_types.cpp similarity index 62% rename from test/JsonDeserializer/std_istream.cpp rename to test/JsonDeserializer/input_types.cpp index 8f698389..9bf9efc7 100644 --- a/test/JsonDeserializer/std_istream.cpp +++ b/test/JsonDeserializer/input_types.cpp @@ -6,6 +6,35 @@ #include #include +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(); + 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 doc; + DeserializationError err = deserializeJson(doc, vla); + + REQUIRE(err == DeserializationError::Ok); +} +#endif diff --git a/test/JsonDeserializer/std_string.cpp b/test/JsonDeserializer/std_string.cpp deleted file mode 100644 index f15063b3..00000000 --- a/test/JsonDeserializer/std_string.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -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(); - REQUIRE(err == DeserializationError::Ok); - REQUIRE(std::string("hello") == array[0]); - } -} diff --git a/test/JsonObject/CMakeLists.txt b/test/JsonObject/CMakeLists.txt index 7ddab023..b4f03f52 100644 --- a/test/JsonObject/CMakeLists.txt +++ b/test/JsonObject/CMakeLists.txt @@ -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 diff --git a/test/JsonObject/containsKey.cpp b/test/JsonObject/containsKey.cpp index d8cba0c0..43776219 100644 --- a/test/JsonObject/containsKey.cpp +++ b/test/JsonObject/containsKey.cpp @@ -8,23 +8,29 @@ TEST_CASE("JsonObject::containsKey()") { DynamicJsonDocument doc; JsonObject obj = doc.to(); + obj.set("hello", 42); - 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 } diff --git a/test/JsonObject/createNestedArray.cpp b/test/JsonObject/createNestedArray.cpp new file mode 100644 index 00000000..36fe5408 --- /dev/null +++ b/test/JsonObject/createNestedArray.cpp @@ -0,0 +1,25 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("JsonObject::createNestedArray()") { + DynamicJsonDocument doc; + JsonObject obj = doc.to(); + + 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 +} diff --git a/test/JsonObject/createNestedObject.cpp b/test/JsonObject/createNestedObject.cpp new file mode 100644 index 00000000..26e8080c --- /dev/null +++ b/test/JsonObject/createNestedObject.cpp @@ -0,0 +1,25 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("JsonObject::createNestedObject()") { + DynamicJsonDocument doc; + JsonObject obj = doc.to(); + + 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 +} diff --git a/test/JsonObject/get.cpp b/test/JsonObject/get.cpp index 11182dff..b3b8dc67 100644 --- a/test/JsonObject/get.cpp +++ b/test/JsonObject/get.cpp @@ -11,9 +11,20 @@ TEST_CASE("JsonObject::get()") { DynamicJsonDocument doc; JsonObject obj = doc.to(); - SECTION("GetConstCharPointer_GivenStringLiteral") { + SECTION("get(const char*)") { obj.set("hello", "world"); const char* value = obj.get("hello"); REQUIRE_THAT(value, Equals("world")); } + +#ifdef HAS_VARIABLE_LENGTH_ARRAY + SECTION("get(VLA)") { + obj.set("hello", "world"); + int i = 16; + char vla[i]; + strcpy(vla, "hello"); + + REQUIRE(std::string("world") == obj.get(vla)); + } +#endif } diff --git a/test/JsonObject/is.cpp b/test/JsonObject/is.cpp new file mode 100644 index 00000000..eef4a441 --- /dev/null +++ b/test/JsonObject/is.cpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("JsonObject::is()") { + DynamicJsonDocument doc; + JsonObject obj = doc.to(); + obj["int"] = 42; + obj["str"] = "hello"; + + SECTION("is(const char*)") { + REQUIRE(true == obj.is("int")); + REQUIRE(false == obj.is("str")); + } + +#if HAS_VARIABLE_LENGTH_ARRAY + SECTION("is(VLA)") { + int i = 16; + char vla[i]; + strcpy(vla, "int"); + + REQUIRE(true == obj.is(vla)); + } +#endif +} diff --git a/test/JsonObject/remove.cpp b/test/JsonObject/remove.cpp index fc815651..30ef04a0 100644 --- a/test/JsonObject/remove.cpp +++ b/test/JsonObject/remove.cpp @@ -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 } diff --git a/test/JsonObject/set.cpp b/test/JsonObject/set.cpp index 7427d554..d8d84ff6 100644 --- a/test/JsonObject/set.cpp +++ b/test/JsonObject/set.cpp @@ -42,6 +42,38 @@ TEST_CASE("JsonObject::set()") { REQUIRE_FALSE(obj["hello"].is()); } +#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(); diff --git a/test/JsonObject/subscript.cpp b/test/JsonObject/subscript.cpp index 82f5a17d..02c8cfa2 100644 --- a/test/JsonObject/subscript.cpp +++ b/test/JsonObject/subscript.cpp @@ -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()); + } + + 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()); + } + + SECTION("obj[VLA]") { + int i = 16; + char vla[i]; + strcpy(vla, "hello"); + + deserializeJson(doc, "{\"hello\":\"world\"}"); + + obj = doc.as(); + REQUIRE(std::string("world") == obj[vla]); + } +#endif } diff --git a/test/JsonVariant/compare.cpp b/test/JsonVariant/compare.cpp index a14087af..09017c6c 100644 --- a/test/JsonVariant/compare.cpp +++ b/test/JsonVariant/compare.cpp @@ -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(); + 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(); + 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 variant2 = doc2.to(); diff --git a/test/JsonVariant/set_get.cpp b/test/JsonVariant/set_get.cpp index 883c0e91..9ab526f5 100644 --- a/test/JsonVariant/set_get.cpp +++ b/test/JsonVariant/set_get.cpp @@ -138,3 +138,74 @@ TEST_CASE("JsonVariant set()/get()") { checkValue(object); } } + +TEST_CASE("JsonVariant and strings") { + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + + SECTION("stores const char* by reference") { + char str[16]; + + strcpy(str, "hello"); + variant.set(static_cast(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(str)); + strcpy(str, "world"); + + REQUIRE(variant == "hello"); + } + + SECTION("stores signed char* by copy") { + char str[16]; + + strcpy(str, "hello"); + variant.set(reinterpret_cast(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() +} diff --git a/test/JsonVariant/subscript.cpp b/test/JsonVariant/subscript.cpp index 9a94d1cf..0a3b3764 100644 --- a/test/JsonVariant/subscript.cpp +++ b/test/JsonVariant/subscript.cpp @@ -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(); + + 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(); + + REQUIRE(std::string("world") == variant[vla]); + } +#endif } diff --git a/test/Misc/CMakeLists.txt b/test/Misc/CMakeLists.txt index e18e1937..b1667d98 100644 --- a/test/Misc/CMakeLists.txt +++ b/test/Misc/CMakeLists.txt @@ -8,7 +8,6 @@ add_executable(MiscTests TypeTraits.cpp unsigned_char.cpp version.cpp - vla.cpp ) target_link_libraries(MiscTests catch) diff --git a/test/Misc/vla.cpp b/test/Misc/vla.cpp deleted file mode 100644 index 4ed5e306..00000000 --- a/test/Misc/vla.cpp +++ /dev/null @@ -1,327 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -#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 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 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(); - variant.set(vla); - - REQUIRE(42 == variant.as()); - } - -#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR - SECTION("operator[]") { - int i = 16; - char vla[i]; - strcpy(vla, "hello"); - - deserializeJson(doc, "{\"hello\":\"world\"}"); - JsonVariant variant = doc.as(); - - 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(); - - REQUIRE(std::string("world") == variant[vla]); - } -#endif - - SECTION("operator==") { - int i = 16; - char vla[i]; - strcpy(vla, "hello"); - - JsonVariant variant = doc.to(); - 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(); - 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(); - 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(); - REQUIRE(std::string("world") == obj.get(vla)); - } - - SECTION("set() key") { - int i = 16; - char vla[i]; - strcpy(vla, "hello"); - - DynamicJsonDocument doc; - JsonObject obj = doc.to(); - 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(); - 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(); - 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(); - 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(); - obj.remove(vla); - - REQUIRE(0 == obj.size()); - } - - SECTION("is()") { - int i = 16; - char vla[i]; - strcpy(vla, "hello"); - - DynamicJsonDocument doc; - deserializeJson(doc, "{\"hello\":42}"); - JsonObject obj = doc.as(); - - REQUIRE(true == obj.is(vla)); - } - - SECTION("createNestedArray()") { - int i = 16; - char vla[i]; - strcpy(vla, "hello"); - - DynamicJsonDocument doc; - JsonObject obj = doc.to(); - obj.createNestedArray(vla); - } - - SECTION("createNestedObject()") { - int i = 16; - char vla[i]; - strcpy(vla, "hello"); - - DynamicJsonDocument doc; - JsonObject obj = doc.to(); - obj.createNestedObject(vla); - } - } - - SECTION("JsonObjectSubscript") { - SECTION("operator=") { // issue #416 - int i = 32; - char vla[i]; - strcpy(vla, "world"); - - DynamicJsonDocument doc; - JsonObject obj = doc.to(); - obj["hello"] = vla; - - REQUIRE(std::string("world") == obj["hello"].as()); - } - - SECTION("set()") { - int i = 32; - char vla[i]; - strcpy(vla, "world"); - - DynamicJsonDocument doc; - JsonObject obj = doc.to(); - obj["hello"].set(vla); - - REQUIRE(std::string("world") == obj["hello"].as()); - } - } - - SECTION("JsonArray") { - SECTION("add()") { - int i = 16; - char vla[i]; - strcpy(vla, "world"); - - DynamicJsonDocument doc; - JsonArray arr = doc.to(); - 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(); - 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(); - 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(); - arr.add("hello"); - arr[0] = vla; - - REQUIRE(std::string("world") == arr[0]); - } - } -} -#endif diff --git a/test/MsgPackDeserializer/CMakeLists.txt b/test/MsgPackDeserializer/CMakeLists.txt index c5c8d238..057ff099 100644 --- a/test/MsgPackDeserializer/CMakeLists.txt +++ b/test/MsgPackDeserializer/CMakeLists.txt @@ -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) diff --git a/test/MsgPackDeserializer/std_string.cpp b/test/MsgPackDeserializer/input_types.cpp similarity index 57% rename from test/MsgPackDeserializer/std_string.cpp rename to test/MsgPackDeserializer/input_types.cpp index f04b8183..ccd33577 100644 --- a/test/MsgPackDeserializer/std_string.cpp +++ b/test/MsgPackDeserializer/input_types.cpp @@ -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(); + 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 doc; + DeserializationError err = deserializeMsgPack(doc, vla); + + REQUIRE(err == DeserializationError::Ok); +} +#endif diff --git a/test/MsgPackDeserializer/std_istream.cpp b/test/MsgPackDeserializer/std_istream.cpp deleted file mode 100644 index cae588fc..00000000 --- a/test/MsgPackDeserializer/std_istream.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -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(); - 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); - } -}