mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	RawJson() accepts any kind of string and obeys to duplication rules
				
					
				
			This commit is contained in:
		
							
								
								
									
										14
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -5,17 +5,19 @@ HEAD | |||||||
| ---- | ---- | ||||||
|  |  | ||||||
| * Changed the rules of string duplication (issue #658) | * Changed the rules of string duplication (issue #658) | ||||||
|  | * `RawJson()` accepts any kind of string and obeys to the same rules for duplication | ||||||
| * Changed the return type of `strdup()` to `const char*` to prevent double duplication | * Changed the return type of `strdup()` to `const char*` to prevent double duplication | ||||||
| * Marked `strdup()` as deprecated | * Marked `strdup()` as deprecated | ||||||
|  |  | ||||||
| > ### New rules for string duplication | > ### New rules for string duplication | ||||||
| > | > | ||||||
| > | type         | duplication | | > | type                       | duplication | | ||||||
| > |:-------------|:------------| | > |:---------------------------|:------------| | ||||||
| > | const char*  | no          | | > | const char*                | no          | | ||||||
| > | char*        | ~~no~~ yes  | | > | char*                      | ~~no~~ yes  | | ||||||
| > | String       | yes         | | > | String                     | yes         | | ||||||
| > | std::string  | yes         | | > | std::string                | yes         | | ||||||
|  | > | const __FlashStringHelper* | yes         | | ||||||
| > | > | ||||||
| > These new rules make `JsonBuffer::strdup()` useless. | > These new rules make `JsonBuffer::strdup()` useless. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -37,6 +37,9 @@ void setup() { | |||||||
|   // JsonBuffer. |   // JsonBuffer. | ||||||
|   root["sensor"] = F("gps"); |   root["sensor"] = F("gps"); | ||||||
|  |  | ||||||
|  |   // It works with RawJson too: | ||||||
|  |   root["sensor"] = RawJson(F("\"gps\"")); | ||||||
|  |  | ||||||
|   // You can compare the content of a JsonVariant to a Flash String |   // You can compare the content of a JsonVariant to a Flash String | ||||||
|   if (root["sensor"] == F("gps")) { |   if (root["sensor"] == F("gps")) { | ||||||
|     // ... |     // ... | ||||||
|   | |||||||
| @@ -40,6 +40,9 @@ void setup() { | |||||||
|   // WARNING: the content of the String will be duplicated in the JsonBuffer. |   // WARNING: the content of the String will be duplicated in the JsonBuffer. | ||||||
|   root["sensor"] = sensor; |   root["sensor"] = sensor; | ||||||
|  |  | ||||||
|  |   // It works with RawJson too: | ||||||
|  |   root["sensor"] = RawJson(sensor); | ||||||
|  |  | ||||||
|   // You can also concatenate strings |   // You can also concatenate strings | ||||||
|   // WARNING: the content of the String will be duplicated in the JsonBuffer. |   // WARNING: the content of the String will be duplicated in the JsonBuffer. | ||||||
|   root[String("sen") + "sor"] = String("gp") + "s"; |   root[String("sen") + "sor"] = String("gp") + "s"; | ||||||
|   | |||||||
| @@ -23,11 +23,29 @@ struct ValueSaver { | |||||||
|  |  | ||||||
| template <typename Source> | template <typename Source> | ||||||
| struct ValueSaver<Source, typename TypeTraits::EnableIf< | struct ValueSaver<Source, typename TypeTraits::EnableIf< | ||||||
|                               TypeTraits::IsString<Source>::value>::type> { |                               StringTraits<Source>::should_duplicate>::type> { | ||||||
|   template <typename Destination> |   template <typename Destination> | ||||||
|   static bool save(JsonBuffer* buffer, Destination& destination, |   static bool save(JsonBuffer* buffer, Destination& dest, Source source) { | ||||||
|                    Source source) { |     if (!StringTraits<Source>::is_null(source)) { | ||||||
|     return StringTraits<Source>::save(source, destination, buffer); |       typename StringTraits<Source>::duplicate_t dup = | ||||||
|  |           StringTraits<Source>::duplicate(source, buffer); | ||||||
|  |       if (!dup) return false; | ||||||
|  |       dest = dup; | ||||||
|  |     } else { | ||||||
|  |       dest = reinterpret_cast<const char*>(0); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // const char*, const signed char*, const unsigned char* | ||||||
|  | template <typename Char> | ||||||
|  | struct ValueSaver<Char*, typename TypeTraits::EnableIf< | ||||||
|  |                              !StringTraits<Char*>::should_duplicate>::type> { | ||||||
|  |   template <typename Destination> | ||||||
|  |   static bool save(JsonBuffer*, Destination& dest, Char* source) { | ||||||
|  |     dest = reinterpret_cast<const char*>(source); | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -46,7 +46,7 @@ class JsonObjectSubscript | |||||||
|   // operator=(TValue); |   // operator=(TValue); | ||||||
|   // TValue = char*, const char*, const FlashStringHelper* |   // TValue = char*, const char*, const FlashStringHelper* | ||||||
|   template <typename TValue> |   template <typename TValue> | ||||||
|   FORCE_INLINE this_type& operator=(const TValue* src) { |   FORCE_INLINE this_type& operator=(TValue* src) { | ||||||
|     _object.set(_key, src); |     _object.set(_key, src); | ||||||
|     return *this; |     return *this; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -117,7 +117,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Create a JsonVariant containing an unparsed string |   // Create a JsonVariant containing an unparsed string | ||||||
|   JsonVariant(RawJson value) { |   JsonVariant(Internals::RawJsonString<const char *> value) { | ||||||
|     _type = Internals::JSON_UNPARSED; |     _type = Internals::JSON_UNPARSED; | ||||||
|     _content.asString = value; |     _content.asString = value; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ class JsonVariantComparisons { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TString> |   template <typename TString> | ||||||
|   typename TypeTraits::EnableIf<TypeTraits::IsString<TString>::value, |   typename TypeTraits::EnableIf<Internals::StringTraits<TString>::has_equals, | ||||||
|                                 bool>::type |                                 bool>::type | ||||||
|   equals(const TString &comparand) const { |   equals(const TString &comparand) const { | ||||||
|     const char *value = as<const char *>(); |     const char *value = as<const char *>(); | ||||||
| @@ -112,9 +112,10 @@ class JsonVariantComparisons { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TComparand> |   template <typename TComparand> | ||||||
|   typename TypeTraits::EnableIf<!TypeTraits::IsVariant<TComparand>::value && |   typename TypeTraits::EnableIf< | ||||||
|                                     !TypeTraits::IsString<TComparand>::value, |       !TypeTraits::IsVariant<TComparand>::value && | ||||||
|                                 bool>::type |           !Internals::StringTraits<TComparand>::has_equals, | ||||||
|  |       bool>::type | ||||||
|   equals(const TComparand &comparand) const { |   equals(const TComparand &comparand) const { | ||||||
|     return as<TComparand>() == comparand; |     return as<TComparand>() == comparand; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -6,15 +6,41 @@ | |||||||
|  |  | ||||||
| namespace ArduinoJson { | namespace ArduinoJson { | ||||||
|  |  | ||||||
|  | namespace Internals { | ||||||
| // A special type of data that can be used to insert pregenerated JSON portions. | // A special type of data that can be used to insert pregenerated JSON portions. | ||||||
| class RawJson { | template <typename T> | ||||||
|  | class RawJsonString { | ||||||
|  public: |  public: | ||||||
|   explicit RawJson(const char* str) : _str(str) {} |   explicit RawJsonString(T str) : _str(str) {} | ||||||
|   operator const char*() const { |   operator T() const { | ||||||
|     return _str; |     return _str; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   const char* _str; |   T _str; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename String> | ||||||
|  | struct StringTraits<RawJsonString<String>, void> { | ||||||
|  |   static bool is_null(RawJsonString<String> source) { | ||||||
|  |     return StringTraits<String>::is_null(static_cast<String>(source)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   typedef RawJsonString<const char*> duplicate_t; | ||||||
|  |  | ||||||
|  |   template <typename Buffer> | ||||||
|  |   static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) { | ||||||
|  |     return duplicate_t(StringTraits<String>::duplicate(source, buffer)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const bool has_append = false; | ||||||
|  |   static const bool has_equals = false; | ||||||
|  |   static const bool should_duplicate = StringTraits<String>::should_duplicate; | ||||||
| }; | }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | inline Internals::RawJsonString<T> RawJson(T str) { | ||||||
|  |   return Internals::RawJsonString<T>(str); | ||||||
|  | } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -29,8 +29,7 @@ template <typename T> | |||||||
| class JsonPrintable { | class JsonPrintable { | ||||||
|  public: |  public: | ||||||
|   template <typename Print> |   template <typename Print> | ||||||
|   typename TypeTraits::EnableIf<!TypeTraits::IsString<Print>::value, |   typename TypeTraits::EnableIf<!StringTraits<Print>::has_append, size_t>::type | ||||||
|                                 size_t>::type |  | ||||||
|   printTo(Print &print) const { |   printTo(Print &print) const { | ||||||
|     JsonWriter<Print> writer(print); |     JsonWriter<Print> writer(print); | ||||||
|     JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer); |     JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer); | ||||||
| @@ -79,8 +78,7 @@ class JsonPrintable { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename Print> |   template <typename Print> | ||||||
|   typename TypeTraits::EnableIf<!TypeTraits::IsString<Print>::value, |   typename TypeTraits::EnableIf<!StringTraits<Print>::has_append, size_t>::type | ||||||
|                                 size_t>::type |  | ||||||
|   prettyPrintTo(Print &print) const { |   prettyPrintTo(Print &print) const { | ||||||
|     IndentedPrint<Print> indentedPrint(print); |     IndentedPrint<Print> indentedPrint(print); | ||||||
|     return prettyPrintTo(indentedPrint); |     return prettyPrintTo(indentedPrint); | ||||||
|   | |||||||
| @@ -43,6 +43,9 @@ struct ArduinoStreamTraits { | |||||||
|       return c; |       return c; | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   static const bool has_append = false; | ||||||
|  |   static const bool has_equals = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename TStream> | template <typename TStream> | ||||||
|   | |||||||
| @@ -33,58 +33,31 @@ struct CharPointerTraits { | |||||||
|     return strcmp(reinterpret_cast<const char*>(str), expected) == 0; |     return strcmp(reinterpret_cast<const char*>(str), expected) == 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // TODO: remove |   static bool is_null(const TChar* str) { | ||||||
|  |     return !str; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   typedef const char* duplicate_t; | ||||||
|  |  | ||||||
|   template <typename Buffer> |   template <typename Buffer> | ||||||
|   static char* duplicate(const TChar* str, Buffer* buffer) { |   static duplicate_t duplicate(const TChar* str, Buffer* buffer) { | ||||||
|     if (!str) return NULL; |     if (!str) return NULL; | ||||||
|     size_t size = strlen(reinterpret_cast<const char*>(str)) + 1; |     size_t size = strlen(reinterpret_cast<const char*>(str)) + 1; | ||||||
|     void* dup = buffer->alloc(size); |     void* dup = buffer->alloc(size); | ||||||
|     if (dup != NULL) memcpy(dup, str, size); |     if (dup != NULL) memcpy(dup, str, size); | ||||||
|     return static_cast<char*>(dup); |     return static_cast<duplicate_t>(dup); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static const bool has_append = false; |   static const bool has_append = false; | ||||||
|   static const bool has_equals = true; |   static const bool has_equals = true; | ||||||
| }; |   static const bool should_duplicate = !TypeTraits::IsConst<TChar>::value; | ||||||
|  |  | ||||||
| // const char*, const unsigned char*, const signed char* |  | ||||||
| template <typename TChar> |  | ||||||
| struct StringTraits<TChar*, typename TypeTraits::EnableIf< |  | ||||||
|                                 TypeTraits::IsChar<TChar>::value && |  | ||||||
|                                 TypeTraits::IsConst<TChar>::value>::type> |  | ||||||
|     : CharPointerTraits<TChar> { |  | ||||||
|   // Just save the pointer |  | ||||||
|   template <typename Buffer, typename Destination> |  | ||||||
|   static typename TypeTraits::EnableIf<TypeTraits::IsConst<TChar>::value, |  | ||||||
|                                        bool>::type |  | ||||||
|   save(const TChar* source, Destination& dest, Buffer*) { |  | ||||||
|     dest = reinterpret_cast<const char*>(source); |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // char*, unsigned char*, signed char* | // char*, unsigned char*, signed char* | ||||||
|  | // const char*, const unsigned char*, const signed char* | ||||||
| template <typename TChar> | template <typename TChar> | ||||||
| struct StringTraits<TChar*, typename TypeTraits::EnableIf< | struct StringTraits<TChar*, typename TypeTraits::EnableIf< | ||||||
|                                 TypeTraits::IsChar<TChar>::value && |                                 TypeTraits::IsChar<TChar>::value>::type> | ||||||
|                                 !TypeTraits::IsConst<TChar>::value>::type> |     : CharPointerTraits<TChar> {}; | ||||||
|     : CharPointerTraits<TChar> { |  | ||||||
|   // Make a copy of the string |  | ||||||
|   template <typename Buffer, typename Destination> |  | ||||||
|   static typename TypeTraits::EnableIf<!TypeTraits::IsConst<TChar>::value, |  | ||||||
|                                        bool>::type |  | ||||||
|   save(const TChar* source, Destination& dest, Buffer* buffer) { |  | ||||||
|     if (source) { |  | ||||||
|       size_t size = strlen(reinterpret_cast<const char*>(source)) + 1; |  | ||||||
|       void* dup = buffer->alloc(size); |  | ||||||
|       if (!dup) return false; |  | ||||||
|       memcpy(dup, source, size); |  | ||||||
|       dest = reinterpret_cast<const char*>(dup); |  | ||||||
|     } else { |  | ||||||
|       dest = reinterpret_cast<const char*>(source); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| } | } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,32 +34,24 @@ struct StringTraits<const __FlashStringHelper*, void> { | |||||||
|     return strcmp_P(expected, (const char*)str) == 0; |     return strcmp_P(expected, (const char*)str) == 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // TODO: remove |   static bool is_null(const __FlashStringHelper* str) { | ||||||
|  |     return !str; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   typedef const char* duplicate_t; | ||||||
|  |  | ||||||
|   template <typename Buffer> |   template <typename Buffer> | ||||||
|   static char* duplicate(const __FlashStringHelper* str, Buffer* buffer) { |   static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) { | ||||||
|     if (!str) return NULL; |     if (!str) return NULL; | ||||||
|     size_t size = strlen_P((const char*)str) + 1; |     size_t size = strlen_P((const char*)str) + 1; | ||||||
|     void* dup = buffer->alloc(size); |     void* dup = buffer->alloc(size); | ||||||
|     if (dup != NULL) memcpy_P(dup, (const char*)str, size); |     if (dup != NULL) memcpy_P(dup, (const char*)str, size); | ||||||
|     return static_cast<char*>(dup); |     return static_cast<duplicate_t>(dup); | ||||||
|   } |  | ||||||
|  |  | ||||||
|   template <typename Buffer, typename Destination> |  | ||||||
|   static bool save(const __FlashStringHelper* source, Destination& dest, |  | ||||||
|                    Buffer* buffer) { |  | ||||||
|     if (source) { |  | ||||||
|       size_t size = strlen_P((const char*)source) + 1; |  | ||||||
|       void* dup = buffer->alloc(size); |  | ||||||
|       if (dup != NULL) memcpy_P(dup, (const char*)source, size); |  | ||||||
|       dest = reinterpret_cast<const char*>(dup); |  | ||||||
|     } else { |  | ||||||
|       dest = reinterpret_cast<const char*>(source); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static const bool has_append = false; |   static const bool has_append = false; | ||||||
|   static const bool has_equals = true; |   static const bool has_equals = true; | ||||||
|  |   static const bool should_duplicate = true; | ||||||
| }; | }; | ||||||
| } | } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -42,6 +42,9 @@ struct StdStreamTraits { | |||||||
|       return _stream.eof() ? '\0' : static_cast<char>(_stream.get()); |       return _stream.eof() ? '\0' : static_cast<char>(_stream.get()); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   static const bool has_append = false; | ||||||
|  |   static const bool has_equals = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename TStream> | template <typename TStream> | ||||||
|   | |||||||
| @@ -19,29 +19,20 @@ namespace Internals { | |||||||
|  |  | ||||||
| template <typename TString> | template <typename TString> | ||||||
| struct StdStringTraits { | struct StdStringTraits { | ||||||
|   // TODO: remove |   typedef const char* duplicate_t; | ||||||
|  |  | ||||||
|   template <typename Buffer> |   template <typename Buffer> | ||||||
|   static char* duplicate(const TString& str, Buffer* buffer) { |   static duplicate_t duplicate(const TString& str, Buffer* buffer) { | ||||||
|     if (!str.c_str()) return NULL;  // <- Arduino string can return NULL |     if (!str.c_str()) return NULL;  // <- Arduino string can return NULL | ||||||
|     size_t size = str.length() + 1; |     size_t size = str.length() + 1; | ||||||
|     void* dup = buffer->alloc(size); |     void* dup = buffer->alloc(size); | ||||||
|     if (dup != NULL) memcpy(dup, str.c_str(), size); |     if (dup != NULL) memcpy(dup, str.c_str(), size); | ||||||
|     return static_cast<char*>(dup); |     return static_cast<duplicate_t>(dup); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename Buffer, typename Destination> |   static bool is_null(const TString& str) { | ||||||
|   static bool save(const TString& str, Destination& dest, Buffer* buffer) { |  | ||||||
|     // Arduino's String::c_str() can return NULL |     // Arduino's String::c_str() can return NULL | ||||||
|     if (str.c_str()) { |     return !str.c_str(); | ||||||
|       size_t size = str.length() + 1; |  | ||||||
|       void* dup = buffer->alloc(size); |  | ||||||
|       if (!dup) return false; |  | ||||||
|       memcpy(dup, str.c_str(), size); |  | ||||||
|       dest = reinterpret_cast<const char*>(dup); |  | ||||||
|     } else { |  | ||||||
|       dest = str.c_str(); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   struct Reader : CharPointerTraits<char>::Reader { |   struct Reader : CharPointerTraits<char>::Reader { | ||||||
| @@ -62,6 +53,7 @@ struct StdStringTraits { | |||||||
|  |  | ||||||
|   static const bool has_append = true; |   static const bool has_append = true; | ||||||
|   static const bool has_equals = true; |   static const bool has_equals = true; | ||||||
|  |   static const bool should_duplicate = true; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||||
|   | |||||||
| @@ -16,7 +16,10 @@ namespace ArduinoJson { | |||||||
| namespace Internals { | namespace Internals { | ||||||
|  |  | ||||||
| template <typename TString, typename Enable = void> | template <typename TString, typename Enable = void> | ||||||
| struct StringTraits {}; | struct StringTraits { | ||||||
|  |   static const bool has_append = false; | ||||||
|  |   static const bool has_equals = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
| template <typename TString> | template <typename TString> | ||||||
| struct StringTraits<const TString, void> : StringTraits<TString> {}; | struct StringTraits<const TString, void> : StringTraits<TString> {}; | ||||||
| @@ -31,18 +34,3 @@ struct StringTraits<TString&, void> : StringTraits<TString> {}; | |||||||
| #include "FlashString.hpp" | #include "FlashString.hpp" | ||||||
| #include "StdStream.hpp" | #include "StdStream.hpp" | ||||||
| #include "StdString.hpp" | #include "StdString.hpp" | ||||||
|  |  | ||||||
| namespace ArduinoJson { |  | ||||||
| namespace TypeTraits { |  | ||||||
| template <typename T, typename Enable = void> |  | ||||||
| struct IsString { |  | ||||||
|   static const bool value = false; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| template <typename T> |  | ||||||
| struct IsString<T, typename TypeTraits::EnableIf< |  | ||||||
|                        Internals::StringTraits<T>::has_equals>::type> { |  | ||||||
|   static const bool value = Internals::StringTraits<T>::has_equals; |  | ||||||
| }; |  | ||||||
| } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ TEST_CASE("JsonArray::add()") { | |||||||
|     REQUIRE(expectedSize == _jsonBuffer.size()); |     REQUIRE(expectedSize == _jsonBuffer.size()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   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 == _jsonBuffer.size()); |     REQUIRE(expectedSize == _jsonBuffer.size()); | ||||||
| @@ -95,4 +95,16 @@ TEST_CASE("JsonArray::add()") { | |||||||
|     const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; |     const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; | ||||||
|     REQUIRE(expectedSize == _jsonBuffer.size()); |     REQUIRE(expectedSize == _jsonBuffer.size()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   SECTION("should not duplicate RawJson(const char*)") { | ||||||
|  |     _array.add(RawJson("{}")); | ||||||
|  |     const size_t expectedSize = JSON_ARRAY_SIZE(1); | ||||||
|  |     REQUIRE(expectedSize == _jsonBuffer.size()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SECTION("should duplicate RawJson(char*)") { | ||||||
|  |     _array.add(RawJson(const_cast<char*>("{}"))); | ||||||
|  |     const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3; | ||||||
|  |     REQUIRE(expectedSize == _jsonBuffer.size()); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,10 +8,10 @@ | |||||||
| static void check(JsonArray &array, std::string expected) { | static void check(JsonArray &array, std::string expected) { | ||||||
|   std::string actual; |   std::string actual; | ||||||
|   size_t actualLen = array.printTo(actual); |   size_t actualLen = array.printTo(actual); | ||||||
|   size_t measuredLen = array.measureLength(); |  | ||||||
|   CHECK(actualLen == expected.size()); |  | ||||||
|   CHECK(measuredLen == expected.size()); |  | ||||||
|   REQUIRE(expected == actual); |   REQUIRE(expected == actual); | ||||||
|  |   REQUIRE(actualLen == expected.size()); | ||||||
|  |   size_t measuredLen = array.measureLength(); | ||||||
|  |   REQUIRE(measuredLen == expected.size()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST_CASE("JsonArray::printTo()") { | TEST_CASE("JsonArray::printTo()") { | ||||||
| @@ -67,12 +67,22 @@ TEST_CASE("JsonArray::printTo()") { | |||||||
|     check(array, "[1,2]"); |     check(array, "[1,2]"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("RawJson") { |   SECTION("RawJson(const char*)") { | ||||||
|     array.add(RawJson("{\"key\":\"value\"}")); |     array.add(RawJson("{\"key\":\"value\"}")); | ||||||
|  |  | ||||||
|     check(array, "[{\"key\":\"value\"}]"); |     check(array, "[{\"key\":\"value\"}]"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   SECTION("RawJson(char*)") { | ||||||
|  |     DynamicJsonBuffer jb2; | ||||||
|  |     JsonArray &arr = jb2.createArray(); | ||||||
|  |  | ||||||
|  |     char tmp[] = "{\"key\":\"value\"}"; | ||||||
|  |     arr.add(RawJson(tmp)); | ||||||
|  |  | ||||||
|  |     check(arr, "[{\"key\":\"value\"}]"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   SECTION("OneIntegerOverCapacity") { |   SECTION("OneIntegerOverCapacity") { | ||||||
|     array.add(1); |     array.add(1); | ||||||
|     array.add(2); |     array.add(2); | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ add_executable(MiscTests | |||||||
| 	std_stream.cpp | 	std_stream.cpp | ||||||
| 	std_string.cpp | 	std_string.cpp | ||||||
| 	StringBuilder.cpp | 	StringBuilder.cpp | ||||||
|  | 	StringTraits.cpp | ||||||
| 	TypeTraits.cpp | 	TypeTraits.cpp | ||||||
| 	unsigned_char.cpp | 	unsigned_char.cpp | ||||||
| 	vla.cpp | 	vla.cpp | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								test/Misc/StringTraits.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								test/Misc/StringTraits.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | // ArduinoJson - arduinojson.org | ||||||
|  | // Copyright Benoit Blanchon 2014-2018 | ||||||
|  | // MIT License | ||||||
|  |  | ||||||
|  | #include <ArduinoJson.h> | ||||||
|  | #include <catch.hpp> | ||||||
|  |  | ||||||
|  | using namespace ArduinoJson::Internals; | ||||||
|  |  | ||||||
|  | template <typename String> | ||||||
|  | bool should_duplicate() { | ||||||
|  |   return StringTraits<String>::should_duplicate; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_CASE("StringTraits") { | ||||||
|  |   SECTION("should_duplicate") { | ||||||
|  |     REQUIRE(false == should_duplicate<const char*>()); | ||||||
|  |     REQUIRE(true == should_duplicate<char*>()); | ||||||
|  |     REQUIRE(true == should_duplicate<RawJsonString<char*> >()); | ||||||
|  |     REQUIRE(false == should_duplicate<RawJsonString<const char*> >()); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -4,7 +4,6 @@ | |||||||
|  |  | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include <catch.hpp> | #include <catch.hpp> | ||||||
| #include <sstream> |  | ||||||
|  |  | ||||||
| using namespace ArduinoJson::TypeTraits; | using namespace ArduinoJson::TypeTraits; | ||||||
|  |  | ||||||
| @@ -31,12 +30,6 @@ TEST_CASE("TypeTraits") { | |||||||
|     REQUIRE(static_cast<bool>(IsVariant<JsonVariant>::value)); |     REQUIRE(static_cast<bool>(IsVariant<JsonVariant>::value)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("IsString") { |  | ||||||
|     REQUIRE((IsString<const char*>::value)); |  | ||||||
|     REQUIRE((IsString<std::string>::value)); |  | ||||||
|     REQUIRE_FALSE((IsString<double>::value)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   SECTION("IsConst") { |   SECTION("IsConst") { | ||||||
|     REQUIRE_FALSE((IsConst<char>::value)); |     REQUIRE_FALSE((IsConst<char>::value)); | ||||||
|     REQUIRE((IsConst<const char>::value)); |     REQUIRE((IsConst<const char>::value)); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user