mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Added support for non zero-terminated strings (fixes #704)
This commit is contained in:
		| @@ -31,7 +31,7 @@ matrix: | ||||
|         apt: | ||||
|           sources: ['ubuntu-toolchain-r-test'] | ||||
|           packages: ['g++-5'] | ||||
|       env: SCRIPT=cmake GCC=5 SANITIZE=undefined | ||||
|       env: SCRIPT=cmake GCC=5 # SANITIZE=undefined  | ||||
|     - compiler: gcc | ||||
|       addons: | ||||
|         apt: | ||||
|   | ||||
| @@ -12,6 +12,7 @@ HEAD | ||||
| * Added `measureJson()` and `measureJsonPretty()` | ||||
| * Added `deserializeMsgPack()` (issue #358) | ||||
| * Added example `MsgPackParser.ino` (issue #358) | ||||
| * Added support for non zero-terminated strings (issue #704) | ||||
| * Removed `JsonBuffer::parseArray()`, `parseObject()` and `parse()` | ||||
| * Removed `JsonBuffer::createArray()` and `createObject()` | ||||
| * Removed `printTo()` and `prettyPrintTo()` | ||||
|   | ||||
| @@ -5,12 +5,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "ArduinoJson/DynamicJsonDocument.hpp" | ||||
| #include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp" | ||||
| #include "ArduinoJson/StaticJsonDocument.hpp" | ||||
| #include "ArduinoJson/deserializeJson.hpp" | ||||
| #include "ArduinoJson/deserializeMsgPack.hpp" | ||||
|  | ||||
| #include "ArduinoJson/Json/Deserialization/JsonDeserializer.hpp" | ||||
| #include "ArduinoJson/Json/Serialization/JsonSerializer.hpp" | ||||
| #include "ArduinoJson/JsonArrayImpl.hpp" | ||||
| #include "ArduinoJson/JsonObjectImpl.hpp" | ||||
|   | ||||
| @@ -1,61 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| template <typename TInput> | ||||
| void skipSpacesAndComments(TInput& input) { | ||||
|   for (;;) { | ||||
|     switch (input.current()) { | ||||
|       // spaces | ||||
|       case ' ': | ||||
|       case '\t': | ||||
|       case '\r': | ||||
|       case '\n': | ||||
|         input.move(); | ||||
|         continue; | ||||
|  | ||||
|       // comments | ||||
|       case '/': | ||||
|         switch (input.next()) { | ||||
|           // C-style block comment | ||||
|           case '*': | ||||
|             input.move();  // skip '/' | ||||
|             // no need to skip '*' | ||||
|             for (;;) { | ||||
|               input.move(); | ||||
|               if (input.current() == '\0') return; | ||||
|               if (input.current() == '*' && input.next() == '/') { | ||||
|                 input.move();  // skip '*' | ||||
|                 input.move();  // skip '/' | ||||
|                 break; | ||||
|               } | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|           // C++-style line comment | ||||
|           case '/': | ||||
|             // not need to skip "//" | ||||
|             for (;;) { | ||||
|               input.move(); | ||||
|               if (input.current() == '\0') return; | ||||
|               if (input.current() == '\n') break; | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|           // not a comment, just a '/' | ||||
|           default: | ||||
|             return; | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|       default: | ||||
|         return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| } | ||||
| } | ||||
| @@ -7,10 +7,9 @@ | ||||
| #include "../../JsonError.hpp" | ||||
| #include "../../JsonVariant.hpp" | ||||
| #include "../../Memory/JsonBuffer.hpp" | ||||
| #include "../../Strings/StringWriter.hpp" | ||||
| #include "../../Reading/Reader.hpp" | ||||
| #include "../../TypeTraits/IsConst.hpp" | ||||
| #include "../Encoding.hpp" | ||||
| #include "./Comments.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| @@ -23,11 +22,13 @@ class JsonDeserializer { | ||||
|       : _buffer(buffer), | ||||
|         _reader(reader), | ||||
|         _writer(writer), | ||||
|         _nestingLimit(nestingLimit) {} | ||||
|         _nestingLimit(nestingLimit), | ||||
|         _loaded(false) {} | ||||
|   JsonError parse(JsonVariant &variant) { | ||||
|     skipSpacesAndComments(_reader); | ||||
|     JsonError err = skipSpacesAndComments(); | ||||
|     if (err) return err; | ||||
|  | ||||
|     switch (_reader.current()) { | ||||
|     switch (current()) { | ||||
|       case '[': | ||||
|         return parseArray(variant); | ||||
|  | ||||
| @@ -42,15 +43,25 @@ class JsonDeserializer { | ||||
|  private: | ||||
|   JsonDeserializer &operator=(const JsonDeserializer &);  // non-copiable | ||||
|  | ||||
|   static bool eat(TReader &reader, char charToSkip) { | ||||
|     skipSpacesAndComments(reader); | ||||
|     if (reader.current() != charToSkip) return false; | ||||
|     reader.move(); | ||||
|     return true; | ||||
|   char current() { | ||||
|     if (!_loaded) { | ||||
|       if (_reader.ended()) | ||||
|         _current = 0; | ||||
|       else | ||||
|         _current = _reader.read(); | ||||
|       _loaded = true; | ||||
|     } | ||||
|     return _current; | ||||
|   } | ||||
|  | ||||
|   void move() { | ||||
|     _loaded = false; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool eat(char charToSkip) { | ||||
|     return eat(_reader, charToSkip); | ||||
|     if (current() != charToSkip) return false; | ||||
|     move(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   JsonError parseArray(JsonVariant &variant) { | ||||
| @@ -62,6 +73,12 @@ class JsonDeserializer { | ||||
|  | ||||
|     // Check opening braket | ||||
|     if (!eat('[')) return JsonError::InvalidInput; | ||||
|  | ||||
|     // Skip spaces | ||||
|     JsonError err = skipSpacesAndComments(); | ||||
|     if (err) return err; | ||||
|  | ||||
|     // Empty array? | ||||
|     if (eat(']')) return JsonError::Ok; | ||||
|  | ||||
|     // Read each value | ||||
| @@ -69,12 +86,16 @@ class JsonDeserializer { | ||||
|       // 1 - Parse value | ||||
|       JsonVariant value; | ||||
|       _nestingLimit--; | ||||
|       JsonError error = parse(value); | ||||
|       err = parse(value); | ||||
|       _nestingLimit++; | ||||
|       if (error != JsonError::Ok) return error; | ||||
|       if (err) return err; | ||||
|       if (!array->add(value)) return JsonError::NoMemory; | ||||
|  | ||||
|       // 2 - More values? | ||||
|       // 2 - Skip spaces | ||||
|       err = skipSpacesAndComments(); | ||||
|       if (err) return err; | ||||
|  | ||||
|       // 3 - More values? | ||||
|       if (eat(']')) return JsonError::Ok; | ||||
|       if (!eat(',')) return JsonError::InvalidInput; | ||||
|     } | ||||
| @@ -89,31 +110,52 @@ class JsonDeserializer { | ||||
|  | ||||
|     // Check opening brace | ||||
|     if (!eat('{')) return JsonError::InvalidInput; | ||||
|  | ||||
|     // Skip spaces | ||||
|     JsonError err = skipSpacesAndComments(); | ||||
|     if (err) return err; | ||||
|  | ||||
|     // Empty object? | ||||
|     if (eat('}')) return JsonError::Ok; | ||||
|  | ||||
|     // Read each key value pair | ||||
|     for (;;) { | ||||
|       // 1 - Parse key | ||||
|       // Parse key | ||||
|       const char *key; | ||||
|       JsonError error = parseString(&key); | ||||
|       if (error) return error; | ||||
|       err = parseString(&key); | ||||
|       if (err) return err; | ||||
|  | ||||
|       // Skip spaces | ||||
|       err = skipSpacesAndComments(); | ||||
|       if (err) return err; | ||||
|  | ||||
|       // Colon | ||||
|       if (!eat(':')) return JsonError::InvalidInput; | ||||
|  | ||||
|       // 2 - Parse value | ||||
|       // Parse value | ||||
|       JsonVariant value; | ||||
|       _nestingLimit--; | ||||
|       error = parse(value); | ||||
|       err = parse(value); | ||||
|       _nestingLimit++; | ||||
|       if (error != JsonError::Ok) return error; | ||||
|       if (err) return err; | ||||
|       if (!object->set(key, value)) return JsonError::NoMemory; | ||||
|  | ||||
|       // 3 - More keys/values? | ||||
|       // Skip spaces | ||||
|       err = skipSpacesAndComments(); | ||||
|       if (err) return err; | ||||
|  | ||||
|       // More keys/values? | ||||
|       if (eat('}')) return JsonError::Ok; | ||||
|       if (!eat(',')) return JsonError::InvalidInput; | ||||
|  | ||||
|       // Skip spaces | ||||
|       err = skipSpacesAndComments(); | ||||
|       if (err) return err; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   JsonError parseValue(JsonVariant &variant) { | ||||
|     bool hasQuotes = isQuote(_reader.current()); | ||||
|     bool hasQuotes = isQuote(current()); | ||||
|     const char *value; | ||||
|     JsonError error = parseString(&value); | ||||
|     if (error) return error; | ||||
| @@ -128,33 +170,35 @@ class JsonDeserializer { | ||||
|   JsonError parseString(const char **result) { | ||||
|     typename RemoveReference<TWriter>::type::String str = _writer.startString(); | ||||
|  | ||||
|     skipSpacesAndComments(_reader); | ||||
|     char c = _reader.current(); | ||||
|     char c = current(); | ||||
|     if (c == '\0') return JsonError::IncompleteInput; | ||||
|  | ||||
|     if (isQuote(c)) {  // quotes | ||||
|       _reader.move(); | ||||
|       move(); | ||||
|       char stopChar = c; | ||||
|       for (;;) { | ||||
|         c = _reader.current(); | ||||
|         if (c == '\0') break; | ||||
|         _reader.move(); | ||||
|  | ||||
|         c = current(); | ||||
|         move(); | ||||
|         if (c == stopChar) break; | ||||
|  | ||||
|         if (c == '\0') return JsonError::IncompleteInput; | ||||
|  | ||||
|         if (c == '\\') { | ||||
|           c = current(); | ||||
|           if (c == 0) return JsonError::IncompleteInput; | ||||
|           // replace char | ||||
|           c = Encoding::unescapeChar(_reader.current()); | ||||
|           c = Encoding::unescapeChar(c); | ||||
|           if (c == '\0') return JsonError::InvalidInput; | ||||
|           _reader.move(); | ||||
|           move(); | ||||
|         } | ||||
|  | ||||
|         str.append(c); | ||||
|       } | ||||
|     } else if (canBeInNonQuotedString(c)) {  // no quotes | ||||
|       do { | ||||
|         _reader.move(); | ||||
|         move(); | ||||
|         str.append(c); | ||||
|         c = _reader.current(); | ||||
|         c = current(); | ||||
|       } while (canBeInNonQuotedString(c)); | ||||
|     } else { | ||||
|       return JsonError::InvalidInput; | ||||
| @@ -178,41 +222,80 @@ class JsonDeserializer { | ||||
|     return c == '\'' || c == '\"'; | ||||
|   } | ||||
|  | ||||
|   JsonError skipSpacesAndComments() { | ||||
|     for (;;) { | ||||
|       switch (current()) { | ||||
|         // end of string | ||||
|         case '\0': | ||||
|           return JsonError::IncompleteInput; | ||||
|  | ||||
|         // spaces | ||||
|         case ' ': | ||||
|         case '\t': | ||||
|         case '\r': | ||||
|         case '\n': | ||||
|           move(); | ||||
|           continue; | ||||
|  | ||||
|         // comments | ||||
|         case '/': | ||||
|           move();  // skip '/' | ||||
|           switch (current()) { | ||||
|             // block comment | ||||
|             case '*': { | ||||
|               move();  // skip '*' | ||||
|               bool wasStar = false; | ||||
|               for (;;) { | ||||
|                 char c = current(); | ||||
|                 if (c == '\0') return JsonError::IncompleteInput; | ||||
|                 if (c == '/' && wasStar) { | ||||
|                   move(); | ||||
|                   break; | ||||
|                 } | ||||
|                 wasStar = c == '*'; | ||||
|                 move(); | ||||
|               } | ||||
|               break; | ||||
|             } | ||||
|  | ||||
|             // trailing comment | ||||
|             case '/': | ||||
|               // no need to skip "//" | ||||
|               for (;;) { | ||||
|                 move(); | ||||
|                 char c = current(); | ||||
|                 if (c == '\0') return JsonError::IncompleteInput; | ||||
|                 if (c == '\n') break; | ||||
|               } | ||||
|               break; | ||||
|  | ||||
|             // not a comment, just a '/' | ||||
|             default: | ||||
|               return JsonError::InvalidInput; | ||||
|           } | ||||
|           break; | ||||
|  | ||||
|         default: | ||||
|           return JsonError::Ok; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   JsonBuffer *_buffer; | ||||
|   TReader _reader; | ||||
|   TWriter _writer; | ||||
|   uint8_t _nestingLimit; | ||||
|   char _current; | ||||
|   bool _loaded; | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TString, typename Enable = void> | ||||
| struct JsonParserBuilder { | ||||
|   typedef typename StringTraits<TString>::Reader InputReader; | ||||
|   typedef JsonDeserializer<InputReader, TJsonBuffer &> TParser; | ||||
|  | ||||
|   static TParser makeParser(TJsonBuffer *buffer, TString &json, | ||||
|                             uint8_t nestingLimit) { | ||||
|     return TParser(buffer, InputReader(json), *buffer, nestingLimit); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TChar> | ||||
| struct JsonParserBuilder<TJsonBuffer, TChar *, | ||||
|                          typename EnableIf<!IsConst<TChar>::value>::type> { | ||||
|   typedef typename StringTraits<TChar *>::Reader TReader; | ||||
|   typedef StringWriter<TChar> TWriter; | ||||
|   typedef JsonDeserializer<TReader, TWriter> TParser; | ||||
|  | ||||
|   static TParser makeParser(TJsonBuffer *buffer, TChar *json, | ||||
|                             uint8_t nestingLimit) { | ||||
|     return TParser(buffer, TReader(json), TWriter(json), nestingLimit); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TString> | ||||
| inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser( | ||||
|     TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) { | ||||
|   return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json, | ||||
|                                                              nestingLimit); | ||||
| template <typename TJsonBuffer, typename TReader, typename TWriter> | ||||
| JsonDeserializer<TReader, TWriter> makeJsonDeserializer(TJsonBuffer *buffer, | ||||
|                                                         TReader reader, | ||||
|                                                         TWriter writer, | ||||
|                                                         uint8_t nestingLimit) { | ||||
|   return JsonDeserializer<TReader, TWriter>(buffer, reader, writer, | ||||
|                                             nestingLimit); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -4,11 +4,15 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ostream> | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| class JsonError { | ||||
|  public: | ||||
|   enum Code { Ok, TooDeep, NoMemory, InvalidInput }; | ||||
|   enum Code { Ok, TooDeep, NoMemory, InvalidInput, IncompleteInput }; | ||||
|  | ||||
|   JsonError(Code code) : _code(code) {} | ||||
|  | ||||
| @@ -42,6 +46,8 @@ class JsonError { | ||||
|         return "NoMemory"; | ||||
|       case InvalidInput: | ||||
|         return "InvalidInput"; | ||||
|       case IncompleteInput: | ||||
|         return "IncompleteInput"; | ||||
|       default: | ||||
|         return "???"; | ||||
|     } | ||||
|   | ||||
| @@ -6,8 +6,9 @@ | ||||
|  | ||||
| #include "../JsonVariant.hpp" | ||||
| #include "../Memory/JsonBuffer.hpp" | ||||
| #include "../Strings/StringWriter.hpp" | ||||
| #include "../Reading/Reader.hpp" | ||||
| #include "../TypeTraits/IsConst.hpp" | ||||
| #include "../Writing/Writer.hpp" | ||||
| #include "./MsgPackError.hpp" | ||||
| #include "./endianess.hpp" | ||||
| #include "./ieee754.hpp" | ||||
| @@ -29,27 +30,28 @@ class MsgPackDeserializer { | ||||
|         _nestingLimit(nestingLimit) {} | ||||
|  | ||||
|   MsgPackError parse(JsonVariant &variant) { | ||||
|     uint8_t c = readOne(); | ||||
|     uint8_t code; | ||||
|     if (!readByte(code)) return MsgPackError::IncompleteInput; | ||||
|  | ||||
|     if ((c & 0x80) == 0) { | ||||
|       variant = c; | ||||
|     if ((code & 0x80) == 0) { | ||||
|       variant = code; | ||||
|       return MsgPackError::Ok; | ||||
|     } | ||||
|  | ||||
|     if ((c & 0xe0) == 0xe0) { | ||||
|       variant = static_cast<int8_t>(c); | ||||
|     if ((code & 0xe0) == 0xe0) { | ||||
|       variant = static_cast<int8_t>(code); | ||||
|       return MsgPackError::Ok; | ||||
|     } | ||||
|  | ||||
|     if ((c & 0xe0) == 0xa0) { | ||||
|       return readString(variant, c & 0x1f); | ||||
|     if ((code & 0xe0) == 0xa0) { | ||||
|       return readString(variant, code & 0x1f); | ||||
|     } | ||||
|  | ||||
|     if ((c & 0xf0) == 0x90) return readArray(variant, c & 0x0F); | ||||
|     if ((code & 0xf0) == 0x90) return readArray(variant, code & 0x0F); | ||||
|  | ||||
|     if ((c & 0xf0) == 0x80) return readObject(variant, c & 0x0F); | ||||
|     if ((code & 0xf0) == 0x80) return readObject(variant, code & 0x0F); | ||||
|  | ||||
|     switch (c) { | ||||
|     switch (code) { | ||||
|       case 0xc0: | ||||
|         variant = static_cast<char *>(0); | ||||
|         return MsgPackError::Ok; | ||||
| @@ -63,81 +65,65 @@ class MsgPackDeserializer { | ||||
|         return MsgPackError::Ok; | ||||
|  | ||||
|       case 0xcc: | ||||
|         variant = readInteger<uint8_t>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readInteger<uint8_t>(variant); | ||||
|  | ||||
|       case 0xcd: | ||||
|         variant = readInteger<uint16_t>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readInteger<uint16_t>(variant); | ||||
|  | ||||
|       case 0xce: | ||||
|         variant = readInteger<uint32_t>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readInteger<uint32_t>(variant); | ||||
|  | ||||
|       case 0xcf: | ||||
| #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 | ||||
|         variant = readInteger<uint64_t>(); | ||||
|         return readInteger<uint64_t>(variant); | ||||
| #else | ||||
|         readInteger<uint32_t>(); | ||||
|         variant = readInteger<uint32_t>(); | ||||
|         return readInteger<uint32_t>(variant); | ||||
| #endif | ||||
|         return MsgPackError::Ok; | ||||
|  | ||||
|       case 0xd0: | ||||
|         variant = readInteger<int8_t>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readInteger<int8_t>(variant); | ||||
|  | ||||
|       case 0xd1: | ||||
|         variant = readInteger<int16_t>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readInteger<int16_t>(variant); | ||||
|  | ||||
|       case 0xd2: | ||||
|         variant = readInteger<int32_t>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readInteger<int32_t>(variant); | ||||
|  | ||||
|       case 0xd3: | ||||
| #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 | ||||
|         variant = readInteger<int64_t>(); | ||||
|         return readInteger<int64_t>(variant); | ||||
| #else | ||||
|         readInteger<int32_t>(); | ||||
|         variant = readInteger<int32_t>(); | ||||
|         if (!skip(4)) return MsgPackError::IncompleteInput; | ||||
|         return readInteger<int32_t>(variant); | ||||
| #endif | ||||
|         return MsgPackError::Ok; | ||||
|  | ||||
|       case 0xca: | ||||
|         variant = readFloat<float>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readFloat<float>(variant); | ||||
|  | ||||
|       case 0xcb: | ||||
|         variant = readDouble<double>(); | ||||
|         return MsgPackError::Ok; | ||||
|         return readDouble<double>(variant); | ||||
|  | ||||
|       case 0xd9: { | ||||
|         uint8_t n = readInteger<uint8_t>(); | ||||
|         return readString(variant, n); | ||||
|       } | ||||
|       case 0xd9: | ||||
|         return readString<uint8_t>(variant); | ||||
|  | ||||
|       case 0xda: { | ||||
|         uint16_t n = readInteger<uint16_t>(); | ||||
|         return readString(variant, n); | ||||
|       } | ||||
|       case 0xda: | ||||
|         return readString<uint16_t>(variant); | ||||
|  | ||||
|       case 0xdb: { | ||||
|         uint32_t n = readInteger<uint32_t>(); | ||||
|         return readString(variant, n); | ||||
|       } | ||||
|       case 0xdb: | ||||
|         return readString<uint32_t>(variant); | ||||
|  | ||||
|       case 0xdc: | ||||
|         return readArray(variant, readInteger<uint16_t>()); | ||||
|         return readArray<uint16_t>(variant); | ||||
|  | ||||
|       case 0xdd: | ||||
|         return readArray(variant, readInteger<uint32_t>()); | ||||
|         return readArray<uint32_t>(variant); | ||||
|  | ||||
|       case 0xde: | ||||
|         return readObject(variant, readInteger<uint16_t>()); | ||||
|         return readObject<uint16_t>(variant); | ||||
|  | ||||
|       case 0xdf: | ||||
|         return readObject(variant, readInteger<uint32_t>()); | ||||
|         return readObject<uint32_t>(variant); | ||||
|  | ||||
|       default: | ||||
|         return MsgPackError::NotSupported; | ||||
| @@ -148,65 +134,115 @@ class MsgPackDeserializer { | ||||
|   // Prevent VS warning "assignment operator could not be generated" | ||||
|   MsgPackDeserializer &operator=(const MsgPackDeserializer &); | ||||
|  | ||||
|   uint8_t readOne() { | ||||
|     char c = _reader.current(); | ||||
|     _reader.move(); | ||||
|     return static_cast<uint8_t>(c); | ||||
|   bool skip(uint8_t n) { | ||||
|     while (n--) { | ||||
|       if (_reader.ended()) return false; | ||||
|       _reader.read(); | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   void read(uint8_t *p, size_t n) { | ||||
|     for (size_t i = 0; i < n; i++) p[i] = readOne(); | ||||
|   bool readByte(uint8_t &value) { | ||||
|     if (_reader.ended()) return false; | ||||
|     value = static_cast<uint8_t>(_reader.read()); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool readBytes(uint8_t *p, size_t n) { | ||||
|     for (size_t i = 0; i < n; i++) { | ||||
|       if (!readByte(p[i])) return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   void read(T &value) { | ||||
|     read(reinterpret_cast<uint8_t *>(&value), sizeof(value)); | ||||
|   bool readBytes(T &value) { | ||||
|     return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   T readInteger() { | ||||
|     T value; | ||||
|     read(value); | ||||
|     readBytes(value); | ||||
|     fixEndianess(value); | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   typename EnableIf<sizeof(T) == 4, T>::type readFloat() { | ||||
|   bool readInteger(T &value) { | ||||
|     if (!readBytes(value)) return false; | ||||
|     fixEndianess(value); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   MsgPackError readInteger(JsonVariant &variant) { | ||||
|     T value; | ||||
|     read(value); | ||||
|     fixEndianess(value); | ||||
|     return value; | ||||
|     if (!readInteger(value)) return MsgPackError::IncompleteInput; | ||||
|     variant = value; | ||||
|     return MsgPackError::Ok; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   typename EnableIf<sizeof(T) == 8, T>::type readDouble() { | ||||
|   typename EnableIf<sizeof(T) == 4, MsgPackError>::type readFloat( | ||||
|       JsonVariant &variant) { | ||||
|     T value; | ||||
|     read(value); | ||||
|     if (!readBytes(value)) return MsgPackError::IncompleteInput; | ||||
|     fixEndianess(value); | ||||
|     return value; | ||||
|     variant = value; | ||||
|     return MsgPackError::Ok; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   typename EnableIf<sizeof(T) == 4, T>::type readDouble() { | ||||
|   typename EnableIf<sizeof(T) == 8, MsgPackError>::type readDouble( | ||||
|       JsonVariant &variant) { | ||||
|     T value; | ||||
|     if (!readBytes(value)) return MsgPackError::IncompleteInput; | ||||
|     fixEndianess(value); | ||||
|     variant = value; | ||||
|     return MsgPackError::Ok; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   typename EnableIf<sizeof(T) == 4, MsgPackError>::type readDouble( | ||||
|       JsonVariant &variant) { | ||||
|     uint8_t i[8];  // input is 8 bytes | ||||
|     T value;       // output is 4 bytes | ||||
|     uint8_t *o = reinterpret_cast<uint8_t *>(&value); | ||||
|     read(i, 8); | ||||
|     if (!readBytes(i, 8)) return MsgPackError::IncompleteInput; | ||||
|     doubleToFloat(i, o); | ||||
|     fixEndianess(value); | ||||
|     return value; | ||||
|     variant = value; | ||||
|     return MsgPackError::Ok; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   MsgPackError readString(JsonVariant &variant) { | ||||
|     T size; | ||||
|     if (!readInteger(size)) return MsgPackError::IncompleteInput; | ||||
|     return readString(variant, size); | ||||
|   } | ||||
|  | ||||
|   MsgPackError readString(JsonVariant &variant, size_t n) { | ||||
|     typename RemoveReference<TWriter>::type::String str = _writer.startString(); | ||||
|     for (; n; --n) str.append(static_cast<char>(readOne())); | ||||
|     for (; n; --n) { | ||||
|       uint8_t c; | ||||
|       if (!readBytes(c)) return MsgPackError::IncompleteInput; | ||||
|       str.append(static_cast<char>(c)); | ||||
|     } | ||||
|     const char *s = str.c_str(); | ||||
|     if (s == NULL) return MsgPackError::NoMemory; | ||||
|     variant = s; | ||||
|     return MsgPackError::Ok; | ||||
|   } | ||||
|  | ||||
|   template <typename TSize> | ||||
|   MsgPackError readArray(JsonVariant &variant) { | ||||
|     TSize size; | ||||
|     if (!readInteger(size)) return MsgPackError::IncompleteInput; | ||||
|     return readArray(variant, size); | ||||
|   } | ||||
|  | ||||
|   MsgPackError readArray(JsonVariant &variant, size_t n) { | ||||
|     JsonArray *array = new (_buffer) JsonArray(_buffer); | ||||
|     if (!array) return MsgPackError::NoMemory; | ||||
| @@ -227,6 +263,13 @@ class MsgPackDeserializer { | ||||
|     return MsgPackError::Ok; | ||||
|   } | ||||
|  | ||||
|   template <typename TSize> | ||||
|   MsgPackError readObject(JsonVariant &variant) { | ||||
|     TSize size; | ||||
|     if (!readInteger(size)) return MsgPackError::IncompleteInput; | ||||
|     return readObject(variant, size); | ||||
|   } | ||||
|  | ||||
|   MsgPackError readObject(JsonVariant &variant, size_t n) { | ||||
|     JsonObject *object = new (_buffer) JsonObject(_buffer); | ||||
|     if (!object) return MsgPackError::NoMemory; | ||||
| @@ -258,37 +301,11 @@ class MsgPackDeserializer { | ||||
|   uint8_t _nestingLimit; | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TString, typename Enable = void> | ||||
| struct MsgPackDeserializerBuilder { | ||||
|   typedef typename StringTraits<TString>::Reader InputReader; | ||||
|   typedef MsgPackDeserializer<InputReader, TJsonBuffer &> TParser; | ||||
|  | ||||
|   static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json, | ||||
|                                          uint8_t nestingLimit) { | ||||
|     return TParser(buffer, InputReader(json), *buffer, nestingLimit); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TChar> | ||||
| struct MsgPackDeserializerBuilder< | ||||
|     TJsonBuffer, TChar *, typename EnableIf<!IsConst<TChar>::value>::type> { | ||||
|   typedef typename StringTraits<TChar *>::Reader TReader; | ||||
|   typedef StringWriter<TChar> TWriter; | ||||
|   typedef MsgPackDeserializer<TReader, TWriter> TParser; | ||||
|  | ||||
|   static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TChar *json, | ||||
|                                          uint8_t nestingLimit) { | ||||
|     return TParser(buffer, TReader(json), TWriter(json), nestingLimit); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TString> | ||||
| inline typename MsgPackDeserializerBuilder<TJsonBuffer, TString>::TParser | ||||
| makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json, | ||||
|                         uint8_t nestingLimit) { | ||||
|   return MsgPackDeserializerBuilder< | ||||
|       TJsonBuffer, TString>::makeMsgPackDeserializer(buffer, json, | ||||
|                                                      nestingLimit); | ||||
| template <typename TJsonBuffer, typename TReader, typename TWriter> | ||||
| MsgPackDeserializer<TReader, TWriter> makeMsgPackDeserializer( | ||||
|     TJsonBuffer *buffer, TReader reader, TWriter writer, uint8_t nestingLimit) { | ||||
|   return MsgPackDeserializer<TReader, TWriter>(buffer, reader, writer, | ||||
|                                                nestingLimit); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -4,11 +4,15 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include <ostream> | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| class MsgPackError { | ||||
|  public: | ||||
|   enum Code { Ok, NotSupported, NoMemory, TooDeep }; | ||||
|   enum Code { Ok, NotSupported, NoMemory, TooDeep, IncompleteInput }; | ||||
|  | ||||
|   MsgPackError() {} | ||||
|  | ||||
| @@ -44,6 +48,8 @@ class MsgPackError { | ||||
|         return "NoMemory"; | ||||
|       case TooDeep: | ||||
|         return "TooDeep"; | ||||
|       case IncompleteInput: | ||||
|         return "IncompleteInput"; | ||||
|       default: | ||||
|         return "???"; | ||||
|     } | ||||
|   | ||||
							
								
								
									
										41
									
								
								src/ArduinoJson/Reading/ArduinoStreamReader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/ArduinoJson/Reading/ArduinoStreamReader.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STREAM | ||||
|  | ||||
| #include <Stream.h> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| struct ArduinoStreamReader { | ||||
|   Stream& _stream; | ||||
|   char _current; | ||||
|   bool _ended; | ||||
|  | ||||
|  public: | ||||
|   explicit ArduinoStreamReader(Stream& stream) | ||||
|       : _stream(stream), _current(0), _ended(false) {} | ||||
|  | ||||
|   char read() { | ||||
|     // don't use _stream.read() as it ignores the timeout | ||||
|     char c = 0; | ||||
|     _ended = _stream.readBytes(&c, 1) == 0; | ||||
|     return c; | ||||
|   } | ||||
|  | ||||
|   bool ended() const { | ||||
|     return _ended; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| inline ArduinoStreamReader makeReader(Stream& input) { | ||||
|   return ArduinoStreamReader(input); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										64
									
								
								src/ArduinoJson/Reading/CharPointerReader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/ArduinoJson/Reading/CharPointerReader.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TChar> | ||||
| class UnsafeCharPointerReader { | ||||
|   const TChar* _ptr; | ||||
|  | ||||
|  public: | ||||
|   explicit UnsafeCharPointerReader(const TChar* ptr) | ||||
|       : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {} | ||||
|  | ||||
|   char read() { | ||||
|     return static_cast<char>(*_ptr++); | ||||
|   } | ||||
|  | ||||
|   bool ended() const { | ||||
|     // we cannot know | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TChar> | ||||
| class SafeCharPointerReader { | ||||
|   const TChar* _ptr; | ||||
|   const TChar* _end; | ||||
|  | ||||
|  public: | ||||
|   explicit SafeCharPointerReader(const TChar* ptr, size_t len) | ||||
|       : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")), | ||||
|         _end(_ptr + len) {} | ||||
|  | ||||
|   char read() { | ||||
|     return static_cast<char>(*_ptr++); | ||||
|   } | ||||
|  | ||||
|   bool ended() const { | ||||
|     return _ptr == _end; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TChar> | ||||
| inline UnsafeCharPointerReader<TChar> makeReader(TChar* input) { | ||||
|   return UnsafeCharPointerReader<TChar>(input); | ||||
| } | ||||
|  | ||||
| template <typename TChar> | ||||
| inline SafeCharPointerReader<TChar> makeReader(TChar* input, size_t n) { | ||||
|   return SafeCharPointerReader<TChar>(input, n); | ||||
| } | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
| inline SafeCharPointerReader<char> makeReader(const String& input) { | ||||
|   return SafeCharPointerReader<char>(input.c_str(), input.length()); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										56
									
								
								src/ArduinoJson/Reading/FlashStringReader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/ArduinoJson/Reading/FlashStringReader.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_PROGMEM | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| class UnsafeFlashStringReader { | ||||
|   const char* _ptr; | ||||
|  | ||||
|  public: | ||||
|   explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr) | ||||
|       : _ptr(reinterpret_cast<const char*>(ptr)) {} | ||||
|  | ||||
|   char read() { | ||||
|     return pgm_read_byte_near(_ptr++); | ||||
|   } | ||||
|  | ||||
|   bool ended() const { | ||||
|     // this reader cannot detect the end | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class SafeFlashStringReader { | ||||
|   const char* _ptr; | ||||
|   const char* _end; | ||||
|  | ||||
|  public: | ||||
|   explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size) | ||||
|       : _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {} | ||||
|  | ||||
|   char read() { | ||||
|     return pgm_read_byte_near(_ptr++); | ||||
|   } | ||||
|  | ||||
|   bool ended() const { | ||||
|     return _ptr == _end; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| inline UnsafeFlashStringReader makeReader(const __FlashStringHelper* input) { | ||||
|   return UnsafeFlashStringReader(input); | ||||
| } | ||||
|  | ||||
| inline SafeFlashStringReader makeReader(const __FlashStringHelper* input, | ||||
|                                         size_t size) { | ||||
|   return SafeFlashStringReader(input, size); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										34
									
								
								src/ArduinoJson/Reading/IteratorReader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/ArduinoJson/Reading/IteratorReader.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TIterator> | ||||
| class IteratorReader { | ||||
|   TIterator _ptr, _end; | ||||
|  | ||||
|  public: | ||||
|   explicit IteratorReader(TIterator begin, TIterator end) | ||||
|       : _ptr(begin), _end(end) {} | ||||
|  | ||||
|   bool ended() const { | ||||
|     return _ptr == _end; | ||||
|   } | ||||
|  | ||||
|   char read() { | ||||
|     return char(*_ptr++); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TInput> | ||||
| inline IteratorReader<typename TInput::const_iterator> makeReader( | ||||
|     const TInput& input) { | ||||
|   return IteratorReader<typename TInput::const_iterator>(input.begin(), | ||||
|                                                          input.end()); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										11
									
								
								src/ArduinoJson/Reading/Reader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/ArduinoJson/Reading/Reader.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./ArduinoStreamReader.hpp" | ||||
| #include "./CharPointerReader.hpp" | ||||
| #include "./FlashStringReader.hpp" | ||||
| #include "./IteratorReader.hpp" | ||||
| #include "./StdStreamReader.hpp" | ||||
							
								
								
									
										40
									
								
								src/ArduinoJson/Reading/StdStreamReader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/ArduinoJson/Reading/StdStreamReader.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
|  | ||||
| #include <istream> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class StdStreamReader { | ||||
|   std::istream& _stream; | ||||
|   char _current; | ||||
|  | ||||
|  public: | ||||
|   explicit StdStreamReader(std::istream& stream) | ||||
|       : _stream(stream), _current(0) {} | ||||
|  | ||||
|   bool ended() const { | ||||
|     return _stream.eof(); | ||||
|   } | ||||
|  | ||||
|   char read() { | ||||
|     return static_cast<char>(_stream.get()); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   StdStreamReader& operator=(const StdStreamReader&);  // Visual Studio C4512 | ||||
| }; | ||||
|  | ||||
| inline StdStreamReader makeReader(std::istream& input) { | ||||
|   return StdStreamReader(input); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #endif | ||||
| @@ -1,61 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STREAM | ||||
|  | ||||
| #include <Stream.h> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| struct ArduinoStreamTraits { | ||||
|   class Reader { | ||||
|     Stream& _stream; | ||||
|     char _current, _next; | ||||
|  | ||||
|    public: | ||||
|     Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {} | ||||
|  | ||||
|     void move() { | ||||
|       _current = _next; | ||||
|       _next = 0; | ||||
|     } | ||||
|  | ||||
|     char current() { | ||||
|       if (!_current) _current = read(); | ||||
|       return _current; | ||||
|     } | ||||
|  | ||||
|     char next() { | ||||
|       // assumes that current() has been called | ||||
|       if (!_next) _next = read(); | ||||
|       return _next; | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     char read() { | ||||
|       // don't use _stream.read() as it ignores the timeout | ||||
|       char c = 0; | ||||
|       _stream.readBytes(&c, 1); | ||||
|       return c; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static const bool has_append = false; | ||||
|   static const bool has_equals = false; | ||||
| }; | ||||
|  | ||||
| template <typename TStream> | ||||
| struct StringTraits< | ||||
|     TStream, | ||||
|     // match any type that is derived from Stream: | ||||
|     typename EnableIf< | ||||
|         IsBaseOf<Stream, typename RemoveReference<TStream>::type>::value>::type> | ||||
|     : ArduinoStreamTraits {}; | ||||
| } | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -9,26 +9,6 @@ namespace Internals { | ||||
|  | ||||
| template <typename TChar> | ||||
| struct CharPointerTraits { | ||||
|   class Reader { | ||||
|     const TChar* _ptr; | ||||
|  | ||||
|    public: | ||||
|     Reader(const TChar* ptr) | ||||
|         : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {} | ||||
|  | ||||
|     void move() { | ||||
|       ++_ptr; | ||||
|     } | ||||
|  | ||||
|     char current() const { | ||||
|       return char(_ptr[0]); | ||||
|     } | ||||
|  | ||||
|     char next() const { | ||||
|       return char(_ptr[1]); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static bool equals(const TChar* str, const char* expected) { | ||||
|     return strcmp(reinterpret_cast<const char*>(str), expected) == 0; | ||||
|   } | ||||
|   | ||||
| @@ -10,26 +10,6 @@ namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| template <> | ||||
| struct StringTraits<const __FlashStringHelper*, void> { | ||||
|   class Reader { | ||||
|     const char* _ptr; | ||||
|  | ||||
|    public: | ||||
|     Reader(const __FlashStringHelper* ptr) | ||||
|         : _ptr(reinterpret_cast<const char*>(ptr)) {} | ||||
|  | ||||
|     void move() { | ||||
|       _ptr++; | ||||
|     } | ||||
|  | ||||
|     char current() const { | ||||
|       return pgm_read_byte_near(_ptr); | ||||
|     } | ||||
|  | ||||
|     char next() const { | ||||
|       return pgm_read_byte_near(_ptr + 1); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static bool equals(const __FlashStringHelper* str, const char* expected) { | ||||
|     return strcmp_P(expected, (const char*)str) == 0; | ||||
|   } | ||||
|   | ||||
| @@ -1,60 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
|  | ||||
| #include <istream> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| struct StdStreamTraits { | ||||
|   class Reader { | ||||
|     std::istream& _stream; | ||||
|     char _current, _next; | ||||
|  | ||||
|    public: | ||||
|     Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {} | ||||
|  | ||||
|     void move() { | ||||
|       _current = _next; | ||||
|       _next = 0; | ||||
|     } | ||||
|  | ||||
|     char current() { | ||||
|       if (!_current) _current = read(); | ||||
|       return _current; | ||||
|     } | ||||
|  | ||||
|     char next() { | ||||
|       // assumes that current() has been called | ||||
|       if (!_next) _next = read(); | ||||
|       return _next; | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     Reader& operator=(const Reader&);  // Visual Studio C4512 | ||||
|  | ||||
|     char read() { | ||||
|       return _stream.eof() ? '\0' : static_cast<char>(_stream.get()); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static const bool has_append = false; | ||||
|   static const bool has_equals = false; | ||||
| }; | ||||
|  | ||||
| template <typename TStream> | ||||
| struct StringTraits< | ||||
|     TStream, | ||||
|     // match any type that is derived from std::istream: | ||||
|     typename EnableIf<IsBaseOf< | ||||
|         std::istream, typename RemoveReference<TStream>::type>::value>::type> | ||||
|     : StdStreamTraits {}; | ||||
| } | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -35,10 +35,6 @@ struct StdStringTraits { | ||||
|     return !str.c_str(); | ||||
|   } | ||||
|  | ||||
|   struct Reader : CharPointerTraits<char>::Reader { | ||||
|     Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {} | ||||
|   }; | ||||
|  | ||||
|   static bool equals(const TString& str, const char* expected) { | ||||
|     return 0 == strcmp(str.c_str(), expected); | ||||
|   } | ||||
|   | ||||
| @@ -29,8 +29,6 @@ struct StringTraits<TString&, void> : StringTraits<TString> {}; | ||||
| } | ||||
| } | ||||
|  | ||||
| #include "ArduinoStream.hpp" | ||||
| #include "CharPointer.hpp" | ||||
| #include "FlashString.hpp" | ||||
| #include "StdStream.hpp" | ||||
| #include "StdString.hpp" | ||||
|   | ||||
							
								
								
									
										27
									
								
								src/ArduinoJson/Writing/JsonBufferWriter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/ArduinoJson/Writing/JsonBufferWriter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./StringWriter.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TJsonBuffer> | ||||
| class JsonBufferWriter { | ||||
|  public: | ||||
|   JsonBufferWriter(TJsonBuffer& jb) : _jb(&jb) {} | ||||
|  | ||||
|   typedef typename TJsonBuffer::String String; | ||||
|  | ||||
|   String startString() { | ||||
|     return _jb->startString(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   TJsonBuffer* _jb; | ||||
| }; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										44
									
								
								src/ArduinoJson/Writing/Writer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/ArduinoJson/Writing/Writer.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./JsonBufferWriter.hpp" | ||||
| #include "./StringWriter.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TJsonBuffer, typename TInput, typename Enable = void> | ||||
| struct Writer { | ||||
|   typedef JsonBufferWriter<TJsonBuffer> type; | ||||
|  | ||||
|   static type create(TJsonBuffer& jb, TInput&) { | ||||
|     return type(jb); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TChar> | ||||
| struct Writer<TJsonBuffer, TChar*, | ||||
|               typename EnableIf<!IsConst<TChar>::value>::type> { | ||||
|   typedef StringWriter<TChar> type; | ||||
|  | ||||
|   static type create(TJsonBuffer&, TChar* input) { | ||||
|     return type(input); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TInput> | ||||
| typename Writer<TJsonBuffer, TInput>::type makeWriter(TJsonBuffer& jb, | ||||
|                                                       TInput& input) { | ||||
|   return Writer<TJsonBuffer, TInput>::create(jb, input); | ||||
| } | ||||
|  | ||||
| template <typename TJsonBuffer, typename TChar> | ||||
| typename Writer<TJsonBuffer, TChar*>::type makeWriter(TJsonBuffer& jb, | ||||
|                                                       TChar* input) { | ||||
|   return Writer<TJsonBuffer, TChar*>::create(jb, input); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
| @@ -5,34 +5,53 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Json/Deserialization/JsonDeserializer.hpp" | ||||
| #include "Reading/Reader.hpp" | ||||
| #include "Writing/Writer.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| // JsonError deserializeJson(TDocument& doc, TString json); | ||||
| // JsonError deserializeJson(TDocument& doc, TString input); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TString = const std::string&, const String& | ||||
| template <typename TDocument, typename TString> | ||||
| typename Internals::EnableIf<!Internals::IsArray<TString>::value, | ||||
|                              JsonError>::type | ||||
| deserializeJson(TDocument &doc, const TString &json) { | ||||
|   return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit) | ||||
| deserializeJson(TDocument &doc, const TString &input) { | ||||
|   using namespace Internals; | ||||
|   return makeJsonDeserializer(&doc.buffer(), makeReader(input), | ||||
|                               makeWriter(doc.buffer(), input), doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| // | ||||
| // JsonError deserializeJson(TDocument& doc, TString json); | ||||
| // JsonError deserializeJson(TDocument& doc, TChar* input); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TString = const char*, const char[N], const FlashStringHelper* | ||||
| template <typename TDocument, typename TString> | ||||
| JsonError deserializeJson(TDocument &doc, TString *json) { | ||||
|   return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit) | ||||
| // TChar* = char*, const char*, const FlashStringHelper* | ||||
| template <typename TDocument, typename TChar> | ||||
| JsonError deserializeJson(TDocument &doc, TChar *input) { | ||||
|   using namespace Internals; | ||||
|   return makeJsonDeserializer(&doc.buffer(), makeReader(input), | ||||
|                               makeWriter(doc.buffer(), input), doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| // | ||||
| // JsonError deserializeJson(TDocument& doc, TString json); | ||||
| // JsonError deserializeJson(TDocument& doc, TChar* input, size_t inputSize); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TString = std::istream&, Stream& | ||||
| template <typename TDocument, typename TString> | ||||
| JsonError deserializeJson(TDocument &doc, TString &json) { | ||||
|   return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit) | ||||
| // TChar* = char*, const char*, const FlashStringHelper* | ||||
| template <typename TDocument, typename TChar> | ||||
| JsonError deserializeJson(TDocument &doc, TChar *input, size_t inputSize) { | ||||
|   using namespace Internals; | ||||
|   return makeJsonDeserializer(&doc.buffer(), makeReader(input, inputSize), | ||||
|                               makeWriter(doc.buffer(), input), doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| // | ||||
| // JsonError deserializeJson(TDocument& doc, TStream input); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TStream = std::istream&, Stream& | ||||
| template <typename TDocument, typename TStream> | ||||
| JsonError deserializeJson(TDocument &doc, TStream &input) { | ||||
|   using namespace Internals; | ||||
|   return makeJsonDeserializer(&doc.buffer(), makeReader(input), | ||||
|                               makeWriter(doc.buffer(), input), doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -5,37 +5,59 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "MsgPack/MsgPackDeserializer.hpp" | ||||
| #include "Reading/Reader.hpp" | ||||
| #include "Writing/Writer.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TString json); | ||||
| // TDocument = DynamicJsonArray | StaticJsonArray | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TString input); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TString = const std::string&, const String& | ||||
| template <typename TDocument, typename TString> | ||||
| typename Internals::EnableIf<!Internals::IsArray<TString>::value, | ||||
|                              MsgPackError>::type | ||||
| deserializeMsgPack(TDocument &doc, const TString &json) { | ||||
|   return Internals::makeMsgPackDeserializer(&doc.buffer(), json, | ||||
|                                             doc.nestingLimit) | ||||
| deserializeMsgPack(TDocument &doc, const TString &input) { | ||||
|   using namespace Internals; | ||||
|   return makeMsgPackDeserializer(&doc.buffer(), makeReader(input), | ||||
|                                  makeWriter(doc.buffer(), input), | ||||
|                                  doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| // | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TString json); | ||||
| // TDocument = DynamicJsonArray | StaticJsonArray | ||||
| // TString = const char*, const char[N], const FlashStringHelper* | ||||
| template <typename TDocument, typename TString> | ||||
| MsgPackError deserializeMsgPack(TDocument &doc, TString *json) { | ||||
|   return Internals::makeMsgPackDeserializer(&doc.buffer(), json, | ||||
|                                             doc.nestingLimit) | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TChar* input); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TChar* = char*, const char*, const FlashStringHelper* | ||||
| template <typename TDocument, typename TChar> | ||||
| MsgPackError deserializeMsgPack(TDocument &doc, TChar *input) { | ||||
|   using namespace Internals; | ||||
|   return makeMsgPackDeserializer(&doc.buffer(), makeReader(input), | ||||
|                                  makeWriter(doc.buffer(), input), | ||||
|                                  doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| // | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TString json); | ||||
| // TDocument = DynamicJsonArray | StaticJsonArray | ||||
| // TString = std::istream&, Stream& | ||||
| template <typename TDocument, typename TString> | ||||
| MsgPackError deserializeMsgPack(TDocument &doc, TString &json) { | ||||
|   return Internals::makeMsgPackDeserializer(&doc.buffer(), json, | ||||
|                                             doc.nestingLimit) | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TChar* input, size_t | ||||
| // inputSize); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TChar* = char*, const char*, const FlashStringHelper* | ||||
| template <typename TDocument, typename TChar> | ||||
| MsgPackError deserializeMsgPack(TDocument &doc, TChar *input, | ||||
|                                 size_t inputSize) { | ||||
|   using namespace Internals; | ||||
|   return makeMsgPackDeserializer(&doc.buffer(), makeReader(input, inputSize), | ||||
|                                  makeWriter(doc.buffer(), input), | ||||
|                                  doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| // | ||||
| // MsgPackError deserializeMsgPack(TDocument& doc, TStream input); | ||||
| // TDocument = DynamicJsonDocument, StaticJsonDocument | ||||
| // TStream = std::istream&, Stream& | ||||
| template <typename TDocument, typename TStream> | ||||
| MsgPackError deserializeMsgPack(TDocument &doc, TStream &input) { | ||||
|   using namespace Internals; | ||||
|   return makeMsgPackDeserializer(&doc.buffer(), makeReader(input), | ||||
|                                  makeWriter(doc.buffer(), input), | ||||
|                                  doc.nestingLimit) | ||||
|       .parse(doc.template to<JsonVariant>()); | ||||
| } | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -12,6 +12,7 @@ add_executable(JsonArrayTests | ||||
| 	remove.cpp | ||||
| 	set.cpp | ||||
| 	size.cpp | ||||
| 	std_string.cpp | ||||
| 	subscript.cpp | ||||
| ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										39
									
								
								test/JsonArray/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								test/JsonArray/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| static void eraseString(std::string &str) { | ||||
|   char *p = const_cast<char *>(str.c_str()); | ||||
|   while (*p) *p++ = '*'; | ||||
| } | ||||
|  | ||||
| TEST_CASE("std::string") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonArray &array = doc.to<JsonArray>(); | ||||
|  | ||||
|   SECTION("add()") { | ||||
|     std::string value("hello"); | ||||
|     array.add(value); | ||||
|     eraseString(value); | ||||
|     REQUIRE(std::string("hello") == array[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("set()") { | ||||
|     std::string value("world"); | ||||
|     array.add("hello"); | ||||
|     array.set(0, value); | ||||
|     eraseString(value); | ||||
|     REQUIRE(std::string("world") == array[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("operator[]") { | ||||
|     std::string value("world"); | ||||
|     array.add("hello"); | ||||
|     array[0] = value; | ||||
|     eraseString(value); | ||||
|     REQUIRE(std::string("world") == array[0]); | ||||
|   } | ||||
| } | ||||
| @@ -10,6 +10,8 @@ add_executable(JsonDeserializerTests | ||||
| 	deserializeJsonValue.cpp | ||||
| 	JsonError.cpp | ||||
| 	nestingLimit.cpp | ||||
| 	std_istream.cpp | ||||
| 	std_string.cpp | ||||
| ) | ||||
|  | ||||
| target_link_libraries(JsonDeserializerTests catch) | ||||
|   | ||||
| @@ -25,6 +25,7 @@ TEST_CASE("JsonError") { | ||||
|     TEST_STRINGIFICATION(TooDeep); | ||||
|     TEST_STRINGIFICATION(NoMemory); | ||||
|     TEST_STRINGIFICATION(InvalidInput); | ||||
|     TEST_STRINGIFICATION(IncompleteInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("as boolean") { | ||||
| @@ -32,6 +33,7 @@ TEST_CASE("JsonError") { | ||||
|     TEST_BOOLIFICATION(TooDeep, true); | ||||
|     TEST_BOOLIFICATION(NoMemory, true); | ||||
|     TEST_BOOLIFICATION(InvalidInput, true); | ||||
|     TEST_BOOLIFICATION(IncompleteInput, true); | ||||
|   } | ||||
|  | ||||
|   SECTION("ostream") { | ||||
|   | ||||
| @@ -164,13 +164,13 @@ TEST_CASE("deserialize JSON array") { | ||||
|     SECTION("Closing single quotes missing") { | ||||
|       JsonError err = deserializeJson(doc, "[\"]"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("Closing double quotes missing") { | ||||
|       JsonError err = deserializeJson(doc, "[\']"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -233,21 +233,21 @@ TEST_CASE("deserialize JSON array") { | ||||
|  | ||||
|     SECTION("/*/") { | ||||
|       JsonError err = deserializeJson(doc, "[/*/\n]"); | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("Unfinished comment") { | ||||
|       JsonError err = deserializeJson(doc, "[/*COMMENT]"); | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("Final slash missing") { | ||||
|       JsonError err = deserializeJson(doc, "[/*COMMENT*]"); | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Line comments") { | ||||
|   SECTION("Trailing comments") { | ||||
|     SECTION("Before opening bracket") { | ||||
|       JsonError err = deserializeJson(doc, "//COMMENT\n\t[\"hello\"]"); | ||||
|       JsonArray& arr = doc.as<JsonArray>(); | ||||
| @@ -311,39 +311,53 @@ TEST_CASE("deserialize JSON array") { | ||||
|  | ||||
|     SECTION("End document with comment") { | ||||
|       JsonError err = deserializeJson(doc, "[//COMMENT"); | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Premature null-terminator") { | ||||
|     SECTION("After opening bracket") { | ||||
|       JsonError err = deserializeJson(doc, "["); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After value") { | ||||
|       JsonError err = deserializeJson(doc, "[1"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After comma") { | ||||
|       JsonError err = deserializeJson(doc, "[1,"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Premature end of input") { | ||||
|     const char* input = "[1,2]"; | ||||
|  | ||||
|     SECTION("After opening bracket") { | ||||
|       JsonError err = deserializeJson(doc, input, 1); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After value") { | ||||
|       JsonError err = deserializeJson(doc, input, 2); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After comma") { | ||||
|       JsonError err = deserializeJson(doc, input, 3); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Misc") { | ||||
|     SECTION("Garbage") { | ||||
|       JsonError err = deserializeJson(doc, "%*$£¤"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("The opening bracket is missing") { | ||||
|       JsonError err = deserializeJson(doc, "]"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("The closing bracket is missing") { | ||||
|       JsonError err = deserializeJson(doc, "["); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("Escape sequences") { | ||||
|       JsonError err = | ||||
|           deserializeJson(doc, "[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]"); | ||||
|       JsonArray& arr = doc.as<JsonArray>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(1 == arr.size()); | ||||
|       REQUIRE(arr[0] == "1\"2\\3/4\b5\f6\n7\r8\t9"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Nested objects") { | ||||
|       char jsonString[] = | ||||
|           " [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] "; | ||||
|   | ||||
| @@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") { | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|     REQUIRE(err == JsonError::NoMemory); | ||||
|   } | ||||
|  | ||||
|   SECTION("BufferOfTheRightSizeForArrayWithOneValue") { | ||||
| @@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") { | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|     REQUIRE(err == JsonError::NoMemory); | ||||
|   } | ||||
|  | ||||
|   SECTION("BufferOfTheRightSizeForArrayWithNestedObject") { | ||||
| @@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") { | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("CharPtrNull") { | ||||
|     StaticJsonDocument<100> doc; | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, static_cast<char*>(0)); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("ConstCharPtrNull") { | ||||
|     StaticJsonDocument<100> doc; | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, static_cast<const char*>(0)); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("CopyStringNotSpaces") { | ||||
|     StaticJsonDocument<100> doc; | ||||
|  | ||||
|   | ||||
| @@ -212,19 +212,39 @@ TEST_CASE("deserialize JSON object") { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Misc") { | ||||
|     SECTION("The opening brace is missing") { | ||||
|       JsonError err = deserializeJson(doc, "}"); | ||||
|   SECTION("Premature null terminator") { | ||||
|     SECTION("After opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "{"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("The closing brace is missing") { | ||||
|     SECTION("After key") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\""); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After value") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\""); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After comma") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\","); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Misc") { | ||||
|     SECTION("A quoted key without value") { | ||||
|       JsonError err = deserializeJson(doc, "{\"key\"}"); | ||||
|  | ||||
| @@ -250,6 +270,200 @@ TEST_CASE("deserialize JSON object") { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Block comments") { | ||||
|     SECTION("Before opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "/*COMMENT*/ {\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("After opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "{/*COMMENT*/\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\"/*COMMENT*/:\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("After colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":/*COMMENT*/\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before closing brace") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\"/*COMMENT*/}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("After closing brace") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}/*COMMENT*/"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before comma") { | ||||
|       JsonError err = deserializeJson( | ||||
|           doc, "{\"hello\":\"world\"/*COMMENT*/,\"answer\":42}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|       REQUIRE(obj["answer"] == 42); | ||||
|     } | ||||
|  | ||||
|     SECTION("After comma") { | ||||
|       JsonError err = deserializeJson( | ||||
|           doc, "{\"hello\":\"world\",/*COMMENT*/\"answer\":42}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|       REQUIRE(obj["answer"] == 42); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Trailing comments") { | ||||
|     SECTION("Before opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "//COMMENT\n {\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("After opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "{//COMMENT\n\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\"//COMMENT\n:\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("After colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\"://COMMENT\n\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before closing brace") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\"//COMMENT\n}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("After closing brace") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}//COMMENT\n"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before comma") { | ||||
|       JsonError err = deserializeJson( | ||||
|           doc, "{\"hello\":\"world\"//COMMENT\n,\"answer\":42}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|       REQUIRE(obj["answer"] == 42); | ||||
|     } | ||||
|  | ||||
|     SECTION("After comma") { | ||||
|       JsonError err = deserializeJson( | ||||
|           doc, "{\"hello\":\"world\",//COMMENT\n\"answer\":42}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|       REQUIRE(obj["answer"] == 42); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Dangling slash") { | ||||
|     SECTION("Before opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "/{\"hello\":\"world\"}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After opening brace") { | ||||
|       JsonError err = deserializeJson(doc, "{/\"hello\":\"world\"}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\"/:\"world\"}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After colon") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":/\"world\"}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before closing brace") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\"/}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After closing brace") { | ||||
|       JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}/"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(obj["hello"] == "world"); | ||||
|     } | ||||
|  | ||||
|     SECTION("Before comma") { | ||||
|       JsonError err = | ||||
|           deserializeJson(doc, "{\"hello\":\"world\"/,\"answer\":42}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("After comma") { | ||||
|       JsonError err = | ||||
|           deserializeJson(doc, "{\"hello\":\"world\",/\"answer\":42}"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::InvalidInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Should clear the JsonObject") { | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     deserializeJson(doc, "{}"); | ||||
|   | ||||
| @@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") { | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|     REQUIRE(err == JsonError::NoMemory); | ||||
|   } | ||||
|  | ||||
|   SECTION("BufferOfTheRightSizeForObjectWithOneValue") { | ||||
| @@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") { | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|     REQUIRE(err == JsonError::NoMemory); | ||||
|   } | ||||
|  | ||||
|   SECTION("BufferOfTheRightSizeForObjectWithNestedObject") { | ||||
| @@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") { | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("CharPtrNull") { | ||||
|     StaticJsonDocument<100> doc; | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, static_cast<char*>(0)); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("ConstCharPtrNull") { | ||||
|     StaticJsonDocument<100> doc; | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, static_cast<const char*>(0)); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should clear the JsonObject") { | ||||
|     StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; | ||||
|     char input[] = "{\"hello\":\"world\"}"; | ||||
|   | ||||
| @@ -10,18 +10,16 @@ using namespace Catch::Matchers; | ||||
| TEST_CASE("deserializeJson(DynamicJsonDocument&)") { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   SECTION("EmptyObject") { | ||||
|     JsonError err = deserializeJson(doc, "{}"); | ||||
|   SECTION("null char*") { | ||||
|     JsonError err = deserializeJson(doc, static_cast<char*>(0)); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(doc.is<JsonObject>()); | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("EmptyArray") { | ||||
|     JsonError err = deserializeJson(doc, "[]"); | ||||
|   SECTION("null const char*") { | ||||
|     JsonError err = deserializeJson(doc, static_cast<const char*>(0)); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(doc.is<JsonArray>()); | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("Integer") { | ||||
| @@ -58,6 +56,14 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { | ||||
|     REQUIRE_THAT(doc.as<char*>(), Equals("hello world")); | ||||
|   } | ||||
|  | ||||
|   SECTION("Escape sequences") { | ||||
|     JsonError err = | ||||
|         deserializeJson(doc, "\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\""); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(doc.as<std::string>() == "1\"2\\3/4\b5\f6\n7\r8\t9"); | ||||
|   } | ||||
|  | ||||
|   SECTION("True") { | ||||
|     JsonError err = deserializeJson(doc, "true"); | ||||
|  | ||||
| @@ -74,25 +80,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { | ||||
|     REQUIRE(doc.as<bool>() == false); | ||||
|   } | ||||
|  | ||||
|   SECTION("OpenBrace") { | ||||
|     JsonError err = deserializeJson(doc, "{"); | ||||
|  | ||||
|     REQUIRE(err != JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("Incomplete string") { | ||||
|     JsonError err = deserializeJson(doc, "\"hello"); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(doc.is<char*>()); | ||||
|     REQUIRE_THAT(doc.as<char*>(), Equals("hello")); | ||||
|   } | ||||
|  | ||||
|   SECTION("Unterminated escape sequence") { | ||||
|     JsonError err = deserializeJson(doc, "\"\\\0\""); | ||||
|     REQUIRE(err == JsonError::InvalidInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should clear the JsonVariant") { | ||||
|     deserializeJson(doc, "[1,2,3]"); | ||||
|     deserializeJson(doc, "{}"); | ||||
| @@ -100,4 +87,86 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { | ||||
|     REQUIRE(doc.is<JsonObject>()); | ||||
|     REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); | ||||
|   } | ||||
|  | ||||
|   SECTION("Empty input") { | ||||
|     JsonError err = deserializeJson(doc, ""); | ||||
|  | ||||
|     REQUIRE(err == JsonError::IncompleteInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("Just a trailing comment") { | ||||
|     JsonError err = deserializeJson(doc, "// comment"); | ||||
|  | ||||
|     REQUIRE(err == JsonError::IncompleteInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("Just a block comment") { | ||||
|     JsonError err = deserializeJson(doc, "/*comment*/"); | ||||
|  | ||||
|     REQUIRE(err == JsonError::IncompleteInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("Just a slash") { | ||||
|     JsonError err = deserializeJson(doc, "/"); | ||||
|  | ||||
|     REQUIRE(err == JsonError::InvalidInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("Garbage") { | ||||
|     JsonError err = deserializeJson(doc, "%*$£¤"); | ||||
|  | ||||
|     REQUIRE(err == JsonError::InvalidInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("Premature null-terminator") { | ||||
|     SECTION("In escape sequence") { | ||||
|       JsonError err = deserializeJson(doc, "\"\\"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("In block comment") { | ||||
|       JsonError err = deserializeJson(doc, "/* comment"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("In double quoted string") { | ||||
|       JsonError err = deserializeJson(doc, "\"hello"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("In single quoted string") { | ||||
|       JsonError err = deserializeJson(doc, "'hello"); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Premature end of input") { | ||||
|     SECTION("In escape sequence") { | ||||
|       JsonError err = deserializeJson(doc, "\"\\n\"", 2); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("In block comment") { | ||||
|       JsonError err = deserializeJson(doc, "/* comment */", 10); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("In double quoted string") { | ||||
|       JsonError err = deserializeJson(doc, "\"hello\"", 6); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|  | ||||
|     SECTION("In single quoted string") { | ||||
|       JsonError err = deserializeJson(doc, "'hello'", 6); | ||||
|  | ||||
|       REQUIRE(err == JsonError::IncompleteInput); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										73
									
								
								test/JsonDeserializer/std_istream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								test/JsonDeserializer/std_istream.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
| #include <sstream> | ||||
|  | ||||
| TEST_CASE("deserializeJson(std::istream&)") { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   SECTION("array") { | ||||
|     std::istringstream json(" [ 42 /* comment */ ] "); | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|     JsonArray& arr = doc.as<JsonArray>(); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(1 == arr.size()); | ||||
|     REQUIRE(42 == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("object") { | ||||
|     std::istringstream json(" { hello : world // comment\n }"); | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(1 == obj.size()); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should not read after the closing brace of an empty object") { | ||||
|     std::istringstream json("{}123"); | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE('1' == char(json.get())); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should not read after the closing brace") { | ||||
|     std::istringstream json("{\"hello\":\"world\"}123"); | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE('1' == char(json.get())); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should not read after the closing bracket of an empty array") { | ||||
|     std::istringstream json("[]123"); | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE('1' == char(json.get())); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should not read after the closing bracket") { | ||||
|     std::istringstream json("[\"hello\",\"world\"]123"); | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE('1' == char(json.get())); | ||||
|   } | ||||
|  | ||||
|   SECTION("Should not read after the closing quote") { | ||||
|     std::istringstream json("\"hello\"123"); | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE('1' == char(json.get())); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										35
									
								
								test/JsonDeserializer/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								test/JsonDeserializer/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("deserializeJson(const std::string&)") { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   SECTION("should accept const string") { | ||||
|     const std::string input("[42]"); | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("should accept temporary string") { | ||||
|     JsonError err = deserializeJson(doc, std::string("[42]")); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("should duplicate content") { | ||||
|     std::string input("[\"hello\"]"); | ||||
|  | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|     input[2] = 'X';  // alter the string tomake sure we made a copy | ||||
|  | ||||
|     JsonArray &array = doc.as<JsonArray>(); | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(std::string("hello") == array[0]); | ||||
|   } | ||||
| } | ||||
| @@ -11,6 +11,7 @@ add_executable(JsonObjectTests | ||||
| 	remove.cpp | ||||
| 	set.cpp | ||||
| 	size.cpp | ||||
| 	std_string.cpp | ||||
| 	subscript.cpp | ||||
| ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										173
									
								
								test/JsonObject/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								test/JsonObject/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| static void eraseString(std::string &str) { | ||||
|   char *p = const_cast<char *>(str.c_str()); | ||||
|   while (*p) *p++ = '*'; | ||||
| } | ||||
|  | ||||
| TEST_CASE("std::string") { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   SECTION("operator[]") { | ||||
|     char json[] = "{\"key\":\"value\"}"; | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|     JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(std::string("value") == obj[std::string("key")]); | ||||
|   } | ||||
|  | ||||
|   SECTION("operator[] const") { | ||||
|     char json[] = "{\"key\":\"value\"}"; | ||||
|  | ||||
|     deserializeJson(doc, json); | ||||
|     JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(std::string("value") == obj[std::string("key")]); | ||||
|   } | ||||
|  | ||||
|   SECTION("set(key)") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     std::string key("hello"); | ||||
|     obj.set(key, "world"); | ||||
|     eraseString(key); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("set(value)") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     std::string value("world"); | ||||
|     obj.set("hello", value); | ||||
|     eraseString(value); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("set(key,value)") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     std::string key("hello"); | ||||
|     std::string value("world"); | ||||
|     obj.set(key, value); | ||||
|     eraseString(key); | ||||
|     eraseString(value); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("set(JsonArraySubscript)") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     DynamicJsonDocument doc2; | ||||
|     JsonArray &arr = doc2.to<JsonArray>(); | ||||
|     arr.add("world"); | ||||
|  | ||||
|     obj.set(std::string("hello"), arr[0]); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("set(JsonObjectSubscript)") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     DynamicJsonDocument doc2; | ||||
|     JsonObject &obj2 = doc2.to<JsonObject>(); | ||||
|     obj2.set("x", "world"); | ||||
|  | ||||
|     obj.set(std::string("hello"), obj2["x"]); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("get<T>()") { | ||||
|     char json[] = "{\"key\":\"value\"}"; | ||||
|     deserializeJson(doc, json); | ||||
|     JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(std::string("value") == obj.get<const char *>(std::string("key"))); | ||||
|   } | ||||
|  | ||||
|   SECTION("is<T>()") { | ||||
|     char json[] = "{\"key\":\"value\"}"; | ||||
|     deserializeJson(doc, json); | ||||
|     JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(true == obj.is<const char *>(std::string("key"))); | ||||
|   } | ||||
|  | ||||
|   SECTION("createNestedObject()") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     std::string key = "key"; | ||||
|     char json[64]; | ||||
|     obj.createNestedObject(key); | ||||
|     eraseString(key); | ||||
|     serializeJson(doc, json, sizeof(json)); | ||||
|     REQUIRE(std::string("{\"key\":{}}") == json); | ||||
|   } | ||||
|  | ||||
|   SECTION("createNestedArray()") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     std::string key = "key"; | ||||
|     char json[64]; | ||||
|     obj.createNestedArray(key); | ||||
|     eraseString(key); | ||||
|     serializeJson(doc, json, sizeof(json)); | ||||
|     REQUIRE(std::string("{\"key\":[]}") == json); | ||||
|   } | ||||
|  | ||||
|   SECTION("containsKey()") { | ||||
|     char json[] = "{\"key\":\"value\"}"; | ||||
|     deserializeJson(doc, json); | ||||
|     JsonObject &obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(true == obj.containsKey(std::string("key"))); | ||||
|   } | ||||
|  | ||||
|   SECTION("remove()") { | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     obj["key"] = "value"; | ||||
|  | ||||
|     obj.remove(std::string("key")); | ||||
|  | ||||
|     REQUIRE(0 == obj.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("operator[], set key") { | ||||
|     std::string key("hello"); | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     obj[key] = "world"; | ||||
|     eraseString(key); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("operator[], set value") { | ||||
|     std::string value("world"); | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|     obj["hello"] = value; | ||||
|     eraseString(value); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("memoryUsage() increases when adding a new key") { | ||||
|     std::string key1("hello"), key2("world"); | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|  | ||||
|     obj[key1] = 1; | ||||
|     size_t sizeBefore = doc.memoryUsage(); | ||||
|     obj[key2] = 2; | ||||
|     size_t sizeAfter = doc.memoryUsage(); | ||||
|  | ||||
|     REQUIRE(sizeAfter - sizeBefore >= key2.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("memoryUsage() remains when adding the same key") { | ||||
|     std::string key("hello"); | ||||
|     JsonObject &obj = doc.to<JsonObject>(); | ||||
|  | ||||
|     obj[key] = 1; | ||||
|     size_t sizeBefore = doc.memoryUsage(); | ||||
|     obj[key] = 2; | ||||
|     size_t sizeAfter = doc.memoryUsage(); | ||||
|  | ||||
|     REQUIRE(sizeBefore == sizeAfter); | ||||
|   } | ||||
| } | ||||
| @@ -8,6 +8,8 @@ add_executable(JsonSerializerTests | ||||
| 	JsonObject.cpp | ||||
| 	JsonObjectPretty.cpp | ||||
| 	JsonVariant.cpp | ||||
| 	std_stream.cpp | ||||
| 	std_string.cpp | ||||
| ) | ||||
|  | ||||
| target_link_libraries(JsonSerializerTests catch) | ||||
|   | ||||
							
								
								
									
										64
									
								
								test/JsonSerializer/std_stream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								test/JsonSerializer/std_stream.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
| #include <sstream> | ||||
|  | ||||
| TEST_CASE("operator<<(std::ostream)") { | ||||
|   DynamicJsonDocument doc; | ||||
|   std::ostringstream os; | ||||
|  | ||||
|   SECTION("JsonVariant containing false") { | ||||
|     JsonVariant variant = false; | ||||
|  | ||||
|     os << variant; | ||||
|  | ||||
|     REQUIRE("false" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant containing string") { | ||||
|     JsonVariant variant = "coucou"; | ||||
|  | ||||
|     os << variant; | ||||
|  | ||||
|     REQUIRE("\"coucou\"" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject") { | ||||
|     JsonObject& object = doc.to<JsonObject>(); | ||||
|     object["key"] = "value"; | ||||
|  | ||||
|     os << object; | ||||
|  | ||||
|     REQUIRE("{\"key\":\"value\"}" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObjectSubscript") { | ||||
|     JsonObject& object = doc.to<JsonObject>(); | ||||
|     object["key"] = "value"; | ||||
|  | ||||
|     os << object["key"]; | ||||
|  | ||||
|     REQUIRE("\"value\"" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray") { | ||||
|     JsonArray& array = doc.to<JsonArray>(); | ||||
|     array.add("value"); | ||||
|  | ||||
|     os << array; | ||||
|  | ||||
|     REQUIRE("[\"value\"]" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArraySubscript") { | ||||
|     JsonArray& array = doc.to<JsonArray>(); | ||||
|     array.add("value"); | ||||
|  | ||||
|     os << array[0]; | ||||
|  | ||||
|     REQUIRE("\"value\"" == os.str()); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										47
									
								
								test/JsonSerializer/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								test/JsonSerializer/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("serialize JsonArray to std::string") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonArray &array = doc.to<JsonArray>(); | ||||
|   array.add(4); | ||||
|   array.add(2); | ||||
|  | ||||
|   SECTION("serializeJson()") { | ||||
|     std::string json; | ||||
|     serializeJson(array, json); | ||||
|  | ||||
|     REQUIRE(std::string("[4,2]") == json); | ||||
|   } | ||||
|  | ||||
|   SECTION("serializeJsonPretty") { | ||||
|     std::string json; | ||||
|     serializeJsonPretty(array, json); | ||||
|  | ||||
|     REQUIRE(std::string("[\r\n  4,\r\n  2\r\n]") == json); | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("serialize JsonObject to std::string") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonObject &obj = doc.to<JsonObject>(); | ||||
|   obj["key"] = "value"; | ||||
|  | ||||
|   SECTION("object") { | ||||
|     std::string json; | ||||
|     serializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE(std::string("{\"key\":\"value\"}") == json); | ||||
|   } | ||||
|  | ||||
|   SECTION("serializeJsonPretty") { | ||||
|     std::string json; | ||||
|     serializeJsonPretty(doc, json); | ||||
|  | ||||
|     REQUIRE(std::string("{\r\n  \"key\": \"value\"\r\n}") == json); | ||||
|   } | ||||
| } | ||||
| @@ -2,10 +2,8 @@ | ||||
| # Copyright Benoit Blanchon 2014-2018 | ||||
| # MIT License | ||||
|  | ||||
| add_executable(MiscTests  | ||||
| add_executable(MiscTests | ||||
| 	FloatParts.cpp | ||||
| 	std_stream.cpp | ||||
| 	std_string.cpp | ||||
| 	StringBuilder.cpp | ||||
| 	StringTraits.cpp | ||||
| 	TypeTraits.cpp | ||||
|   | ||||
| @@ -1,88 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
| #include <sstream> | ||||
|  | ||||
| TEST_CASE("std::stream") { | ||||
|   SECTION("JsonVariantFalse") { | ||||
|     std::ostringstream os; | ||||
|     JsonVariant variant = false; | ||||
|     os << variant; | ||||
|     REQUIRE("false" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariantString") { | ||||
|     std::ostringstream os; | ||||
|     JsonVariant variant = "coucou"; | ||||
|     os << variant; | ||||
|     REQUIRE("\"coucou\"" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject") { | ||||
|     std::ostringstream os; | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& object = doc.to<JsonObject>(); | ||||
|     object["key"] = "value"; | ||||
|     os << object; | ||||
|     REQUIRE("{\"key\":\"value\"}" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObjectSubscript") { | ||||
|     std::ostringstream os; | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& object = doc.to<JsonObject>(); | ||||
|     object["key"] = "value"; | ||||
|     os << object["key"]; | ||||
|     REQUIRE("\"value\"" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray") { | ||||
|     std::ostringstream os; | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& array = doc.to<JsonArray>(); | ||||
|     array.add("value"); | ||||
|     os << array; | ||||
|     REQUIRE("[\"value\"]" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArraySubscript") { | ||||
|     std::ostringstream os; | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& array = doc.to<JsonArray>(); | ||||
|     array.add("value"); | ||||
|     os << array[0]; | ||||
|     REQUIRE("\"value\"" == os.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseArray") { | ||||
|     std::istringstream json(" [ 42 /* comment */ ] "); | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|     JsonArray& arr = doc.as<JsonArray>(); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(1 == arr.size()); | ||||
|     REQUIRE(42 == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseObject") { | ||||
|     std::istringstream json(" { hello : world // comment\n }"); | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(1 == obj.size()); | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("ShouldNotReadPastTheEnd") { | ||||
|     std::istringstream json("{}123"); | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, json); | ||||
|     REQUIRE('1' == json.get()); | ||||
|   } | ||||
| } | ||||
| @@ -1,259 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| static void eraseString(std::string &str) { | ||||
|   char *p = const_cast<char *>(str.c_str()); | ||||
|   while (*p) *p++ = '*'; | ||||
| } | ||||
|  | ||||
| TEST_CASE("std::string") { | ||||
|   SECTION("deserializeJson duplicates content") { | ||||
|     std::string json("[\"hello\"]"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|     eraseString(json); | ||||
|  | ||||
|     JsonArray &array = doc.as<JsonArray>(); | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|     REQUIRE(std::string("hello") == array[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray") { | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray &array = doc.to<JsonArray>(); | ||||
|  | ||||
|     SECTION("add()") { | ||||
|       std::string value("hello"); | ||||
|       array.add(value); | ||||
|       eraseString(value); | ||||
|       REQUIRE(std::string("hello") == array[0]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set()") { | ||||
|       std::string value("world"); | ||||
|       array.add("hello"); | ||||
|       array.set(0, value); | ||||
|       eraseString(value); | ||||
|       REQUIRE(std::string("world") == array[0]); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator[]") { | ||||
|       std::string value("world"); | ||||
|       array.add("hello"); | ||||
|       array[0] = value; | ||||
|       eraseString(value); | ||||
|       REQUIRE(std::string("world") == array[0]); | ||||
|     } | ||||
|  | ||||
|     SECTION("serializeJson()") { | ||||
|       array.add(4); | ||||
|       array.add(2); | ||||
|       std::string json; | ||||
|       serializeJson(array, json); | ||||
|       REQUIRE(std::string("[4,2]") == json); | ||||
|     } | ||||
|  | ||||
|     SECTION("serializeJsonPretty()") { | ||||
|       array.add(4); | ||||
|       array.add(2); | ||||
|       std::string json; | ||||
|       serializeJsonPretty(array, json); | ||||
|       REQUIRE(std::string("[\r\n  4,\r\n  2\r\n]") == json); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject") { | ||||
|     DynamicJsonDocument doc; | ||||
|  | ||||
|     SECTION("deserializeJson()") { | ||||
|       std::string json("{\"hello\":\"world\"}"); | ||||
|  | ||||
|       JsonError err = deserializeJson(doc, json); | ||||
|       JsonObject &obj = doc.as<JsonObject>(); | ||||
|       eraseString(json); | ||||
|  | ||||
|       REQUIRE(err == JsonError::Ok); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator[]") { | ||||
|       char json[] = "{\"key\":\"value\"}"; | ||||
|  | ||||
|       deserializeJson(doc, json); | ||||
|       JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(std::string("value") == obj[std::string("key")]); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator[] const") { | ||||
|       char json[] = "{\"key\":\"value\"}"; | ||||
|  | ||||
|       deserializeJson(doc, json); | ||||
|       JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(std::string("value") == obj[std::string("key")]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set(key)") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       std::string key("hello"); | ||||
|       obj.set(key, "world"); | ||||
|       eraseString(key); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set(value)") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       std::string value("world"); | ||||
|       obj.set("hello", value); | ||||
|       eraseString(value); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set(key,value)") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       std::string key("hello"); | ||||
|       std::string value("world"); | ||||
|       obj.set(key, value); | ||||
|       eraseString(key); | ||||
|       eraseString(value); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set(JsonArraySubscript)") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       DynamicJsonDocument doc2; | ||||
|       JsonArray &arr = doc2.to<JsonArray>(); | ||||
|       arr.add("world"); | ||||
|  | ||||
|       obj.set(std::string("hello"), arr[0]); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set(JsonObjectSubscript)") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       DynamicJsonDocument doc2; | ||||
|       JsonObject &obj2 = doc2.to<JsonObject>(); | ||||
|       obj2.set("x", "world"); | ||||
|  | ||||
|       obj.set(std::string("hello"), obj2["x"]); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("get<T>()") { | ||||
|       char json[] = "{\"key\":\"value\"}"; | ||||
|       deserializeJson(doc, json); | ||||
|       JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(std::string("value") == | ||||
|               obj.get<const char *>(std::string("key"))); | ||||
|     } | ||||
|  | ||||
|     SECTION("is<T>()") { | ||||
|       char json[] = "{\"key\":\"value\"}"; | ||||
|       deserializeJson(doc, json); | ||||
|       JsonObject &obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(true == obj.is<const char *>(std::string("key"))); | ||||
|     } | ||||
|  | ||||
|     SECTION("createNestedObject()") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       std::string key = "key"; | ||||
|       char json[64]; | ||||
|       obj.createNestedObject(key); | ||||
|       eraseString(key); | ||||
|       serializeJson(doc, json, sizeof(json)); | ||||
|       REQUIRE(std::string("{\"key\":{}}") == json); | ||||
|     } | ||||
|  | ||||
|     SECTION("createNestedArray()") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       std::string key = "key"; | ||||
|       char json[64]; | ||||
|       obj.createNestedArray(key); | ||||
|       eraseString(key); | ||||
|       serializeJson(doc, json, sizeof(json)); | ||||
|       REQUIRE(std::string("{\"key\":[]}") == json); | ||||
|     } | ||||
|  | ||||
|     SECTION("containsKey()") { | ||||
|       char json[] = "{\"key\":\"value\"}"; | ||||
|       deserializeJson(doc, json); | ||||
|       JsonObject &obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(true == obj.containsKey(std::string("key"))); | ||||
|     } | ||||
|  | ||||
|     SECTION("remove()") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       obj["key"] = "value"; | ||||
|  | ||||
|       obj.remove(std::string("key")); | ||||
|  | ||||
|       REQUIRE(0 == obj.size()); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator[], set key") { | ||||
|       std::string key("hello"); | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       obj[key] = "world"; | ||||
|       eraseString(key); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator[], set value") { | ||||
|       std::string value("world"); | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       obj["hello"] = value; | ||||
|       eraseString(value); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("serializeJson()") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       obj["key"] = "value"; | ||||
|       std::string json; | ||||
|       serializeJson(doc, json); | ||||
|       REQUIRE(std::string("{\"key\":\"value\"}") == json); | ||||
|     } | ||||
|  | ||||
|     SECTION("serializeJsonPretty()") { | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|       obj["key"] = "value"; | ||||
|       std::string json; | ||||
|       serializeJsonPretty(doc, json); | ||||
|       REQUIRE(std::string("{\r\n  \"key\": \"value\"\r\n}") == json); | ||||
|     } | ||||
|  | ||||
|     SECTION("memoryUsage() increases when adding a new key") { | ||||
|       std::string key1("hello"), key2("world"); | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|  | ||||
|       obj[key1] = 1; | ||||
|       size_t sizeBefore = doc.memoryUsage(); | ||||
|       obj[key2] = 2; | ||||
|       size_t sizeAfter = doc.memoryUsage(); | ||||
|  | ||||
|       REQUIRE(sizeAfter - sizeBefore >= key2.size()); | ||||
|     } | ||||
|  | ||||
|     SECTION("memoryUsage() remains when adding the same key") { | ||||
|       std::string key("hello"); | ||||
|       JsonObject &obj = doc.to<JsonObject>(); | ||||
|  | ||||
|       obj[key] = 1; | ||||
|       size_t sizeBefore = doc.memoryUsage(); | ||||
|       obj[key] = 2; | ||||
|       size_t sizeAfter = doc.memoryUsage(); | ||||
|  | ||||
|       REQUIRE(sizeBefore == sizeAfter); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -9,259 +9,267 @@ | ||||
| #define CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
| #endif | ||||
|  | ||||
| TEST_CASE("unsigned char string") { | ||||
|   SECTION("JsonBuffer::parseArray") { | ||||
|     unsigned char json[] = "[42]"; | ||||
|  | ||||
|     StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc; | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonBuffer::parseObject") { | ||||
|     unsigned char json[] = "{\"a\":42}"; | ||||
| TEST_CASE("unsigned char[]") { | ||||
|   SECTION("deserializeJson()") { | ||||
|     unsigned char input[] = "{\"a\":42}"; | ||||
|  | ||||
|     StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; | ||||
|     JsonError err = deserializeJson(doc, json); | ||||
|     JsonError err = deserializeJson(doc, input); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant constructor") { | ||||
|     unsigned char value[] = "42"; | ||||
|   SECTION("deserializeMsgPack()") { | ||||
|     unsigned char input[] = "\xDE\x00\x01\xA5Hello\xA5world"; | ||||
|  | ||||
|     JsonVariant variant(value); | ||||
|     StaticJsonDocument<JSON_OBJECT_SIZE(2)> doc; | ||||
|     MsgPackError err = deserializeMsgPack(doc, input); | ||||
|  | ||||
|     REQUIRE(42 == variant.as<int>()); | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant assignment operator") { | ||||
|     unsigned char value[] = "42"; | ||||
|   SECTION("JsonVariant") { | ||||
|     SECTION("constructor") { | ||||
|       unsigned char value[] = "42"; | ||||
|  | ||||
|     JsonVariant variant(666); | ||||
|     variant = value; | ||||
|       JsonVariant variant(value); | ||||
|  | ||||
|     REQUIRE(42 == variant.as<int>()); | ||||
|   } | ||||
|       REQUIRE(42 == variant.as<int>()); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator=") { | ||||
|       unsigned char value[] = "42"; | ||||
|  | ||||
|       JsonVariant variant(666); | ||||
|       variant = value; | ||||
|  | ||||
|       REQUIRE(42 == variant.as<int>()); | ||||
|     } | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonVariant::operator[]") { | ||||
|     unsigned char key[] = "hello"; | ||||
|     SECTION("operator[]") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     JsonVariant variant = doc.as<JsonVariant>(); | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       JsonVariant variant = doc.as<JsonVariant>(); | ||||
|  | ||||
|     REQUIRE(std::string("world") == variant[key]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == variant[key]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonVariant::operator[] const") { | ||||
|     unsigned char key[] = "hello"; | ||||
|     SECTION("operator[] const") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     const JsonVariant variant = doc.as<JsonVariant>(); | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       const JsonVariant variant = doc.as<JsonVariant>(); | ||||
|  | ||||
|     REQUIRE(std::string("world") == variant[key]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == variant[key]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|   SECTION("JsonVariant::operator==") { | ||||
|     unsigned char comparand[] = "hello"; | ||||
|     SECTION("operator==") { | ||||
|       unsigned char comparand[] = "hello"; | ||||
|  | ||||
|     JsonVariant variant; | ||||
|     variant = "hello"; | ||||
|       JsonVariant variant; | ||||
|       variant = "hello"; | ||||
|  | ||||
|     REQUIRE(comparand == variant); | ||||
|     REQUIRE(variant == comparand); | ||||
|     REQUIRE_FALSE(comparand != variant); | ||||
|     REQUIRE_FALSE(variant != comparand); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant::operator!=") { | ||||
|     unsigned char comparand[] = "hello"; | ||||
|  | ||||
|     JsonVariant variant; | ||||
|     variant = "world"; | ||||
|  | ||||
|     REQUIRE(comparand != variant); | ||||
|     REQUIRE(variant != comparand); | ||||
|     REQUIRE_FALSE(comparand == variant); | ||||
|     REQUIRE_FALSE(variant == comparand); | ||||
|       REQUIRE(comparand == variant); | ||||
|       REQUIRE(variant == comparand); | ||||
|       REQUIRE_FALSE(comparand != variant); | ||||
|       REQUIRE_FALSE(variant != comparand); | ||||
|     } | ||||
|  | ||||
|     SECTION("operator!=") { | ||||
|       unsigned char comparand[] = "hello"; | ||||
|  | ||||
|       JsonVariant variant; | ||||
|       variant = "world"; | ||||
|  | ||||
|       REQUIRE(comparand != variant); | ||||
|       REQUIRE(variant != comparand); | ||||
|       REQUIRE_FALSE(comparand == variant); | ||||
|       REQUIRE_FALSE(variant == comparand); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject") { | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonObject::operator[]") { | ||||
|     unsigned char key[] = "hello"; | ||||
|     SECTION("operator[]") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj[key] = "world"; | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj[key] = "world"; | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("JsonObject::operator[] const") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|  | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(std::string("world") == obj[key]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|   SECTION("JsonObjectSubscript::operator=") {  // issue #416 | ||||
|     unsigned char value[] = "world"; | ||||
|     SECTION("get()") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj["hello"] = value; | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(std::string("world") == obj.get<char*>(key)); | ||||
|     } | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|     SECTION("set() key") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.set(key, "world"); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set() value") { | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.set("hello", value); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set() key&value") { | ||||
|       unsigned char key[] = "world"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.set(key, key); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["world"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("containsKey()") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(true == obj.containsKey(key)); | ||||
|     } | ||||
|  | ||||
|     SECTION("remove()") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       obj.remove(key); | ||||
|  | ||||
|       REQUIRE(0 == obj.size()); | ||||
|     } | ||||
|  | ||||
|     SECTION("is()") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":42}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(true == obj.is<int>(key)); | ||||
|     } | ||||
|  | ||||
|     SECTION("createNestedArray()") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.createNestedArray(key); | ||||
|     } | ||||
|  | ||||
|     SECTION("createNestedObject()") { | ||||
|       unsigned char key[] = "hello"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.createNestedObject(key); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObjectSubscript::set()") { | ||||
|     unsigned char value[] = "world"; | ||||
|   SECTION("JsonObjectSubscript") { | ||||
|     SECTION("operator=") {  // issue #416 | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj["hello"].set(value); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj["hello"] = value; | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set()") { | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj["hello"].set(value); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonObject::operator[] const") { | ||||
|     unsigned char key[] = "hello"; | ||||
|   SECTION("JsonArray") { | ||||
|     SECTION("add()") { | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add(value); | ||||
|  | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(std::string("world") == obj[key]); | ||||
|   } | ||||
| #endif | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|  | ||||
|   SECTION("JsonObject::get()") { | ||||
|     unsigned char key[] = "hello"; | ||||
|     SECTION("set()") { | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(std::string("world") == obj.get<char*>(key)); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add("hello"); | ||||
|       arr.set(0, value); | ||||
|  | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::set() key") { | ||||
|     unsigned char key[] = "hello"; | ||||
|   SECTION("JsonArraySubscript") { | ||||
|     SECTION("set()") { | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.set(key, "world"); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add("hello"); | ||||
|       arr[0].set(value); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|  | ||||
|   SECTION("JsonObject::set() value") { | ||||
|     unsigned char value[] = "world"; | ||||
|     SECTION("operator=") { | ||||
|       unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.set("hello", value); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add("hello"); | ||||
|       arr[0] = value; | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::set key&value") { | ||||
|     unsigned char key[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.set(key, key); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["world"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::containsKey()") { | ||||
|     unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(true == obj.containsKey(key)); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::remove()") { | ||||
|     unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     obj.remove(key); | ||||
|  | ||||
|     REQUIRE(0 == obj.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::is()") { | ||||
|     unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":42}"); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(true == obj.is<int>(key)); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::createNestedArray()") { | ||||
|     unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.createNestedArray(key); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject::createNestedObject()") { | ||||
|     unsigned char key[] = "hello"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.createNestedObject(key); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray::add()") { | ||||
|     unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add(value); | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray::set()") { | ||||
|     unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add("hello"); | ||||
|     arr.set(0, value); | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArraySubscript::set()") { | ||||
|     unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add("hello"); | ||||
|     arr[0].set(value); | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArraySubscript::operator=") { | ||||
|     unsigned char value[] = "world"; | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add("hello"); | ||||
|     arr[0] = value; | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -17,322 +17,321 @@ | ||||
| #ifndef VLA_NOT_SUPPORTED | ||||
|  | ||||
| TEST_CASE("Variable Length Array") { | ||||
|   SECTION("ParseArray") { | ||||
|     int i = 8; | ||||
|   SECTION("deserializeJson()") { | ||||
|     int i = 9; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "[42]"); | ||||
|     strcpy(vla, "{\"a\":42}"); | ||||
|  | ||||
|     StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc; | ||||
|     StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; | ||||
|     JsonError err = deserializeJson(doc, vla); | ||||
|  | ||||
|     REQUIRE(err == JsonError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseObject") { | ||||
|   SECTION("deserializeMsgPack()") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "{\"a\":42}"); | ||||
|     memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15); | ||||
|  | ||||
|     StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; | ||||
|     JsonError error = deserializeJson(doc, vla); | ||||
|     MsgPackError err = deserializeMsgPack(doc, vla); | ||||
|  | ||||
|     REQUIRE(error == JsonError::Ok); | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("Parse") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "42"); | ||||
|   SECTION("JsonVariant") { | ||||
|     SECTION("constructor") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "42"); | ||||
|  | ||||
|     StaticJsonDocument<> variant; | ||||
|     deserializeJson(variant, vla); | ||||
|       JsonVariant variant(vla); | ||||
|  | ||||
|     REQUIRE(42 == variant.as<int>()); | ||||
|   } | ||||
|       REQUIRE(42 == variant.as<int>()); | ||||
|     } | ||||
|  | ||||
|   SECTION("JsonVariant_Constructor") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "42"); | ||||
|     SECTION("operator=") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "42"); | ||||
|  | ||||
|     JsonVariant variant(vla); | ||||
|       JsonVariant variant(666); | ||||
|       variant = vla; | ||||
|  | ||||
|     REQUIRE(42 == variant.as<int>()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant_Assign") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "42"); | ||||
|  | ||||
|     JsonVariant variant(666); | ||||
|     variant = vla; | ||||
|  | ||||
|     REQUIRE(42 == variant.as<int>()); | ||||
|   } | ||||
|       REQUIRE(42 == variant.as<int>()); | ||||
|     } | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonVariant_Subscript") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|     SECTION("operator[]") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     JsonVariant variant = doc.as<JsonVariant>(); | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       JsonVariant variant = doc.as<JsonVariant>(); | ||||
|  | ||||
|     REQUIRE(std::string("world") == variant[vla]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == variant[vla]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonVariant_Subscript_Const") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|     SECTION("operator[] const") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     const JsonVariant variant = doc.as<JsonVariant>(); | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       const JsonVariant variant = doc.as<JsonVariant>(); | ||||
|  | ||||
|     REQUIRE(std::string("world") == variant[vla]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == variant[vla]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|   SECTION("JsonVariant_Equals") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|     SECTION("operator==") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|     JsonVariant variant; | ||||
|     variant = "hello"; | ||||
|       JsonVariant variant; | ||||
|       variant = "hello"; | ||||
|  | ||||
|     REQUIRE((vla == variant)); | ||||
|     REQUIRE((variant == vla)); | ||||
|     REQUIRE_FALSE((vla != variant)); | ||||
|     REQUIRE_FALSE((variant != vla)); | ||||
|       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 = "world"; | ||||
|  | ||||
|       REQUIRE((vla != variant)); | ||||
|       REQUIRE((variant != vla)); | ||||
|       REQUIRE_FALSE((vla == variant)); | ||||
|       REQUIRE_FALSE((variant == vla)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonVariant_Differs") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|   SECTION("JsonObject") { | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|     SECTION("operator[]") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|     JsonVariant variant; | ||||
|     variant = "world"; | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj[vla] = "world"; | ||||
|  | ||||
|     REQUIRE((vla != variant)); | ||||
|     REQUIRE((variant != vla)); | ||||
|     REQUIRE_FALSE((vla == variant)); | ||||
|     REQUIRE_FALSE((variant == vla)); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonObject_Subscript") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|     SECTION("operator[] const") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj[vla] = "world"; | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(std::string("world") == obj[vla]); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|   SECTION("JsonObject_Subscript_Assign") {  // issue #416 | ||||
|     int i = 32; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|     SECTION("get()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj["hello"] = vla; | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"].as<char*>()); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(std::string("world") == obj.get<char*>(vla)); | ||||
|     } | ||||
|  | ||||
|     SECTION("set() key") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.set(vla, "world"); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set() value") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.set("hello", vla); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("set() key&value") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.set(vla, vla); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["world"]); | ||||
|     } | ||||
|  | ||||
|     SECTION("containsKey()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|  | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       REQUIRE(true == obj.containsKey(vla)); | ||||
|     } | ||||
|  | ||||
|     SECTION("remove()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|       obj.remove(vla); | ||||
|  | ||||
|       REQUIRE(0 == obj.size()); | ||||
|     } | ||||
|  | ||||
|     SECTION("is<T>()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       deserializeJson(doc, "{\"hello\":42}"); | ||||
|       JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|       REQUIRE(true == obj.is<int>(vla)); | ||||
|     } | ||||
|  | ||||
|     SECTION("createNestedArray()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.createNestedArray(vla); | ||||
|     } | ||||
|  | ||||
|     SECTION("createNestedObject()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "hello"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj.createNestedObject(vla); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_Subscript_Set") { | ||||
|     int i = 32; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|   SECTION("JsonObjectSubscript") { | ||||
|     SECTION("operator=") {  // issue #416 | ||||
|       int i = 32; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj["hello"].set(vla); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj["hello"] = vla; | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"].as<char*>()); | ||||
|       REQUIRE(std::string("world") == obj["hello"].as<char*>()); | ||||
|     } | ||||
|  | ||||
|     SECTION("set()") { | ||||
|       int i = 32; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonObject& obj = doc.to<JsonObject>(); | ||||
|       obj["hello"].set(vla); | ||||
|  | ||||
|       REQUIRE(std::string("world") == obj["hello"].as<char*>()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR | ||||
|   SECTION("JsonObject_Subscript_Const") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|   SECTION("JsonArray") { | ||||
|     SECTION("add()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add(vla); | ||||
|  | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(std::string("world") == obj[vla]); | ||||
|   } | ||||
| #endif | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|  | ||||
|   SECTION("JsonObject_Get") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|     SECTION("set()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add("hello"); | ||||
|       arr.set(0, vla); | ||||
|  | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(std::string("world") == obj.get<char*>(vla)); | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_Set_Key") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|   SECTION("JsonArraySubscript") { | ||||
|     SECTION("set()") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.set(vla, "world"); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add("hello"); | ||||
|       arr[0].set(vla); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|  | ||||
|   SECTION("JsonObject_Set_Value") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|     SECTION("operator=") { | ||||
|       int i = 16; | ||||
|       char vla[i]; | ||||
|       strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.set("hello", vla); | ||||
|       DynamicJsonDocument doc; | ||||
|       JsonArray& arr = doc.to<JsonArray>(); | ||||
|       arr.add("hello"); | ||||
|       arr[0] = vla; | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["hello"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_Set_KeyAndValue") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.set(vla, vla); | ||||
|  | ||||
|     REQUIRE(std::string("world") == obj["world"]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_ContainsKey") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|  | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     REQUIRE(true == obj.containsKey(vla)); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_Remove") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|     obj.remove(vla); | ||||
|  | ||||
|     REQUIRE(0 == obj.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_Is") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     deserializeJson(doc, "{\"hello\":42}"); | ||||
|     JsonObject& obj = doc.as<JsonObject>(); | ||||
|  | ||||
|     REQUIRE(true == obj.is<int>(vla)); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_CreateNestedArray") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.createNestedArray(vla); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonObject_CreateNestedObject") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "hello"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonObject& obj = doc.to<JsonObject>(); | ||||
|     obj.createNestedObject(vla); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray_Add") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add(vla); | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArray_Set") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add("hello"); | ||||
|     arr.set(0, vla); | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArraySubscript_Set") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add("hello"); | ||||
|     arr[0].set(vla); | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("JsonArraySubscript_Assign") { | ||||
|     int i = 16; | ||||
|     char vla[i]; | ||||
|     strcpy(vla, "world"); | ||||
|  | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray& arr = doc.to<JsonArray>(); | ||||
|     arr.add("hello"); | ||||
|     arr[0] = vla; | ||||
|  | ||||
|     REQUIRE(std::string("world") == arr[0]); | ||||
|       REQUIRE(std::string("world") == arr[0]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -3,13 +3,17 @@ | ||||
| # MIT License | ||||
|  | ||||
| add_executable(MsgPackTests | ||||
| 	deserializationErrors.cpp | ||||
| 	MsgPackError.cpp | ||||
| 	deserializeArray.cpp | ||||
| 	deserializeObject.cpp | ||||
| 	deserializeVariant.cpp | ||||
| 	deserializeStaticVariant.cpp | ||||
| 	deserializeVariant.cpp | ||||
| 	doubleToFloat.cpp | ||||
| 	MsgPackError.cpp | ||||
| 	incompleteInput.cpp | ||||
| 	nestingLimit.cpp | ||||
| 	notSupported.cpp | ||||
| 	std_string.cpp | ||||
| 	std_istream.cpp | ||||
| ) | ||||
|  | ||||
| target_link_libraries(MsgPackTests catch) | ||||
|   | ||||
| @@ -25,6 +25,7 @@ TEST_CASE("MsgPackError") { | ||||
|     TEST_STRINGIFICATION(NotSupported); | ||||
|     TEST_STRINGIFICATION(NoMemory); | ||||
|     TEST_STRINGIFICATION(TooDeep); | ||||
|     TEST_STRINGIFICATION(IncompleteInput); | ||||
|   } | ||||
|  | ||||
|   SECTION("as boolean") { | ||||
| @@ -32,6 +33,7 @@ TEST_CASE("MsgPackError") { | ||||
|     TEST_BOOLIFICATION(NotSupported, true); | ||||
|     TEST_BOOLIFICATION(NoMemory, true); | ||||
|     TEST_BOOLIFICATION(TooDeep, true); | ||||
|     TEST_BOOLIFICATION(IncompleteInput, true); | ||||
|   } | ||||
|  | ||||
|   SECTION("ostream") { | ||||
|   | ||||
| @@ -1,59 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| static void check(const char* input, MsgPackError expected, | ||||
|                   uint8_t nestingLimit = 10) { | ||||
|   DynamicJsonDocument doc; | ||||
|   doc.nestingLimit = nestingLimit; | ||||
|  | ||||
|   MsgPackError error = deserializeMsgPack(doc, input); | ||||
|  | ||||
|   REQUIRE(error == expected); | ||||
| } | ||||
|  | ||||
| TEST_CASE("Errors returned by deserializeMsgPack()") { | ||||
|   SECTION("unsupported") { | ||||
|     check("\xc4", MsgPackError::NotSupported);  // bin 8 | ||||
|     check("\xc5", MsgPackError::NotSupported);  // bin 16 | ||||
|     check("\xc6", MsgPackError::NotSupported);  // bin 32 | ||||
|     check("\xc7", MsgPackError::NotSupported);  // ext 8 | ||||
|     check("\xc8", MsgPackError::NotSupported);  // ext 16 | ||||
|     check("\xc9", MsgPackError::NotSupported);  // ext 32 | ||||
|     check("\xd4", MsgPackError::NotSupported);  // fixext 1 | ||||
|     check("\xd5", MsgPackError::NotSupported);  // fixext 2 | ||||
|     check("\xd6", MsgPackError::NotSupported);  // fixext 4 | ||||
|     check("\xd7", MsgPackError::NotSupported);  // fixext 8 | ||||
|     check("\xd8", MsgPackError::NotSupported);  // fixext 16 | ||||
|   } | ||||
|  | ||||
|   SECTION("unsupported in array") { | ||||
|     check("\x91\xc4", MsgPackError::NotSupported); | ||||
|   } | ||||
|  | ||||
|   SECTION("unsupported in map") { | ||||
|     check("\x81\xc4\x00\xA1H", MsgPackError::NotSupported); | ||||
|     check("\x81\xA1H\xc4\x00", MsgPackError::NotSupported); | ||||
|   } | ||||
|  | ||||
|   SECTION("integer as key") { | ||||
|     check("\x81\x01\xA1H", MsgPackError::NotSupported); | ||||
|   } | ||||
|  | ||||
|   SECTION("object too deep") { | ||||
|     check("\x80", MsgPackError::TooDeep, 0);           // {} | ||||
|     check("\x80", MsgPackError::Ok, 1);                // {} | ||||
|     check("\x81\xA1H\x80", MsgPackError::TooDeep, 1);  // {H:{}} | ||||
|     check("\x81\xA1H\x80", MsgPackError::Ok, 2);       // {H:{}} | ||||
|   } | ||||
|  | ||||
|   SECTION("array too deep") { | ||||
|     check("\x90", MsgPackError::TooDeep, 0);      // [] | ||||
|     check("\x90", MsgPackError::Ok, 1);           // [] | ||||
|     check("\x91\x90", MsgPackError::TooDeep, 1);  // [[]] | ||||
|     check("\x91\x90", MsgPackError::Ok, 2);       // [[]] | ||||
|   } | ||||
| } | ||||
							
								
								
									
										106
									
								
								test/MsgPack/incompleteInput.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								test/MsgPack/incompleteInput.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| MsgPackError deserialize(const char* input, size_t len) { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   return deserializeMsgPack(doc, input, len); | ||||
| } | ||||
|  | ||||
| void checkAllSizes(const char* input, size_t len) { | ||||
|   REQUIRE(deserialize(input, len) == MsgPackError::Ok); | ||||
|  | ||||
|   while (--len) { | ||||
|     REQUIRE(deserialize(input, len) == MsgPackError::IncompleteInput); | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("deserializeMsgPack() returns IncompleteInput") { | ||||
|   SECTION("empty input") { | ||||
|     checkAllSizes("\x00", 1); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixarray") { | ||||
|     checkAllSizes("\x91\x01", 2); | ||||
|   } | ||||
|  | ||||
|   SECTION("array 16") { | ||||
|     checkAllSizes("\xDC\x00\x01\x01", 4); | ||||
|   } | ||||
|  | ||||
|   SECTION("array 32") { | ||||
|     checkAllSizes("\xDD\x00\x00\x00\x01\x01", 6); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixmap") { | ||||
|     checkAllSizes("\x81\xA3one\x01", 6); | ||||
|   } | ||||
|  | ||||
|   SECTION("map 16") { | ||||
|     checkAllSizes("\xDE\x00\x01\xA3one\x01", 8); | ||||
|   } | ||||
|  | ||||
|   SECTION("map 32") { | ||||
|     checkAllSizes("\xDF\x00\x00\x00\x01\xA3one\x01", 10); | ||||
|   } | ||||
|  | ||||
|   SECTION("uint 8") { | ||||
|     checkAllSizes("\xcc\x01", 2); | ||||
|   } | ||||
|  | ||||
|   SECTION("uint 16") { | ||||
|     checkAllSizes("\xcd\x00\x01", 3); | ||||
|   } | ||||
|  | ||||
|   SECTION("uint 32") { | ||||
|     checkAllSizes("\xCE\x00\x00\x00\x01", 5); | ||||
|   } | ||||
|  | ||||
|   SECTION("uint 64") { | ||||
|     checkAllSizes("\xCF\x00\x00\x00\x00\x00\x00\x00\x00", 9); | ||||
|   } | ||||
|  | ||||
|   SECTION("int 8") { | ||||
|     checkAllSizes("\xD0\x01", 2); | ||||
|   } | ||||
|  | ||||
|   SECTION("int 16") { | ||||
|     checkAllSizes("\xD1\x00\x01", 3); | ||||
|   } | ||||
|  | ||||
|   SECTION("int 32") { | ||||
|     checkAllSizes("\xD2\x00\x00\x00\x01", 5); | ||||
|   } | ||||
|  | ||||
|   SECTION("int 64") { | ||||
|     checkAllSizes("\xD3\x00\x00\x00\x00\x00\x00\x00\x00", 9); | ||||
|   } | ||||
|  | ||||
|   SECTION("float 32") { | ||||
|     checkAllSizes("\xCA\x40\x48\xF5\xC3", 5); | ||||
|   } | ||||
|  | ||||
|   SECTION("float 64") { | ||||
|     checkAllSizes("\xCB\x40\x09\x21\xCA\xC0\x83\x12\x6F", 9); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixstr") { | ||||
|     checkAllSizes("\xABhello world", 12); | ||||
|   } | ||||
|  | ||||
|   SECTION("str 8") { | ||||
|     checkAllSizes("\xd9\x05hello", 7); | ||||
|   } | ||||
|  | ||||
|   SECTION("str 16") { | ||||
|     checkAllSizes("\xda\x00\x05hello", 8); | ||||
|   } | ||||
|  | ||||
|   SECTION("str 32") { | ||||
|     checkAllSizes("\xdb\x00\x00\x00\x05hello", 10); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										31
									
								
								test/MsgPack/nestingLimit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								test/MsgPack/nestingLimit.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| static void check(const char* input, MsgPackError expected, uint8_t limit) { | ||||
|   DynamicJsonDocument doc; | ||||
|   doc.nestingLimit = limit; | ||||
|  | ||||
|   MsgPackError error = deserializeMsgPack(doc, input); | ||||
|  | ||||
|   REQUIRE(error == expected); | ||||
| } | ||||
|  | ||||
| TEST_CASE("Errors returned by deserializeMsgPack()") { | ||||
|   SECTION("object too deep") { | ||||
|     check("\x80", MsgPackError::TooDeep, 0);           // {} | ||||
|     check("\x80", MsgPackError::Ok, 1);                // {} | ||||
|     check("\x81\xA1H\x80", MsgPackError::TooDeep, 1);  // {H:{}} | ||||
|     check("\x81\xA1H\x80", MsgPackError::Ok, 2);       // {H:{}} | ||||
|   } | ||||
|  | ||||
|   SECTION("array too deep") { | ||||
|     check("\x90", MsgPackError::TooDeep, 0);      // [] | ||||
|     check("\x90", MsgPackError::Ok, 1);           // [] | ||||
|     check("\x91\x90", MsgPackError::TooDeep, 1);  // [[]] | ||||
|     check("\x91\x90", MsgPackError::Ok, 2);       // [[]] | ||||
|   } | ||||
| } | ||||
							
								
								
									
										73
									
								
								test/MsgPack/notSupported.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								test/MsgPack/notSupported.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| static void checkNotSupported(const char* input) { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   MsgPackError error = deserializeMsgPack(doc, input); | ||||
|  | ||||
|   REQUIRE(error == MsgPackError::NotSupported); | ||||
| } | ||||
|  | ||||
| TEST_CASE("deserializeMsgPack() return NotSupported") { | ||||
|   SECTION("bin 8") { | ||||
|     checkNotSupported("\xc4"); | ||||
|   } | ||||
|  | ||||
|   SECTION("bin 16") { | ||||
|     checkNotSupported("\xc5"); | ||||
|   } | ||||
|  | ||||
|   SECTION("bin 32") { | ||||
|     checkNotSupported("\xc6"); | ||||
|   } | ||||
|  | ||||
|   SECTION("ext 8") { | ||||
|     checkNotSupported("\xc7"); | ||||
|   } | ||||
|  | ||||
|   SECTION("ext 16") { | ||||
|     checkNotSupported("\xc8"); | ||||
|   } | ||||
|  | ||||
|   SECTION("ext 32") { | ||||
|     checkNotSupported("\xc9"); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixext 1") { | ||||
|     checkNotSupported("\xd4"); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixext 2") { | ||||
|     checkNotSupported("\xd5"); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixext 4") { | ||||
|     checkNotSupported("\xd6"); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixext 8") { | ||||
|     checkNotSupported("\xd7"); | ||||
|   } | ||||
|  | ||||
|   SECTION("fixext 16") { | ||||
|     checkNotSupported("\xd8"); | ||||
|   } | ||||
|  | ||||
|   SECTION("unsupported in array") { | ||||
|     checkNotSupported("\x91\xc4"); | ||||
|   } | ||||
|  | ||||
|   SECTION("unsupported in map") { | ||||
|     checkNotSupported("\x81\xc4\x00\xA1H"); | ||||
|     checkNotSupported("\x81\xA1H\xc4\x00"); | ||||
|   } | ||||
|  | ||||
|   SECTION("integer as key") { | ||||
|     checkNotSupported("\x81\x01\xA1H"); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										29
									
								
								test/MsgPack/std_istream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								test/MsgPack/std_istream.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("deserializeMsgPack(std::istream&)") { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   SECTION("should accept a zero in input") { | ||||
|     std::istringstream input(std::string("\x92\x00\x02", 3)); | ||||
|  | ||||
|     MsgPackError err = deserializeMsgPack(doc, input); | ||||
|  | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|     JsonArray& arr = doc.as<JsonArray>(); | ||||
|     REQUIRE(arr[0] == 0); | ||||
|     REQUIRE(arr[1] == 2); | ||||
|   } | ||||
|  | ||||
|   SECTION("should detect incomplete input") { | ||||
|     std::istringstream input("\x92\x00\x02"); | ||||
|  | ||||
|     MsgPackError err = deserializeMsgPack(doc, input); | ||||
|  | ||||
|     REQUIRE(err == MsgPackError::IncompleteInput); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										44
									
								
								test/MsgPack/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								test/MsgPack/std_string.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("deserializeMsgPack(const std::string&)") { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   SECTION("should accept const string") { | ||||
|     const std::string input("\x92\x01\x02"); | ||||
|  | ||||
|     MsgPackError err = deserializeMsgPack(doc, input); | ||||
|  | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("should accept temporary string") { | ||||
|     MsgPackError err = deserializeMsgPack(doc, std::string("\x92\x01\x02")); | ||||
|  | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|   } | ||||
|  | ||||
|   SECTION("should duplicate content") { | ||||
|     std::string input("\x91\xA5hello"); | ||||
|  | ||||
|     MsgPackError err = deserializeMsgPack(doc, input); | ||||
|     input[2] = 'X';  // alter the string tomake sure we made a copy | ||||
|  | ||||
|     JsonArray& array = doc.as<JsonArray>(); | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|     REQUIRE(std::string("hello") == array[0]); | ||||
|   } | ||||
|  | ||||
|   SECTION("should accept a zero in input") { | ||||
|     MsgPackError err = deserializeMsgPack(doc, std::string("\x92\x00\x02", 3)); | ||||
|  | ||||
|     REQUIRE(err == MsgPackError::Ok); | ||||
|     JsonArray& arr = doc.as<JsonArray>(); | ||||
|     REQUIRE(arr[0] == 0); | ||||
|     REQUIRE(arr[1] == 2); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user