mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fixed result of JsonVariant::set((char*)0) (fixes #1368)
				
					
				
			This commit is contained in:
		| @@ -6,6 +6,7 @@ HEAD | |||||||
|  |  | ||||||
| * Added a build failure when nullptr is defined as a macro (issue #1355) | * Added a build failure when nullptr is defined as a macro (issue #1355) | ||||||
| * Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358) | * Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358) | ||||||
|  | * Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368) | ||||||
|  |  | ||||||
| v6.16.1 (2020-08-04) | v6.16.1 (2020-08-04) | ||||||
| ------- | ------- | ||||||
|   | |||||||
| @@ -7,115 +7,150 @@ | |||||||
|  |  | ||||||
| enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 }; | enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 }; | ||||||
|  |  | ||||||
| TEST_CASE("JsonVariant and strings") { | TEST_CASE("JsonVariant::set() when there is enough memory") { | ||||||
|   DynamicJsonDocument doc(4096); |   DynamicJsonDocument doc(4096); | ||||||
|   JsonVariant variant = doc.to<JsonVariant>(); |   JsonVariant variant = doc.to<JsonVariant>(); | ||||||
|  |  | ||||||
|   SECTION("stores const char* by reference") { |   SECTION("const char*") { | ||||||
|     char str[16]; |     char str[16]; | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     strcpy(str, "hello"); | ||||||
|     variant.set(static_cast<const char *>(str)); |     bool result = variant.set(static_cast<const char *>(str)); | ||||||
|     strcpy(str, "world"); |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "world"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "world");  // stores by pointer | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("stores char* by copy") { |   SECTION("(const char*)0") { | ||||||
|     char str[16]; |     bool result = variant.set(static_cast<const char *>(0)); | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     REQUIRE(result == true); | ||||||
|     variant.set(str); |     REQUIRE(variant.isNull()); | ||||||
|     strcpy(str, "world"); |  | ||||||
|  |  | ||||||
|     REQUIRE(variant == "hello"); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("stores unsigned char* by copy") { |   SECTION("char*") { | ||||||
|     char str[16]; |     char str[16]; | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     strcpy(str, "hello"); | ||||||
|     variant.set(reinterpret_cast<unsigned char *>(str)); |     bool result = variant.set(str); | ||||||
|     strcpy(str, "world"); |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "hello"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "hello");  // stores by copy | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("stores signed char* by copy") { |   SECTION("(char*)0") { | ||||||
|  |     bool result = variant.set(static_cast<char *>(0)); | ||||||
|  |  | ||||||
|  |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant.isNull()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SECTION("unsigned char*") { | ||||||
|     char str[16]; |     char str[16]; | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     strcpy(str, "hello"); | ||||||
|     variant.set(reinterpret_cast<signed char *>(str)); |     bool result = variant.set(reinterpret_cast<unsigned char *>(str)); | ||||||
|     strcpy(str, "world"); |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "hello"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "hello");  // stores by copy | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SECTION("signed char*") { | ||||||
|  |     char str[16]; | ||||||
|  |  | ||||||
|  |     strcpy(str, "hello"); | ||||||
|  |     bool result = variant.set(reinterpret_cast<signed char *>(str)); | ||||||
|  |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|  |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "hello");  // stores by copy | ||||||
|   } |   } | ||||||
|  |  | ||||||
| #ifdef HAS_VARIABLE_LENGTH_ARRAY | #ifdef HAS_VARIABLE_LENGTH_ARRAY | ||||||
|   SECTION("stores VLA by copy") { |   SECTION("VLA") { | ||||||
|     int n = 16; |     int n = 16; | ||||||
|     char str[n]; |     char str[n]; | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     strcpy(str, "hello"); | ||||||
|     variant.set(str); |     bool result = variant.set(str); | ||||||
|     strcpy(str, "world"); |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "hello"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "hello");  // stores by copy | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   SECTION("stores std::string by copy") { |   SECTION("std::string") { | ||||||
|     std::string str; |     std::string str; | ||||||
|  |  | ||||||
|     str = "hello"; |     str = "hello"; | ||||||
|     variant.set(str); |     bool result = variant.set(str); | ||||||
|     str.replace(0, 5, "world"); |     str.replace(0, 5, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "hello"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "hello");  // stores by copy | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("stores static JsonString by reference") { |   SECTION("static JsonString") { | ||||||
|     char str[16]; |     char str[16]; | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     strcpy(str, "hello"); | ||||||
|     variant.set(JsonString(str, true)); |     bool result = variant.set(JsonString(str, true)); | ||||||
|     strcpy(str, "world"); |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "world"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "world");  // stores by pointer | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("stores non-static JsonString by copy") { |   SECTION("non-static JsonString") { | ||||||
|     char str[16]; |     char str[16]; | ||||||
|  |  | ||||||
|     strcpy(str, "hello"); |     strcpy(str, "hello"); | ||||||
|     variant.set(JsonString(str, false)); |     bool result = variant.set(JsonString(str, false)); | ||||||
|     strcpy(str, "world"); |     strcpy(str, "world"); | ||||||
|  |  | ||||||
|     REQUIRE(variant == "hello"); |     REQUIRE(result == true); | ||||||
|  |     REQUIRE(variant == "hello");  // stores by copy | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("stores an enum as an integer") { |   SECTION("enum") { | ||||||
|     ErrorCode code = ERROR_10; |     ErrorCode code = ERROR_10; | ||||||
|  |  | ||||||
|     variant.set(code); |     bool result = variant.set(code); | ||||||
|  |  | ||||||
|  |     REQUIRE(result == true); | ||||||
|     REQUIRE(variant.is<int>() == true); |     REQUIRE(variant.is<int>() == true); | ||||||
|     REQUIRE(variant.as<int>() == 10); |     REQUIRE(variant.as<int>() == 10); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST_CASE("JsonVariant with not enough memory") { | TEST_CASE("JsonVariant::set() with not enough memory") { | ||||||
|   StaticJsonDocument<1> doc; |   StaticJsonDocument<1> doc; | ||||||
|  |  | ||||||
|   JsonVariant v = doc.to<JsonVariant>(); |   JsonVariant v = doc.to<JsonVariant>(); | ||||||
|  |  | ||||||
|   SECTION("std::string") { |   SECTION("std::string") { | ||||||
|     v.set(std::string("hello world!!")); |     bool result = v.set(std::string("hello world!!")); | ||||||
|  |  | ||||||
|  |     REQUIRE(result == false); | ||||||
|     REQUIRE(v.isNull()); |     REQUIRE(v.isNull()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("Serialized<std::string>") { |   SECTION("Serialized<std::string>") { | ||||||
|     v.set(serialized(std::string("hello world!!"))); |     bool result = v.set(serialized(std::string("hello world!!"))); | ||||||
|  |  | ||||||
|  |     REQUIRE(result == false); | ||||||
|  |     REQUIRE(v.isNull()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SECTION("char*") { | ||||||
|  |     char s[] = "hello world!!"; | ||||||
|  |     bool result = v.set(s); | ||||||
|  |  | ||||||
|  |     REQUIRE(result == false); | ||||||
|     REQUIRE(v.isNull()); |     REQUIRE(v.isNull()); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -347,8 +347,7 @@ class JsonDeserializer { | |||||||
|     if (!parseQuotedString()) |     if (!parseQuotedString()) | ||||||
|       return false; |       return false; | ||||||
|     const char *value = _stringStorage.save(); |     const char *value = _stringStorage.save(); | ||||||
|     variant.setString(make_not_null(value), |     variant.setStringPointer(value, typename TStringStorage::storage_policy()); | ||||||
|                       typename TStringStorage::storage_policy()); |  | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -233,8 +233,7 @@ class MsgPackDeserializer { | |||||||
|     const char *s = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR) |     const char *s = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR) | ||||||
|     if (!readString(s, n)) |     if (!readString(s, n)) | ||||||
|       return false; |       return false; | ||||||
|     variant.setString(make_not_null(s), |     variant.setStringPointer(s, typename TStringStorage::storage_policy()); | ||||||
|                       typename TStringStorage::storage_policy()); |  | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,34 +0,0 @@ | |||||||
| // ArduinoJson - arduinojson.org |  | ||||||
| // Copyright Benoit Blanchon 2014-2020 |  | ||||||
| // MIT License |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <ArduinoJson/Namespace.hpp> |  | ||||||
| #include <ArduinoJson/Polyfills/assert.hpp> |  | ||||||
|  |  | ||||||
| namespace ARDUINOJSON_NAMESPACE { |  | ||||||
|  |  | ||||||
| template <typename T> |  | ||||||
| class not_null { |  | ||||||
|  public: |  | ||||||
|   explicit not_null(T ptr) : _ptr(ptr) { |  | ||||||
|     ARDUINOJSON_ASSERT(ptr != NULL); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   T get() const { |  | ||||||
|     ARDUINOJSON_ASSERT(_ptr != NULL); |  | ||||||
|     return _ptr; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  private: |  | ||||||
|   T _ptr; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| template <typename T> |  | ||||||
| not_null<T> make_not_null(T ptr) { |  | ||||||
|   ARDUINOJSON_ASSERT(ptr != NULL); |  | ||||||
|   return not_null<T>(ptr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE |  | ||||||
| @@ -7,7 +7,6 @@ | |||||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||||
| #include <ArduinoJson/Misc/SerializedValue.hpp> | #include <ArduinoJson/Misc/SerializedValue.hpp> | ||||||
| #include <ArduinoJson/Numbers/convertNumber.hpp> | #include <ArduinoJson/Numbers/convertNumber.hpp> | ||||||
| #include <ArduinoJson/Polyfills/gsl/not_null.hpp> |  | ||||||
| #include <ArduinoJson/Strings/RamStringAdapter.hpp> | #include <ArduinoJson/Strings/RamStringAdapter.hpp> | ||||||
| #include <ArduinoJson/Variant/VariantContent.hpp> | #include <ArduinoJson/Variant/VariantContent.hpp> | ||||||
|  |  | ||||||
| @@ -245,25 +244,14 @@ class VariantData { | |||||||
|     setType(VALUE_IS_NULL); |     setType(VALUE_IS_NULL); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void setString(not_null<const char *> s, storage_policies::store_by_copy) { |   void setStringPointer(const char *s, storage_policies::store_by_copy) { | ||||||
|     setType(VALUE_IS_OWNED_STRING); |     setType(VALUE_IS_OWNED_STRING); | ||||||
|     _content.asString = s.get(); |     _content.asString = s; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void setString(not_null<const char *> s, storage_policies::store_by_address) { |   void setStringPointer(const char *s, storage_policies::store_by_address) { | ||||||
|     setType(VALUE_IS_LINKED_STRING); |     setType(VALUE_IS_LINKED_STRING); | ||||||
|     _content.asString = s.get(); |     _content.asString = s; | ||||||
|   } |  | ||||||
|  |  | ||||||
|   template <typename TStoragePolicy> |  | ||||||
|   bool setString(const char *s, TStoragePolicy storage_policy) { |  | ||||||
|     if (s) { |  | ||||||
|       setString(make_not_null(s), storage_policy); |  | ||||||
|       return true; |  | ||||||
|     } else { |  | ||||||
|       setType(VALUE_IS_NULL); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TAdaptedString> |   template <typename TAdaptedString> | ||||||
| @@ -283,14 +271,27 @@ class VariantData { | |||||||
|   template <typename TAdaptedString> |   template <typename TAdaptedString> | ||||||
|   inline bool setString(TAdaptedString value, MemoryPool *, |   inline bool setString(TAdaptedString value, MemoryPool *, | ||||||
|                         storage_policies::store_by_address) { |                         storage_policies::store_by_address) { | ||||||
|     return setString(value.data(), storage_policies::store_by_address()); |     if (value.isNull()) | ||||||
|  |       setNull(); | ||||||
|  |     else | ||||||
|  |       setStringPointer(value.data(), storage_policies::store_by_address()); | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TAdaptedString> |   template <typename TAdaptedString> | ||||||
|   inline bool setString(TAdaptedString value, MemoryPool *pool, |   inline bool setString(TAdaptedString value, MemoryPool *pool, | ||||||
|                         storage_policies::store_by_copy) { |                         storage_policies::store_by_copy) { | ||||||
|     return setString(pool->saveString(value), |     if (value.isNull()) { | ||||||
|                      storage_policies::store_by_copy()); |       setNull(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     const char *copy = pool->saveString(value); | ||||||
|  |     if (!copy) { | ||||||
|  |       setNull(); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     setStringPointer(copy, storage_policies::store_by_copy()); | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   CollectionData &toArray() { |   CollectionData &toArray() { | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ | |||||||
|  |  | ||||||
| #include <stdint.h>  // int8_t, int16_t | #include <stdint.h>  // int8_t, int16_t | ||||||
|  |  | ||||||
| #include <ArduinoJson/Polyfills/gsl/not_null.hpp> |  | ||||||
| #include <ArduinoJson/Polyfills/type_traits.hpp> | #include <ArduinoJson/Polyfills/type_traits.hpp> | ||||||
| #include <ArduinoJson/Strings/StoragePolicy.hpp> | #include <ArduinoJson/Strings/StoragePolicy.hpp> | ||||||
| #include <ArduinoJson/Variant/VariantContent.hpp> | #include <ArduinoJson/Variant/VariantContent.hpp> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user