mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Added support of non standard JSON input (issue #44)
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,3 +3,4 @@ | ||||
| /build | ||||
| /bin | ||||
| /lib | ||||
| /sftp-config.json | ||||
|   | ||||
| @@ -4,9 +4,7 @@ compiler: | ||||
|   - clang | ||||
| before_install: | ||||
|   - sudo pip install cpp-coveralls | ||||
| before_script: | ||||
|   - cmake -DCOVERAGE=true . | ||||
| script: | ||||
|   - make && make test | ||||
|   - cmake -DCOVERAGE=true . && make && make test | ||||
| after_success: | ||||
|   - coveralls --exclude test --exclude third-party --gcov-options '\-lp' | ||||
|     - if [ "$CC" = "gcc" ]; then coveralls --exclude third-party --gcov-options '\-lp'; fi | ||||
|   | ||||
							
								
								
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ v5.0 (currently in beta) | ||||
| ---- | ||||
|  | ||||
| * Added support of `String` class (issue #55, #56, #70, #77) | ||||
| * Added support of non standard JSON input (issue #44) | ||||
| * Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators | ||||
| * Switched to new the library layout (requires Arduino 1.0.6 or above) | ||||
|  | ||||
| @@ -20,6 +21,15 @@ The `String` class is **bad** because it uses dynamic memory allocation. | ||||
| Compared to static allocation, it compiles to a bigger, slower program, and is less predictable. | ||||
| You certainly don't want that in an embedded environment! | ||||
|  | ||||
| v4.5 | ||||
| ---- | ||||
|  | ||||
| * Fixed buffer overflow when input contains a backslash followed by a terminator (issue #81) | ||||
|  | ||||
| **Upgrading is recommended** since previous versions contain a potential security risk. | ||||
|  | ||||
| Special thanks to [Giancarlo Canales Barreto](https://github.com/gcanalesb) for finding this nasty bug. | ||||
|  | ||||
| v4.4 | ||||
| ---- | ||||
|  | ||||
|   | ||||
| @@ -12,9 +12,8 @@ if(MSVC) | ||||
| endif() | ||||
|  | ||||
| if(${COVERAGE}) | ||||
| 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -coverage") | ||||
| 	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage") | ||||
| 	set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") | ||||
| endif() | ||||
|  | ||||
| add_subdirectory(src) | ||||
| add_subdirectory(test) | ||||
| add_subdirectory(test) | ||||
|   | ||||
							
								
								
									
										39
									
								
								include/ArduinoJson/Internals/Encoding.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/ArduinoJson/Internals/Encoding.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Arduino/Print.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class Encoding { | ||||
|  public: | ||||
|   // Optimized for code size on a 8-bit AVR | ||||
|   static char escapeChar(char c) { | ||||
|     const char *p = _escapeTable; | ||||
|     while (p[0] && p[1] != c) { | ||||
|       p += 2; | ||||
|     } | ||||
|     return p[0]; | ||||
|   } | ||||
|  | ||||
|   // Optimized for code size on a 8-bit AVR | ||||
|   static char unescapeChar(char c) { | ||||
|     const char *p = _escapeTable + 4; | ||||
|     for (;;) { | ||||
|       if (p[0] == '\0') return c; | ||||
|       if (p[0] == c) return p[1]; | ||||
|       p += 2; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| private: | ||||
| 	static const char _escapeTable[]; | ||||
| }; | ||||
| } | ||||
| } | ||||
| @@ -18,7 +18,10 @@ namespace Internals { | ||||
| class JsonParser { | ||||
|  public: | ||||
|   JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit) | ||||
|       : _buffer(buffer), _ptr(json), _nestingLimit(nestingLimit) {} | ||||
|       : _buffer(buffer), | ||||
|         _readPtr(json), | ||||
|         _writePtr(json), | ||||
|         _nestingLimit(nestingLimit) {} | ||||
|  | ||||
|   JsonArray &parseArray(); | ||||
|   JsonObject &parseObject(); | ||||
| @@ -26,12 +29,10 @@ class JsonParser { | ||||
|  private: | ||||
|   bool skip(char charToSkip); | ||||
|   bool skip(const char *wordToSkip); | ||||
|   void skipSpaces(); | ||||
|  | ||||
|   bool parseAnythingTo(JsonVariant *destination); | ||||
|   FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); | ||||
|  | ||||
|   const char *parseString(); | ||||
|   bool parseAnythingTo(JsonVariant *destination); | ||||
|   FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); | ||||
|  | ||||
|   inline bool parseArrayTo(JsonVariant *destination); | ||||
|   inline bool parseBooleanTo(JsonVariant *destination); | ||||
| @@ -41,7 +42,8 @@ class JsonParser { | ||||
|   inline bool parseStringTo(JsonVariant *destination); | ||||
|  | ||||
|   JsonBuffer *_buffer; | ||||
|   char *_ptr; | ||||
|   const char *_readPtr; | ||||
|   char *_writePtr; | ||||
|   uint8_t _nestingLimit; | ||||
| }; | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,10 @@ | ||||
| #include "Prettyfier.hpp" | ||||
| #include "StringBuilder.hpp" | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include "StreamPrintAdapter.hpp" | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| @@ -28,6 +32,14 @@ class JsonPrintable { | ||||
|     return writer.bytesWritten(); | ||||
|   } | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
|   std::ostream& printTo(std::ostream &os) const { | ||||
|     StreamPrintAdapter adapter(os); | ||||
|     printTo(adapter); | ||||
|     return os; | ||||
|   } | ||||
| #endif  | ||||
|  | ||||
|   size_t printTo(char *buffer, size_t bufferSize) const { | ||||
|     StringBuilder sb(buffer, bufferSize); | ||||
|     return printTo(sb); | ||||
| @@ -61,5 +73,13 @@ class JsonPrintable { | ||||
|  private: | ||||
|   const T &downcast() const { return *static_cast<const T *>(this); } | ||||
| }; | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
| template<typename T> | ||||
| inline std::ostream& operator<<(std::ostream& os, const JsonPrintable<T>& v) { | ||||
|   return v.printTo(os); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../Arduino/Print.hpp" | ||||
| #include "QuotedString.hpp" | ||||
| #include "Encoding.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| @@ -26,7 +26,7 @@ class JsonWriter { | ||||
|   // Returns the number of bytes sent to the Print implementation. | ||||
|   // This is very handy for implementations of printTo() that must return the | ||||
|   // number of bytes written. | ||||
|   size_t bytesWritten() { return _length; } | ||||
|   size_t bytesWritten() const { return _length; } | ||||
|  | ||||
|   void beginArray() { write('['); } | ||||
|   void endArray() { write(']'); } | ||||
| @@ -37,15 +37,32 @@ class JsonWriter { | ||||
|   void writeColon() { write(':'); } | ||||
|   void writeComma() { write(','); } | ||||
|  | ||||
|   void writeBoolean(bool value) { | ||||
|     write(value ? "true" : "false"); | ||||
|   } | ||||
|    | ||||
|   void writeString(const char *value) { | ||||
|     _length += QuotedString::printTo(value, _sink); | ||||
|     if (!value) { | ||||
|       write("null"); | ||||
|     } else { | ||||
|       write('\"'); | ||||
|       while (*value) writeChar(*value++); | ||||
|       write('\"'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void writeChar(char c) { | ||||
|     char specialChar = Encoding::escapeChar(c); | ||||
|     if (specialChar) { | ||||
|       write('\\'); | ||||
|       write(specialChar); | ||||
|     } else { | ||||
|       write(c); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void writeLong(long value) { _length += _sink.print(value); } | ||||
|  | ||||
|   void writeBoolean(bool value) { | ||||
|     _length += _sink.print(value ? "true" : "false"); | ||||
|   } | ||||
|   void writeDouble(double value, uint8_t decimals) { | ||||
|     _length += _sink.print(value, decimals); | ||||
|   } | ||||
|   | ||||
| @@ -1,29 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Arduino/Print.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| // An helper class to print and extract doubly-quoted strings | ||||
| class QuotedString { | ||||
|  public: | ||||
|   // Writes a doubly-quote string to a Print implementation. | ||||
|   // It adds the double quotes (") at the beginning and the end of the string. | ||||
|   // It escapes the special characters as required by the JSON specifications. | ||||
|   static size_t printTo(const char *, Print &); | ||||
|  | ||||
|   // Reads a doubly-quoted string from a buffer. | ||||
|   // It removes the double quotes ("). | ||||
|   // It unescapes the special character as required by the JSON specification, | ||||
|   // with the exception of the Unicode characters (\u0000). | ||||
|   static char *extractFrom(char *input, char **end); | ||||
| }; | ||||
| } | ||||
| } | ||||
							
								
								
									
										34
									
								
								include/ArduinoJson/Internals/StreamPrintAdapter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								include/ArduinoJson/Internals/StreamPrintAdapter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
|  | ||||
| #include "../Arduino/Print.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class StreamPrintAdapter : public Print { | ||||
|  public: | ||||
|   explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} | ||||
|  | ||||
|   virtual size_t write(uint8_t c) { | ||||
|     _os << static_cast<char>(c); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   // cannot be assigned | ||||
|   StreamPrintAdapter& operator=(const StreamPrintAdapter&); | ||||
|  | ||||
|   std::ostream& _os; | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| #endif // ARDUINOJSON_ENABLE_STD_STREAM | ||||
| @@ -40,8 +40,19 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|     return _array.is<T>(_index); | ||||
|   } | ||||
|  | ||||
|   void writeTo(Internals::JsonWriter &writer) const { | ||||
|     _array.get(_index).writeTo(writer); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonArray& _array; | ||||
|   const size_t _index; | ||||
| }; | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
| inline std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& source) { | ||||
|   return source.printTo(os); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| } // namespace ArduinoJson | ||||
|   | ||||
| @@ -41,8 +41,18 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript> { | ||||
|     return _object.is<T>(_key); | ||||
|   } | ||||
|  | ||||
|   void writeTo(Internals::JsonWriter &writer) const { | ||||
|     _object.get(_key).writeTo(writer); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonObject& _object; | ||||
|   JsonObjectKey _key; | ||||
| }; | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
| inline std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& source) { | ||||
|   return source.printTo(os); | ||||
| } | ||||
| #endif | ||||
| } | ||||
|   | ||||
| @@ -28,8 +28,7 @@ class JsonObject; | ||||
| // - a char, short, int or a long (signed or unsigned) | ||||
| // - a string (const char*) | ||||
| // - a reference to a JsonArray or JsonObject | ||||
| class JsonVariant : public Internals::JsonPrintable<JsonVariant>, | ||||
|                     public JsonVariantBase<JsonVariant> { | ||||
| class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|  public: | ||||
|   // Creates an uninitialized JsonVariant | ||||
|   FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} | ||||
|   | ||||
| @@ -186,4 +186,11 @@ template <> | ||||
| inline bool JsonVariant::is<unsigned short>() const { | ||||
|   return _type == Internals::JSON_LONG; | ||||
| } | ||||
|  | ||||
| #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||
| inline std::ostream& operator<<(std::ostream& os, const JsonVariant& source) { | ||||
|   return source.printTo(os); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| } // namespace ArduinoJson | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class JsonArraySubscript; | ||||
| class JsonObjectSubscript; | ||||
|  | ||||
| template <typename TImpl> | ||||
| class JsonVariantBase { | ||||
| class JsonVariantBase : public Internals::JsonPrintable<TImpl> { | ||||
|  public: | ||||
|   // Gets the variant as a boolean value. | ||||
|   // Returns false if the variant is not a boolean value. | ||||
| @@ -79,6 +79,9 @@ class JsonVariantBase { | ||||
|   FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const; | ||||
|   FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const; | ||||
|  | ||||
|   // Serialize the variant to a JsonWriter | ||||
|   void writeTo(Internals::JsonWriter &writer) const; | ||||
|  | ||||
|  private: | ||||
|   const TImpl *impl() const { return static_cast<const TImpl *>(this); } | ||||
| }; | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/Internals/Encoding.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Internals/Encoding.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include "../../include/ArduinoJson/Internals/Encoding.hpp" | ||||
|  | ||||
| // How to escape special chars: | ||||
| // _escapeTable[2*i+1] => the special char | ||||
| // _escapeTable[2*i] => the char to use instead | ||||
| const char ArduinoJson::Internals::Encoding::_escapeTable[] = "\"\"\\\\b\bf\fn\nr\rt\t"; | ||||
| @@ -9,7 +9,7 @@ | ||||
| #include <stdlib.h>  // for strtol, strtod | ||||
| #include <ctype.h> | ||||
|  | ||||
| #include "../../include/ArduinoJson/Internals/QuotedString.hpp" | ||||
| #include "../../include/ArduinoJson/Internals/Encoding.hpp" | ||||
| #include "../../include/ArduinoJson/JsonArray.hpp" | ||||
| #include "../../include/ArduinoJson/JsonBuffer.hpp" | ||||
| #include "../../include/ArduinoJson/JsonObject.hpp" | ||||
| @@ -17,25 +17,28 @@ | ||||
| using namespace ArduinoJson; | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| void JsonParser::skipSpaces() { | ||||
|   while (isspace(*_ptr)) _ptr++; | ||||
| static const char *skipSpaces(const char *ptr) { | ||||
|   while (isspace(*ptr)) ptr++; | ||||
|   return ptr; | ||||
| } | ||||
|  | ||||
| bool JsonParser::skip(char charToSkip) { | ||||
|   skipSpaces(); | ||||
|   if (*_ptr != charToSkip) return false; | ||||
|   _ptr++; | ||||
|   skipSpaces(); | ||||
|   register const char *ptr = skipSpaces(_readPtr); | ||||
|   if (*ptr != charToSkip) return false; | ||||
|   ptr++; | ||||
|   _readPtr = skipSpaces(ptr); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool JsonParser::skip(const char *wordToSkip) { | ||||
|   const char *charToSkip = wordToSkip; | ||||
|   while (*charToSkip && *_ptr == *charToSkip) { | ||||
|     charToSkip++; | ||||
|     _ptr++; | ||||
|   register const char *ptr = _readPtr; | ||||
|   while (*wordToSkip && *ptr == *wordToSkip) { | ||||
|     wordToSkip++; | ||||
|     ptr++; | ||||
|   } | ||||
|   return *charToSkip == '\0'; | ||||
|   if (*wordToSkip != '\0') return false; | ||||
|   _readPtr = ptr; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool JsonParser::parseAnythingTo(JsonVariant *destination) { | ||||
| @@ -47,9 +50,9 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) { | ||||
| } | ||||
|  | ||||
| inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) { | ||||
|   skipSpaces(); | ||||
|   _readPtr = skipSpaces(_readPtr); | ||||
|  | ||||
|   switch (*_ptr) { | ||||
|   switch (*_readPtr) { | ||||
|     case '[': | ||||
|       return parseArrayTo(destination); | ||||
|  | ||||
| @@ -181,7 +184,7 @@ bool JsonParser::parseBooleanTo(JsonVariant *destination) { | ||||
|  | ||||
| bool JsonParser::parseNumberTo(JsonVariant *destination) { | ||||
|   char *endOfLong; | ||||
|   long longValue = strtol(_ptr, &endOfLong, 10); | ||||
|   long longValue = strtol(_readPtr, &endOfLong, 10); | ||||
|   char stopChar = *endOfLong; | ||||
|  | ||||
|   // Could it be a floating point value? | ||||
| @@ -189,14 +192,14 @@ bool JsonParser::parseNumberTo(JsonVariant *destination) { | ||||
|  | ||||
|   if (couldBeFloat) { | ||||
|     // Yes => parse it as a double | ||||
|     double doubleValue = strtod(_ptr, &_ptr); | ||||
|     double doubleValue = strtod(_readPtr, const_cast<char **>(&_readPtr)); | ||||
|     // Count the decimal digits | ||||
|     uint8_t decimals = static_cast<uint8_t>(_ptr - endOfLong - 1); | ||||
|     uint8_t decimals = static_cast<uint8_t>(_readPtr - endOfLong - 1); | ||||
|     // Set the variant as a double | ||||
|     *destination = JsonVariant(doubleValue, decimals); | ||||
|   } else { | ||||
|     // No => set the variant as a long | ||||
|     _ptr = endOfLong; | ||||
|     _readPtr = endOfLong; | ||||
|     *destination = longValue; | ||||
|   } | ||||
|   return true; | ||||
| @@ -209,8 +212,53 @@ bool JsonParser::parseNullTo(JsonVariant *destination) { | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool isStopChar(char c) { | ||||
|   return c == '\0' || c == ':' || c == '}' || c == ']' || c == ','; | ||||
| } | ||||
|  | ||||
| const char *JsonParser::parseString() { | ||||
|   return QuotedString::extractFrom(_ptr, &_ptr); | ||||
|   const char *readPtr = _readPtr; | ||||
|   char *writePtr = _writePtr; | ||||
|  | ||||
|   char c = *readPtr; | ||||
|  | ||||
|   if (c == '\'' || c == '\"') { | ||||
|     char stopChar = c; | ||||
|     for (;;) { | ||||
|       c = *++readPtr; | ||||
|       if (c == '\0') break; | ||||
|  | ||||
|       if (c == stopChar) { | ||||
|         readPtr++; | ||||
|         break; | ||||
|       } | ||||
|  | ||||
|       if (c == '\\') { | ||||
|         // replace char | ||||
|         c = Encoding::unescapeChar(*++readPtr); | ||||
|         if (c == '\0') break; | ||||
|       } | ||||
|  | ||||
|       *writePtr++ = c; | ||||
|     } | ||||
|   } else { | ||||
|     for (;;) { | ||||
|       if (isStopChar(c)) break; | ||||
|       *writePtr++ = c; | ||||
|       c = *++readPtr; | ||||
|     } | ||||
|   } | ||||
|   // end the string here | ||||
|   *writePtr++ = '\0'; | ||||
|  | ||||
|   const char *startPtr = _writePtr; | ||||
|  | ||||
|   // update end ptr | ||||
|   _readPtr = readPtr; | ||||
|   _writePtr = writePtr; | ||||
|  | ||||
|   // return pointer to unquoted string | ||||
|   return startPtr; | ||||
| } | ||||
|  | ||||
| bool JsonParser::parseStringTo(JsonVariant *destination) { | ||||
|   | ||||
| @@ -1,103 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include "../../include/ArduinoJson/Internals/QuotedString.hpp" | ||||
|  | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| // How to escape special chars: | ||||
| // specialChars[2*i+1] => the special char | ||||
| // specialChars[2*i] => the char to use instead | ||||
| static const char specialChars[] = "\"\"\\\\b\bf\fn\nr\rt\t"; | ||||
|  | ||||
| static inline char getSpecialChar(char c) { | ||||
|   // Optimized for code size on a 8-bit AVR | ||||
|  | ||||
|   const char *p = specialChars; | ||||
|  | ||||
|   while (p[0] && p[1] != c) { | ||||
|     p += 2; | ||||
|   } | ||||
|  | ||||
|   return p[0]; | ||||
| } | ||||
|  | ||||
| static inline size_t printCharTo(char c, Print &p) { | ||||
|   char specialChar = getSpecialChar(c); | ||||
|  | ||||
|   return specialChar ? p.write('\\') + p.write(specialChar) : p.write(c); | ||||
| } | ||||
|  | ||||
| size_t QuotedString::printTo(const char *s, Print &p) { | ||||
|   if (!s) return p.print("null"); | ||||
|  | ||||
|   size_t n = p.write('\"'); | ||||
|  | ||||
|   while (*s) { | ||||
|     n += printCharTo(*s++, p); | ||||
|   } | ||||
|  | ||||
|   return n + p.write('\"'); | ||||
| } | ||||
|  | ||||
| static char unescapeChar(char c) { | ||||
|   // Optimized for code size on a 8-bit AVR | ||||
|  | ||||
|   const char *p = specialChars + 4; | ||||
|  | ||||
|   for (;;) { | ||||
|     if (p[0] == '\0') return c; | ||||
|     if (p[0] == c) return p[1]; | ||||
|     p += 2; | ||||
|   } | ||||
| } | ||||
|  | ||||
| static inline bool isQuote(char c) { return c == '\"' || c == '\''; } | ||||
|  | ||||
| char *QuotedString::extractFrom(char *input, char **endPtr) { | ||||
|   char firstChar = *input; | ||||
|  | ||||
|   if (!isQuote(firstChar)) { | ||||
|     // must start with a quote | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   char stopChar = firstChar;  // closing quote is the same as opening quote | ||||
|  | ||||
|   char *startPtr = input + 1;  // skip the quote | ||||
|   char *readPtr = startPtr; | ||||
|   char *writePtr = startPtr; | ||||
|   char c; | ||||
|  | ||||
|   for (;;) { | ||||
|     c = *readPtr++; | ||||
|  | ||||
|     if (c == '\0') { | ||||
|       // premature ending | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|     if (c == stopChar) { | ||||
|       // closing quote | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     if (c == '\\') { | ||||
|       // replace char | ||||
|       c = unescapeChar(*readPtr++); | ||||
|     } | ||||
|  | ||||
|     *writePtr++ = c; | ||||
|   } | ||||
|  | ||||
|   // end the string here | ||||
|   *writePtr = '\0'; | ||||
|  | ||||
|   // update end ptr | ||||
|   *endPtr = readPtr; | ||||
|  | ||||
|   return startPtr; | ||||
| } | ||||
| @@ -18,4 +18,4 @@ add_executable(ArduinoJsonTests | ||||
|  | ||||
| target_link_libraries(ArduinoJsonTests ArduinoJson) | ||||
|  | ||||
| add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests) | ||||
| add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests) | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #define ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ArduinoJson.h> | ||||
| #include "Printers.hpp" | ||||
|  | ||||
| class GbathreeBug : public testing::Test { | ||||
|  public: | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #define ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ArduinoJson.h> | ||||
| #include "Printers.hpp" | ||||
|  | ||||
| class JsonObject_Iterator_Test : public testing::Test { | ||||
|  public: | ||||
|   | ||||
| @@ -9,14 +9,19 @@ | ||||
|  | ||||
| class JsonParser_Array_Tests : public testing::Test { | ||||
|  protected: | ||||
|   void whenInputIs(const char *json) { | ||||
|     strcpy(_jsonString, json); | ||||
|     _array = &_jsonBuffer.parseArray(_jsonString); | ||||
|   void whenInputIs(const char *json) { strcpy(_jsonString, json); } | ||||
|  | ||||
|   void whenInputIs(const char *json, size_t len) { | ||||
|     memcpy(_jsonString, json, len); | ||||
|   } | ||||
|  | ||||
|   void parseMustSucceed() { EXPECT_TRUE(_array->success()); } | ||||
|   void parseMustSucceed() { | ||||
|     _array = &_jsonBuffer.parseArray(_jsonString); | ||||
|     EXPECT_TRUE(_array->success()); | ||||
|   } | ||||
|  | ||||
|   void parseMustFail() { | ||||
|     _array = &_jsonBuffer.parseArray(_jsonString); | ||||
|     EXPECT_FALSE(_array->success()); | ||||
|     EXPECT_EQ(0, _array->size()); | ||||
|   } | ||||
| @@ -154,6 +159,11 @@ TEST_F(JsonParser_Array_Tests, IncompleteFalse) { | ||||
|   parseMustFail(); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, MixedTrueFalse) { | ||||
|   whenInputIs("[trufalse]"); | ||||
|   parseMustFail(); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, TwoStrings) { | ||||
|   whenInputIs("[\"hello\",\"world\"]"); | ||||
|  | ||||
| @@ -162,3 +172,55 @@ TEST_F(JsonParser_Array_Tests, TwoStrings) { | ||||
|   firstElementMustBe("hello"); | ||||
|   secondElementMustBe("world"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, EmptyStringsDoubleQuotes) { | ||||
|   whenInputIs("[\"\",\"\"]"); | ||||
|  | ||||
|   parseMustSucceed(); | ||||
|   sizeMustBe(2); | ||||
|   firstElementMustBe(""); | ||||
|   secondElementMustBe(""); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, EmptyStringSingleQuotes) { | ||||
|   whenInputIs("[\'\',\'\']"); | ||||
|  | ||||
|   parseMustSucceed(); | ||||
|   sizeMustBe(2); | ||||
|   firstElementMustBe(""); | ||||
|   secondElementMustBe(""); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, EmptyStringNoQuotes) { | ||||
|   whenInputIs("[,]"); | ||||
|  | ||||
|   parseMustSucceed(); | ||||
|   sizeMustBe(2); | ||||
|   firstElementMustBe(""); | ||||
|   secondElementMustBe(""); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, ClosingDoubleQuoteMissing) { | ||||
|   whenInputIs("[\"]"); | ||||
|  | ||||
|   parseMustFail(); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, ClosingSignleQuoteMissing) { | ||||
|   whenInputIs("[\']"); | ||||
|  | ||||
|   parseMustFail(); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, StringWithEscapedChars) { | ||||
|   whenInputIs("[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]"); | ||||
|  | ||||
|   parseMustSucceed(); | ||||
|   sizeMustBe(1); | ||||
|   firstElementMustBe("1\"2\\3/4\b5\f6\n7\r8\t9"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, StringWithUnterminatedEscapeSequence) { | ||||
|   whenInputIs("\"\\\0\"", 4); | ||||
|   parseMustFail(); | ||||
| } | ||||
|   | ||||
| @@ -75,6 +75,13 @@ TEST_F(JsonParser_Object_Test, OneStringSingleQuotes) { | ||||
|   keyMustHaveValue("key", "value"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Object_Test, OneStringNoQuotes) { | ||||
|   whenInputIs("{key:value}"); | ||||
|   parseMustSucceed(); | ||||
|   sizeMustBe(1); | ||||
|   keyMustHaveValue("key", "value"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Object_Test, OneStringSpaceBeforeKey) { | ||||
|   whenInputIs("{ \"key\":\"value\"}"); | ||||
|   parseMustSucceed(); | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #define ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ArduinoJson/JsonVariant.hpp> | ||||
| #include "Printers.hpp" | ||||
|  | ||||
| using namespace ArduinoJson; | ||||
|  | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #define ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ArduinoJson.h> | ||||
| #include "Printers.hpp" | ||||
|  | ||||
| class JsonVariant_Undefined_Tests : public ::testing::Test { | ||||
|  protected: | ||||
|   | ||||
| @@ -6,16 +6,18 @@ | ||||
| 
 | ||||
| #include <gtest/gtest.h> | ||||
| 
 | ||||
| #include <ArduinoJson/Internals/QuotedString.hpp> | ||||
| #include <ArduinoJson/Internals/JsonWriter.hpp> | ||||
| #include <ArduinoJson/Internals/StringBuilder.hpp> | ||||
| 
 | ||||
| using namespace ArduinoJson::Internals; | ||||
| 
 | ||||
| class QuotedString_PrintTo_Tests : public testing::Test { | ||||
| class JsonWriter_WriteString_Tests : public testing::Test { | ||||
|  protected: | ||||
|   void whenInputIs(const char *input) { | ||||
|     StringBuilder sb(buffer, sizeof(buffer)); | ||||
|     returnValue = QuotedString::printTo(input, sb); | ||||
|     JsonWriter writer(sb); | ||||
|     writer.writeString(input); | ||||
|     returnValue = writer.bytesWritten(); | ||||
|   } | ||||
| 
 | ||||
|   void outputMustBe(const char *expected) { | ||||
| @@ -28,52 +30,52 @@ class QuotedString_PrintTo_Tests : public testing::Test { | ||||
|   size_t returnValue; | ||||
| }; | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, Null) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, Null) { | ||||
|   whenInputIs(0); | ||||
|   outputMustBe("null"); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, EmptyString) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, EmptyString) { | ||||
|   whenInputIs(""); | ||||
|   outputMustBe("\"\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, QuotationMark) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, QuotationMark) { | ||||
|   whenInputIs("\""); | ||||
|   outputMustBe("\"\\\"\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, ReverseSolidus) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, ReverseSolidus) { | ||||
|   whenInputIs("\\"); | ||||
|   outputMustBe("\"\\\\\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, Solidus) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, Solidus) { | ||||
|   whenInputIs("/"); | ||||
|   outputMustBe("\"/\"");  // but the JSON format allows \/
 | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, Backspace) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, Backspace) { | ||||
|   whenInputIs("\b"); | ||||
|   outputMustBe("\"\\b\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, Formfeed) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, Formfeed) { | ||||
|   whenInputIs("\f"); | ||||
|   outputMustBe("\"\\f\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, Newline) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, Newline) { | ||||
|   whenInputIs("\n"); | ||||
|   outputMustBe("\"\\n\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, CarriageReturn) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, CarriageReturn) { | ||||
|   whenInputIs("\r"); | ||||
|   outputMustBe("\"\\r\""); | ||||
| } | ||||
| 
 | ||||
| TEST_F(QuotedString_PrintTo_Tests, HorizontalTab) { | ||||
| TEST_F(JsonWriter_WriteString_Tests, HorizontalTab) { | ||||
|   whenInputIs("\t"); | ||||
|   outputMustBe("\"\\t\""); | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include "Printers.hpp" | ||||
| #include <ArduinoJson/JsonArray.hpp> | ||||
|  | ||||
| class StreamPrintAdapter : public Print { | ||||
|  public: | ||||
|   explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} | ||||
|  | ||||
|   virtual size_t write(uint8_t c) { | ||||
|     _os << static_cast<char>(c); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   // cannot be assigned | ||||
|   StreamPrintAdapter& operator=(const StreamPrintAdapter&); | ||||
|  | ||||
|   std::ostream& _os; | ||||
| }; | ||||
|  | ||||
| std::ostream& ArduinoJson::operator<<(std::ostream& os, | ||||
|                                       const ArduinoJson::JsonVariant& v) { | ||||
|   StreamPrintAdapter adapter(os); | ||||
|   v.printTo(adapter); | ||||
|   return os; | ||||
| } | ||||
|  | ||||
| std::ostream& ArduinoJson::operator<<(std::ostream& os, | ||||
|                                       const ArduinoJson::JsonArray& v) { | ||||
|   StreamPrintAdapter adapter(os); | ||||
|   v.printTo(adapter); | ||||
|   return os; | ||||
| } | ||||
|  | ||||
| std::ostream& ArduinoJson::operator<<( | ||||
|     std::ostream& os, const ArduinoJson::JsonObjectSubscript& v) { | ||||
|   JsonVariant value = v; | ||||
|   return os << value; | ||||
| } | ||||
|  | ||||
| std::ostream& ArduinoJson::operator<<( | ||||
|     std::ostream& os, const ArduinoJson::JsonArraySubscript& v) { | ||||
|   JsonVariant value = v; | ||||
|   return os << value; | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <ostream> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| std::ostream& operator<<(std::ostream& os, const JsonVariant& v); | ||||
| std::ostream& operator<<(std::ostream& os, const JsonArray& v); | ||||
| std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& v); | ||||
| std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& v); | ||||
| } | ||||
| @@ -1,136 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <ArduinoJson/Internals/QuotedString.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| class QuotedString_ExtractFrom_Tests : public testing::Test { | ||||
|  protected: | ||||
|   void whenInputIs(const char *json) { | ||||
|     strcpy(_jsonString, json); | ||||
|     _result = QuotedString::extractFrom(_jsonString, &_trailing); | ||||
|   } | ||||
|  | ||||
|   void resultMustBe(const char *expected) { EXPECT_STREQ(expected, _result); } | ||||
|  | ||||
|   void trailingMustBe(const char *expected) { | ||||
|     EXPECT_STREQ(expected, _trailing); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   char _jsonString[256]; | ||||
|   char *_result; | ||||
|   char *_trailing; | ||||
| }; | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EmptyDoubleQuotedString) { | ||||
|   whenInputIs("\"\""); | ||||
|  | ||||
|   resultMustBe(""); | ||||
|   trailingMustBe(""); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, NoQuotes) { | ||||
|   whenInputIs("hello world"); | ||||
|  | ||||
|   resultMustBe(0); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, MissingClosingQuote) { | ||||
|   whenInputIs("\"hello world"); | ||||
|  | ||||
|   resultMustBe(0); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EmptySingleQuotedString) { | ||||
|   whenInputIs("''"); | ||||
|  | ||||
|   resultMustBe(""); | ||||
|   trailingMustBe(""); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, SimpleDoubleQuotedString) { | ||||
|   whenInputIs("\"hello world\""); | ||||
|  | ||||
|   resultMustBe("hello world"); | ||||
|   trailingMustBe(""); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, DoubleQuotedStringWithTrailing) { | ||||
|   whenInputIs("\"hello\" world"); | ||||
|  | ||||
|   resultMustBe("hello"); | ||||
|   trailingMustBe(" world"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, SingleQuotedStringWithTrailing) { | ||||
|   whenInputIs("'hello' world"); | ||||
|  | ||||
|   resultMustBe("hello"); | ||||
|   trailingMustBe(" world"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, CurlyBraces) { | ||||
|   whenInputIs("\"{hello:world}\""); | ||||
|   resultMustBe("{hello:world}"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, SquareBraquets) { | ||||
|   whenInputIs("\"[hello,world]\""); | ||||
|   resultMustBe("[hello,world]"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedDoubleQuote) { | ||||
|   whenInputIs("\"hello \\\"world\\\"\""); | ||||
|   resultMustBe("hello \"world\""); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedSingleQuote) { | ||||
|   whenInputIs("\"hello \\\'world\\\'\""); | ||||
|   resultMustBe("hello 'world'"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedSolidus) { | ||||
|   whenInputIs("\"hello \\/world\\/\""); | ||||
|   resultMustBe("hello /world/"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedReverseSolidus) { | ||||
|   whenInputIs("\"hello \\\\world\\\\\""); | ||||
|   resultMustBe("hello \\world\\"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedBackspace) { | ||||
|   whenInputIs("\"hello \\bworld\\b\""); | ||||
|   resultMustBe("hello \bworld\b"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedFormfeed) { | ||||
|   whenInputIs("\"hello \\fworld\\f\""); | ||||
|   resultMustBe("hello \fworld\f"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedNewline) { | ||||
|   whenInputIs("\"hello \\nworld\\n\""); | ||||
|   resultMustBe("hello \nworld\n"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedCarriageReturn) { | ||||
|   whenInputIs("\"hello \\rworld\\r\""); | ||||
|   resultMustBe("hello \rworld\r"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedTab) { | ||||
|   whenInputIs("\"hello \\tworld\\t\""); | ||||
|   resultMustBe("hello \tworld\t"); | ||||
| } | ||||
|  | ||||
| TEST_F(QuotedString_ExtractFrom_Tests, AllEscapedCharsTogether) { | ||||
|   whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\""); | ||||
|   resultMustBe("1\"2\\3/4\b5\f6\n7\r8\t9"); | ||||
| } | ||||
							
								
								
									
										62
									
								
								test/StdStream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								test/StdStream.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <sstream> | ||||
| #include <gtest/gtest.h> | ||||
| #define ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ArduinoJson.h> | ||||
|  | ||||
| TEST(StdStream, JsonVariantFalse) {  | ||||
|   std::ostringstream os; | ||||
|   JsonVariant variant = false; | ||||
|   os << variant; | ||||
|   ASSERT_EQ("false", os.str()); | ||||
| } | ||||
|  | ||||
| TEST(StdStream, JsonVariantString) {  | ||||
|   std::ostringstream os; | ||||
|   JsonVariant variant = "coucou"; | ||||
|   os << variant; | ||||
|   ASSERT_EQ("\"coucou\"", os.str()); | ||||
| } | ||||
|  | ||||
| TEST(StdStream, JsonObject) {  | ||||
|   std::ostringstream os; | ||||
|   DynamicJsonBuffer jsonBuffer; | ||||
|   JsonObject& object = jsonBuffer.createObject(); | ||||
|   object["key"] = "value"; | ||||
|   os << object; | ||||
|   ASSERT_EQ("{\"key\":\"value\"}", os.str()); | ||||
| } | ||||
|  | ||||
| TEST(StdStream, JsonObjectSubscript) {  | ||||
|   std::ostringstream os; | ||||
|   DynamicJsonBuffer jsonBuffer; | ||||
|   JsonObject& object = jsonBuffer.createObject(); | ||||
|   object["key"] = "value"; | ||||
|   os << object["key"]; | ||||
|   ASSERT_EQ("\"value\"", os.str()); | ||||
| } | ||||
|  | ||||
| TEST(StdStream, JsonArray) {  | ||||
|   std::ostringstream os; | ||||
|   DynamicJsonBuffer jsonBuffer; | ||||
|   JsonArray& array = jsonBuffer.createArray(); | ||||
|   array.add("value"); | ||||
|   os << array; | ||||
|   ASSERT_EQ("[\"value\"]", os.str()); | ||||
| } | ||||
|  | ||||
| TEST(StdStream, JsonArraySubscript) {  | ||||
|   std::ostringstream os; | ||||
|   DynamicJsonBuffer jsonBuffer; | ||||
|   JsonArray& array = jsonBuffer.createArray(); | ||||
|   array.add("value"); | ||||
|   os << array[0]; | ||||
|   ASSERT_EQ("\"value\"", os.str()); | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user