Added support for non zero-terminated strings (fixes #704)

This commit is contained in:
Benoit Blanchon
2018-05-14 17:12:59 +02:00
parent 4c9c047ddf
commit ccb54136a2
54 changed files with 2234 additions and 1401 deletions

View File

@ -31,7 +31,7 @@ matrix:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5'] packages: ['g++-5']
env: SCRIPT=cmake GCC=5 SANITIZE=undefined env: SCRIPT=cmake GCC=5 # SANITIZE=undefined
- compiler: gcc - compiler: gcc
addons: addons:
apt: apt:

View File

@ -12,6 +12,7 @@ HEAD
* Added `measureJson()` and `measureJsonPretty()` * Added `measureJson()` and `measureJsonPretty()`
* Added `deserializeMsgPack()` (issue #358) * Added `deserializeMsgPack()` (issue #358)
* Added example `MsgPackParser.ino` (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::parseArray()`, `parseObject()` and `parse()`
* Removed `JsonBuffer::createArray()` and `createObject()` * Removed `JsonBuffer::createArray()` and `createObject()`
* Removed `printTo()` and `prettyPrintTo()` * Removed `printTo()` and `prettyPrintTo()`

View File

@ -5,12 +5,10 @@
#pragma once #pragma once
#include "ArduinoJson/DynamicJsonDocument.hpp" #include "ArduinoJson/DynamicJsonDocument.hpp"
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
#include "ArduinoJson/StaticJsonDocument.hpp" #include "ArduinoJson/StaticJsonDocument.hpp"
#include "ArduinoJson/deserializeJson.hpp" #include "ArduinoJson/deserializeJson.hpp"
#include "ArduinoJson/deserializeMsgPack.hpp" #include "ArduinoJson/deserializeMsgPack.hpp"
#include "ArduinoJson/Json/Deserialization/JsonDeserializer.hpp"
#include "ArduinoJson/Json/Serialization/JsonSerializer.hpp" #include "ArduinoJson/Json/Serialization/JsonSerializer.hpp"
#include "ArduinoJson/JsonArrayImpl.hpp" #include "ArduinoJson/JsonArrayImpl.hpp"
#include "ArduinoJson/JsonObjectImpl.hpp" #include "ArduinoJson/JsonObjectImpl.hpp"

View File

@ -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;
}
}
}
}
}

View File

@ -7,10 +7,9 @@
#include "../../JsonError.hpp" #include "../../JsonError.hpp"
#include "../../JsonVariant.hpp" #include "../../JsonVariant.hpp"
#include "../../Memory/JsonBuffer.hpp" #include "../../Memory/JsonBuffer.hpp"
#include "../../Strings/StringWriter.hpp" #include "../../Reading/Reader.hpp"
#include "../../TypeTraits/IsConst.hpp" #include "../../TypeTraits/IsConst.hpp"
#include "../Encoding.hpp" #include "../Encoding.hpp"
#include "./Comments.hpp"
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
@ -23,11 +22,13 @@ class JsonDeserializer {
: _buffer(buffer), : _buffer(buffer),
_reader(reader), _reader(reader),
_writer(writer), _writer(writer),
_nestingLimit(nestingLimit) {} _nestingLimit(nestingLimit),
_loaded(false) {}
JsonError parse(JsonVariant &variant) { JsonError parse(JsonVariant &variant) {
skipSpacesAndComments(_reader); JsonError err = skipSpacesAndComments();
if (err) return err;
switch (_reader.current()) { switch (current()) {
case '[': case '[':
return parseArray(variant); return parseArray(variant);
@ -42,15 +43,25 @@ class JsonDeserializer {
private: private:
JsonDeserializer &operator=(const JsonDeserializer &); // non-copiable JsonDeserializer &operator=(const JsonDeserializer &); // non-copiable
static bool eat(TReader &reader, char charToSkip) { char current() {
skipSpacesAndComments(reader); if (!_loaded) {
if (reader.current() != charToSkip) return false; if (_reader.ended())
reader.move(); _current = 0;
return true; else
_current = _reader.read();
_loaded = true;
}
return _current;
}
void move() {
_loaded = false;
} }
FORCE_INLINE bool eat(char charToSkip) { FORCE_INLINE bool eat(char charToSkip) {
return eat(_reader, charToSkip); if (current() != charToSkip) return false;
move();
return true;
} }
JsonError parseArray(JsonVariant &variant) { JsonError parseArray(JsonVariant &variant) {
@ -62,6 +73,12 @@ class JsonDeserializer {
// Check opening braket // Check opening braket
if (!eat('[')) return JsonError::InvalidInput; if (!eat('[')) return JsonError::InvalidInput;
// Skip spaces
JsonError err = skipSpacesAndComments();
if (err) return err;
// Empty array?
if (eat(']')) return JsonError::Ok; if (eat(']')) return JsonError::Ok;
// Read each value // Read each value
@ -69,12 +86,16 @@ class JsonDeserializer {
// 1 - Parse value // 1 - Parse value
JsonVariant value; JsonVariant value;
_nestingLimit--; _nestingLimit--;
JsonError error = parse(value); err = parse(value);
_nestingLimit++; _nestingLimit++;
if (error != JsonError::Ok) return error; if (err) return err;
if (!array->add(value)) return JsonError::NoMemory; 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::Ok;
if (!eat(',')) return JsonError::InvalidInput; if (!eat(',')) return JsonError::InvalidInput;
} }
@ -89,31 +110,52 @@ class JsonDeserializer {
// Check opening brace // Check opening brace
if (!eat('{')) return JsonError::InvalidInput; if (!eat('{')) return JsonError::InvalidInput;
// Skip spaces
JsonError err = skipSpacesAndComments();
if (err) return err;
// Empty object?
if (eat('}')) return JsonError::Ok; if (eat('}')) return JsonError::Ok;
// Read each key value pair // Read each key value pair
for (;;) { for (;;) {
// 1 - Parse key // Parse key
const char *key; const char *key;
JsonError error = parseString(&key); err = parseString(&key);
if (error) return error; if (err) return err;
// Skip spaces
err = skipSpacesAndComments();
if (err) return err;
// Colon
if (!eat(':')) return JsonError::InvalidInput; if (!eat(':')) return JsonError::InvalidInput;
// 2 - Parse value // Parse value
JsonVariant value; JsonVariant value;
_nestingLimit--; _nestingLimit--;
error = parse(value); err = parse(value);
_nestingLimit++; _nestingLimit++;
if (error != JsonError::Ok) return error; if (err) return err;
if (!object->set(key, value)) return JsonError::NoMemory; 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::Ok;
if (!eat(',')) return JsonError::InvalidInput; if (!eat(',')) return JsonError::InvalidInput;
// Skip spaces
err = skipSpacesAndComments();
if (err) return err;
} }
} }
JsonError parseValue(JsonVariant &variant) { JsonError parseValue(JsonVariant &variant) {
bool hasQuotes = isQuote(_reader.current()); bool hasQuotes = isQuote(current());
const char *value; const char *value;
JsonError error = parseString(&value); JsonError error = parseString(&value);
if (error) return error; if (error) return error;
@ -128,33 +170,35 @@ class JsonDeserializer {
JsonError parseString(const char **result) { JsonError parseString(const char **result) {
typename RemoveReference<TWriter>::type::String str = _writer.startString(); typename RemoveReference<TWriter>::type::String str = _writer.startString();
skipSpacesAndComments(_reader); char c = current();
char c = _reader.current(); if (c == '\0') return JsonError::IncompleteInput;
if (isQuote(c)) { // quotes if (isQuote(c)) { // quotes
_reader.move(); move();
char stopChar = c; char stopChar = c;
for (;;) { for (;;) {
c = _reader.current(); c = current();
if (c == '\0') break; move();
_reader.move();
if (c == stopChar) break; if (c == stopChar) break;
if (c == '\0') return JsonError::IncompleteInput;
if (c == '\\') { if (c == '\\') {
c = current();
if (c == 0) return JsonError::IncompleteInput;
// replace char // replace char
c = Encoding::unescapeChar(_reader.current()); c = Encoding::unescapeChar(c);
if (c == '\0') return JsonError::InvalidInput; if (c == '\0') return JsonError::InvalidInput;
_reader.move(); move();
} }
str.append(c); str.append(c);
} }
} else if (canBeInNonQuotedString(c)) { // no quotes } else if (canBeInNonQuotedString(c)) { // no quotes
do { do {
_reader.move(); move();
str.append(c); str.append(c);
c = _reader.current(); c = current();
} while (canBeInNonQuotedString(c)); } while (canBeInNonQuotedString(c));
} else { } else {
return JsonError::InvalidInput; return JsonError::InvalidInput;
@ -178,40 +222,79 @@ class JsonDeserializer {
return c == '\'' || c == '\"'; 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; JsonBuffer *_buffer;
TReader _reader; TReader _reader;
TWriter _writer; TWriter _writer;
uint8_t _nestingLimit; uint8_t _nestingLimit;
char _current;
bool _loaded;
}; };
template <typename TJsonBuffer, typename TString, typename Enable = void> template <typename TJsonBuffer, typename TReader, typename TWriter>
struct JsonParserBuilder { JsonDeserializer<TReader, TWriter> makeJsonDeserializer(TJsonBuffer *buffer,
typedef typename StringTraits<TString>::Reader InputReader; TReader reader,
typedef JsonDeserializer<InputReader, TJsonBuffer &> TParser; TWriter writer,
static TParser makeParser(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) { uint8_t nestingLimit) {
return TParser(buffer, InputReader(json), *buffer, nestingLimit); return JsonDeserializer<TReader, TWriter>(buffer, reader, writer,
}
};
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); nestingLimit);
} }
} // namespace Internals } // namespace Internals

View File

@ -4,11 +4,15 @@
#pragma once #pragma once
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream>
#endif
namespace ArduinoJson { namespace ArduinoJson {
class JsonError { class JsonError {
public: public:
enum Code { Ok, TooDeep, NoMemory, InvalidInput }; enum Code { Ok, TooDeep, NoMemory, InvalidInput, IncompleteInput };
JsonError(Code code) : _code(code) {} JsonError(Code code) : _code(code) {}
@ -42,6 +46,8 @@ class JsonError {
return "NoMemory"; return "NoMemory";
case InvalidInput: case InvalidInput:
return "InvalidInput"; return "InvalidInput";
case IncompleteInput:
return "IncompleteInput";
default: default:
return "???"; return "???";
} }

View File

@ -6,8 +6,9 @@
#include "../JsonVariant.hpp" #include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp" #include "../Memory/JsonBuffer.hpp"
#include "../Strings/StringWriter.hpp" #include "../Reading/Reader.hpp"
#include "../TypeTraits/IsConst.hpp" #include "../TypeTraits/IsConst.hpp"
#include "../Writing/Writer.hpp"
#include "./MsgPackError.hpp" #include "./MsgPackError.hpp"
#include "./endianess.hpp" #include "./endianess.hpp"
#include "./ieee754.hpp" #include "./ieee754.hpp"
@ -29,27 +30,28 @@ class MsgPackDeserializer {
_nestingLimit(nestingLimit) {} _nestingLimit(nestingLimit) {}
MsgPackError parse(JsonVariant &variant) { MsgPackError parse(JsonVariant &variant) {
uint8_t c = readOne(); uint8_t code;
if (!readByte(code)) return MsgPackError::IncompleteInput;
if ((c & 0x80) == 0) { if ((code & 0x80) == 0) {
variant = c; variant = code;
return MsgPackError::Ok; return MsgPackError::Ok;
} }
if ((c & 0xe0) == 0xe0) { if ((code & 0xe0) == 0xe0) {
variant = static_cast<int8_t>(c); variant = static_cast<int8_t>(code);
return MsgPackError::Ok; return MsgPackError::Ok;
} }
if ((c & 0xe0) == 0xa0) { if ((code & 0xe0) == 0xa0) {
return readString(variant, c & 0x1f); 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: case 0xc0:
variant = static_cast<char *>(0); variant = static_cast<char *>(0);
return MsgPackError::Ok; return MsgPackError::Ok;
@ -63,81 +65,65 @@ class MsgPackDeserializer {
return MsgPackError::Ok; return MsgPackError::Ok;
case 0xcc: case 0xcc:
variant = readInteger<uint8_t>(); return readInteger<uint8_t>(variant);
return MsgPackError::Ok;
case 0xcd: case 0xcd:
variant = readInteger<uint16_t>(); return readInteger<uint16_t>(variant);
return MsgPackError::Ok;
case 0xce: case 0xce:
variant = readInteger<uint32_t>(); return readInteger<uint32_t>(variant);
return MsgPackError::Ok;
case 0xcf: case 0xcf:
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
variant = readInteger<uint64_t>(); return readInteger<uint64_t>(variant);
#else #else
readInteger<uint32_t>(); readInteger<uint32_t>();
variant = readInteger<uint32_t>(); return readInteger<uint32_t>(variant);
#endif #endif
return MsgPackError::Ok;
case 0xd0: case 0xd0:
variant = readInteger<int8_t>(); return readInteger<int8_t>(variant);
return MsgPackError::Ok;
case 0xd1: case 0xd1:
variant = readInteger<int16_t>(); return readInteger<int16_t>(variant);
return MsgPackError::Ok;
case 0xd2: case 0xd2:
variant = readInteger<int32_t>(); return readInteger<int32_t>(variant);
return MsgPackError::Ok;
case 0xd3: case 0xd3:
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
variant = readInteger<int64_t>(); return readInteger<int64_t>(variant);
#else #else
readInteger<int32_t>(); if (!skip(4)) return MsgPackError::IncompleteInput;
variant = readInteger<int32_t>(); return readInteger<int32_t>(variant);
#endif #endif
return MsgPackError::Ok;
case 0xca: case 0xca:
variant = readFloat<float>(); return readFloat<float>(variant);
return MsgPackError::Ok;
case 0xcb: case 0xcb:
variant = readDouble<double>(); return readDouble<double>(variant);
return MsgPackError::Ok;
case 0xd9: { case 0xd9:
uint8_t n = readInteger<uint8_t>(); return readString<uint8_t>(variant);
return readString(variant, n);
}
case 0xda: { case 0xda:
uint16_t n = readInteger<uint16_t>(); return readString<uint16_t>(variant);
return readString(variant, n);
}
case 0xdb: { case 0xdb:
uint32_t n = readInteger<uint32_t>(); return readString<uint32_t>(variant);
return readString(variant, n);
}
case 0xdc: case 0xdc:
return readArray(variant, readInteger<uint16_t>()); return readArray<uint16_t>(variant);
case 0xdd: case 0xdd:
return readArray(variant, readInteger<uint32_t>()); return readArray<uint32_t>(variant);
case 0xde: case 0xde:
return readObject(variant, readInteger<uint16_t>()); return readObject<uint16_t>(variant);
case 0xdf: case 0xdf:
return readObject(variant, readInteger<uint32_t>()); return readObject<uint32_t>(variant);
default: default:
return MsgPackError::NotSupported; return MsgPackError::NotSupported;
@ -148,65 +134,115 @@ class MsgPackDeserializer {
// Prevent VS warning "assignment operator could not be generated" // Prevent VS warning "assignment operator could not be generated"
MsgPackDeserializer &operator=(const MsgPackDeserializer &); MsgPackDeserializer &operator=(const MsgPackDeserializer &);
uint8_t readOne() { bool skip(uint8_t n) {
char c = _reader.current(); while (n--) {
_reader.move(); if (_reader.ended()) return false;
return static_cast<uint8_t>(c); _reader.read();
}
return true;
} }
void read(uint8_t *p, size_t n) { bool readByte(uint8_t &value) {
for (size_t i = 0; i < n; i++) p[i] = readOne(); 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> template <typename T>
void read(T &value) { bool readBytes(T &value) {
read(reinterpret_cast<uint8_t *>(&value), sizeof(value)); return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
} }
template <typename T> template <typename T>
T readInteger() { T readInteger() {
T value; T value;
read(value); readBytes(value);
fixEndianess(value); fixEndianess(value);
return value; return value;
} }
template <typename T> 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; T value;
read(value); if (!readInteger(value)) return MsgPackError::IncompleteInput;
fixEndianess(value); variant = value;
return value; return MsgPackError::Ok;
} }
template <typename T> template <typename T>
typename EnableIf<sizeof(T) == 8, T>::type readDouble() { typename EnableIf<sizeof(T) == 4, MsgPackError>::type readFloat(
JsonVariant &variant) {
T value; T value;
read(value); if (!readBytes(value)) return MsgPackError::IncompleteInput;
fixEndianess(value); fixEndianess(value);
return value; variant = value;
return MsgPackError::Ok;
} }
template <typename T> 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 uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes T value; // output is 4 bytes
uint8_t *o = reinterpret_cast<uint8_t *>(&value); uint8_t *o = reinterpret_cast<uint8_t *>(&value);
read(i, 8); if (!readBytes(i, 8)) return MsgPackError::IncompleteInput;
doubleToFloat(i, o); doubleToFloat(i, o);
fixEndianess(value); 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) { MsgPackError readString(JsonVariant &variant, size_t n) {
typename RemoveReference<TWriter>::type::String str = _writer.startString(); 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(); const char *s = str.c_str();
if (s == NULL) return MsgPackError::NoMemory; if (s == NULL) return MsgPackError::NoMemory;
variant = s; variant = s;
return MsgPackError::Ok; 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) { MsgPackError readArray(JsonVariant &variant, size_t n) {
JsonArray *array = new (_buffer) JsonArray(_buffer); JsonArray *array = new (_buffer) JsonArray(_buffer);
if (!array) return MsgPackError::NoMemory; if (!array) return MsgPackError::NoMemory;
@ -227,6 +263,13 @@ class MsgPackDeserializer {
return MsgPackError::Ok; 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) { MsgPackError readObject(JsonVariant &variant, size_t n) {
JsonObject *object = new (_buffer) JsonObject(_buffer); JsonObject *object = new (_buffer) JsonObject(_buffer);
if (!object) return MsgPackError::NoMemory; if (!object) return MsgPackError::NoMemory;
@ -258,36 +301,10 @@ class MsgPackDeserializer {
uint8_t _nestingLimit; uint8_t _nestingLimit;
}; };
template <typename TJsonBuffer, typename TString, typename Enable = void> template <typename TJsonBuffer, typename TReader, typename TWriter>
struct MsgPackDeserializerBuilder { MsgPackDeserializer<TReader, TWriter> makeMsgPackDeserializer(
typedef typename StringTraits<TString>::Reader InputReader; TJsonBuffer *buffer, TReader reader, TWriter writer, uint8_t nestingLimit) {
typedef MsgPackDeserializer<InputReader, TJsonBuffer &> TParser; return MsgPackDeserializer<TReader, TWriter>(buffer, reader, writer,
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); nestingLimit);
} }
} // namespace Internals } // namespace Internals

View File

@ -4,11 +4,15 @@
#pragma once #pragma once
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream>
#endif
namespace ArduinoJson { namespace ArduinoJson {
class MsgPackError { class MsgPackError {
public: public:
enum Code { Ok, NotSupported, NoMemory, TooDeep }; enum Code { Ok, NotSupported, NoMemory, TooDeep, IncompleteInput };
MsgPackError() {} MsgPackError() {}
@ -44,6 +48,8 @@ class MsgPackError {
return "NoMemory"; return "NoMemory";
case TooDeep: case TooDeep:
return "TooDeep"; return "TooDeep";
case IncompleteInput:
return "IncompleteInput";
default: default:
return "???"; return "???";
} }

View 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

View 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

View 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

View 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

View 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"

View 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

View File

@ -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

View File

@ -9,26 +9,6 @@ namespace Internals {
template <typename TChar> template <typename TChar>
struct CharPointerTraits { 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) { static bool equals(const TChar* str, const char* expected) {
return strcmp(reinterpret_cast<const char*>(str), expected) == 0; return strcmp(reinterpret_cast<const char*>(str), expected) == 0;
} }

View File

@ -10,26 +10,6 @@ namespace ArduinoJson {
namespace Internals { namespace Internals {
template <> template <>
struct StringTraits<const __FlashStringHelper*, void> { 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) { static bool equals(const __FlashStringHelper* str, const char* expected) {
return strcmp_P(expected, (const char*)str) == 0; return strcmp_P(expected, (const char*)str) == 0;
} }

View File

@ -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

View File

@ -35,10 +35,6 @@ struct StdStringTraits {
return !str.c_str(); 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) { static bool equals(const TString& str, const char* expected) {
return 0 == strcmp(str.c_str(), expected); return 0 == strcmp(str.c_str(), expected);
} }

View File

@ -29,8 +29,6 @@ struct StringTraits<TString&, void> : StringTraits<TString> {};
} }
} }
#include "ArduinoStream.hpp"
#include "CharPointer.hpp" #include "CharPointer.hpp"
#include "FlashString.hpp" #include "FlashString.hpp"
#include "StdStream.hpp"
#include "StdString.hpp" #include "StdString.hpp"

View 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

View 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

View File

@ -5,34 +5,53 @@
#pragma once #pragma once
#include "Json/Deserialization/JsonDeserializer.hpp" #include "Json/Deserialization/JsonDeserializer.hpp"
#include "Reading/Reader.hpp"
#include "Writing/Writer.hpp"
namespace ArduinoJson { namespace ArduinoJson {
// JsonError deserializeJson(TDocument& doc, TString json); // JsonError deserializeJson(TDocument& doc, TString input);
// TDocument = DynamicJsonDocument, StaticJsonDocument // TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const std::string&, const String& // TString = const std::string&, const String&
template <typename TDocument, typename TString> template <typename TDocument, typename TString>
typename Internals::EnableIf<!Internals::IsArray<TString>::value, typename Internals::EnableIf<!Internals::IsArray<TString>::value,
JsonError>::type JsonError>::type
deserializeJson(TDocument &doc, const TString &json) { deserializeJson(TDocument &doc, const TString &input) {
return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit) using namespace Internals;
return makeJsonDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariant>()); .parse(doc.template to<JsonVariant>());
} }
// //
// JsonError deserializeJson(TDocument& doc, TString json); // JsonError deserializeJson(TDocument& doc, TChar* input);
// TDocument = DynamicJsonDocument, StaticJsonDocument // TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const char*, const char[N], const FlashStringHelper* // TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TString> template <typename TDocument, typename TChar>
JsonError deserializeJson(TDocument &doc, TString *json) { JsonError deserializeJson(TDocument &doc, TChar *input) {
return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit) using namespace Internals;
return makeJsonDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariant>()); .parse(doc.template to<JsonVariant>());
} }
// //
// JsonError deserializeJson(TDocument& doc, TString json); // JsonError deserializeJson(TDocument& doc, TChar* input, size_t inputSize);
// TDocument = DynamicJsonDocument, StaticJsonDocument // TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = std::istream&, Stream& // TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TString> template <typename TDocument, typename TChar>
JsonError deserializeJson(TDocument &doc, TString &json) { JsonError deserializeJson(TDocument &doc, TChar *input, size_t inputSize) {
return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit) 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>()); .parse(doc.template to<JsonVariant>());
} }
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -5,36 +5,58 @@
#pragma once #pragma once
#include "MsgPack/MsgPackDeserializer.hpp" #include "MsgPack/MsgPackDeserializer.hpp"
#include "Reading/Reader.hpp"
#include "Writing/Writer.hpp"
namespace ArduinoJson { namespace ArduinoJson {
// MsgPackError deserializeMsgPack(TDocument& doc, TString json); // MsgPackError deserializeMsgPack(TDocument& doc, TString input);
// TDocument = DynamicJsonArray | StaticJsonArray // TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const std::string&, const String& // TString = const std::string&, const String&
template <typename TDocument, typename TString> template <typename TDocument, typename TString>
typename Internals::EnableIf<!Internals::IsArray<TString>::value, typename Internals::EnableIf<!Internals::IsArray<TString>::value,
MsgPackError>::type MsgPackError>::type
deserializeMsgPack(TDocument &doc, const TString &json) { deserializeMsgPack(TDocument &doc, const TString &input) {
return Internals::makeMsgPackDeserializer(&doc.buffer(), json, using namespace Internals;
return makeMsgPackDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input),
doc.nestingLimit) doc.nestingLimit)
.parse(doc.template to<JsonVariant>()); .parse(doc.template to<JsonVariant>());
} }
// //
// MsgPackError deserializeMsgPack(TDocument& doc, TString json); // MsgPackError deserializeMsgPack(TDocument& doc, TChar* input);
// TDocument = DynamicJsonArray | StaticJsonArray // TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const char*, const char[N], const FlashStringHelper* // TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TString> template <typename TDocument, typename TChar>
MsgPackError deserializeMsgPack(TDocument &doc, TString *json) { MsgPackError deserializeMsgPack(TDocument &doc, TChar *input) {
return Internals::makeMsgPackDeserializer(&doc.buffer(), json, using namespace Internals;
return makeMsgPackDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input),
doc.nestingLimit) doc.nestingLimit)
.parse(doc.template to<JsonVariant>()); .parse(doc.template to<JsonVariant>());
} }
// //
// MsgPackError deserializeMsgPack(TDocument& doc, TString json); // MsgPackError deserializeMsgPack(TDocument& doc, TChar* input, size_t
// TDocument = DynamicJsonArray | StaticJsonArray // inputSize);
// TString = std::istream&, Stream& // TDocument = DynamicJsonDocument, StaticJsonDocument
template <typename TDocument, typename TString> // TChar* = char*, const char*, const FlashStringHelper*
MsgPackError deserializeMsgPack(TDocument &doc, TString &json) { template <typename TDocument, typename TChar>
return Internals::makeMsgPackDeserializer(&doc.buffer(), json, 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) doc.nestingLimit)
.parse(doc.template to<JsonVariant>()); .parse(doc.template to<JsonVariant>());
} }

View File

@ -12,6 +12,7 @@ add_executable(JsonArrayTests
remove.cpp remove.cpp
set.cpp set.cpp
size.cpp size.cpp
std_string.cpp
subscript.cpp subscript.cpp
) )

View 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]);
}
}

View File

@ -10,6 +10,8 @@ add_executable(JsonDeserializerTests
deserializeJsonValue.cpp deserializeJsonValue.cpp
JsonError.cpp JsonError.cpp
nestingLimit.cpp nestingLimit.cpp
std_istream.cpp
std_string.cpp
) )
target_link_libraries(JsonDeserializerTests catch) target_link_libraries(JsonDeserializerTests catch)

View File

@ -25,6 +25,7 @@ TEST_CASE("JsonError") {
TEST_STRINGIFICATION(TooDeep); TEST_STRINGIFICATION(TooDeep);
TEST_STRINGIFICATION(NoMemory); TEST_STRINGIFICATION(NoMemory);
TEST_STRINGIFICATION(InvalidInput); TEST_STRINGIFICATION(InvalidInput);
TEST_STRINGIFICATION(IncompleteInput);
} }
SECTION("as boolean") { SECTION("as boolean") {
@ -32,6 +33,7 @@ TEST_CASE("JsonError") {
TEST_BOOLIFICATION(TooDeep, true); TEST_BOOLIFICATION(TooDeep, true);
TEST_BOOLIFICATION(NoMemory, true); TEST_BOOLIFICATION(NoMemory, true);
TEST_BOOLIFICATION(InvalidInput, true); TEST_BOOLIFICATION(InvalidInput, true);
TEST_BOOLIFICATION(IncompleteInput, true);
} }
SECTION("ostream") { SECTION("ostream") {

View File

@ -164,13 +164,13 @@ TEST_CASE("deserialize JSON array") {
SECTION("Closing single quotes missing") { SECTION("Closing single quotes missing") {
JsonError err = deserializeJson(doc, "[\"]"); JsonError err = deserializeJson(doc, "[\"]");
REQUIRE(err == JsonError::InvalidInput); REQUIRE(err == JsonError::IncompleteInput);
} }
SECTION("Closing double quotes missing") { SECTION("Closing double quotes missing") {
JsonError err = deserializeJson(doc, "[\']"); JsonError err = deserializeJson(doc, "[\']");
REQUIRE(err == JsonError::InvalidInput); REQUIRE(err == JsonError::IncompleteInput);
} }
} }
@ -233,21 +233,21 @@ TEST_CASE("deserialize JSON array") {
SECTION("/*/") { SECTION("/*/") {
JsonError err = deserializeJson(doc, "[/*/\n]"); JsonError err = deserializeJson(doc, "[/*/\n]");
REQUIRE(err == JsonError::InvalidInput); REQUIRE(err == JsonError::IncompleteInput);
} }
SECTION("Unfinished comment") { SECTION("Unfinished comment") {
JsonError err = deserializeJson(doc, "[/*COMMENT]"); JsonError err = deserializeJson(doc, "[/*COMMENT]");
REQUIRE(err == JsonError::InvalidInput); REQUIRE(err == JsonError::IncompleteInput);
} }
SECTION("Final slash missing") { SECTION("Final slash missing") {
JsonError err = deserializeJson(doc, "[/*COMMENT*]"); JsonError err = deserializeJson(doc, "[/*COMMENT*]");
REQUIRE(err == JsonError::InvalidInput); REQUIRE(err == JsonError::IncompleteInput);
} }
} }
SECTION("Line comments") { SECTION("Trailing comments") {
SECTION("Before opening bracket") { SECTION("Before opening bracket") {
JsonError err = deserializeJson(doc, "//COMMENT\n\t[\"hello\"]"); JsonError err = deserializeJson(doc, "//COMMENT\n\t[\"hello\"]");
JsonArray& arr = doc.as<JsonArray>(); JsonArray& arr = doc.as<JsonArray>();
@ -311,39 +311,53 @@ TEST_CASE("deserialize JSON array") {
SECTION("End document with comment") { SECTION("End document with comment") {
JsonError err = deserializeJson(doc, "[//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("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") { SECTION("Nested objects") {
char jsonString[] = char jsonString[] =
" [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] "; " [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] ";

View File

@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
JsonError err = deserializeJson(doc, input); JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok); REQUIRE(err == JsonError::NoMemory);
} }
SECTION("BufferOfTheRightSizeForArrayWithOneValue") { SECTION("BufferOfTheRightSizeForArrayWithOneValue") {
@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
JsonError err = deserializeJson(doc, input); JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok); REQUIRE(err == JsonError::NoMemory);
} }
SECTION("BufferOfTheRightSizeForArrayWithNestedObject") { SECTION("BufferOfTheRightSizeForArrayWithNestedObject") {
@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
REQUIRE(err == JsonError::Ok); 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") { SECTION("CopyStringNotSpaces") {
StaticJsonDocument<100> doc; StaticJsonDocument<100> doc;

View File

@ -212,19 +212,39 @@ TEST_CASE("deserialize JSON object") {
} }
} }
SECTION("Misc") { SECTION("Premature null terminator") {
SECTION("The opening brace is missing") { SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "}"); 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\""); 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") { SECTION("A quoted key without value") {
JsonError err = deserializeJson(doc, "{\"key\"}"); 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") { SECTION("Should clear the JsonObject") {
deserializeJson(doc, "{\"hello\":\"world\"}"); deserializeJson(doc, "{\"hello\":\"world\"}");
deserializeJson(doc, "{}"); deserializeJson(doc, "{}");

View File

@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") {
JsonError err = deserializeJson(doc, input); JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok); REQUIRE(err == JsonError::NoMemory);
} }
SECTION("BufferOfTheRightSizeForObjectWithOneValue") { SECTION("BufferOfTheRightSizeForObjectWithOneValue") {
@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") {
JsonError err = deserializeJson(doc, input); JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok); REQUIRE(err == JsonError::NoMemory);
} }
SECTION("BufferOfTheRightSizeForObjectWithNestedObject") { SECTION("BufferOfTheRightSizeForObjectWithNestedObject") {
@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") {
REQUIRE(err == JsonError::Ok); 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") { SECTION("Should clear the JsonObject") {
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
char input[] = "{\"hello\":\"world\"}"; char input[] = "{\"hello\":\"world\"}";

View File

@ -10,18 +10,16 @@ using namespace Catch::Matchers;
TEST_CASE("deserializeJson(DynamicJsonDocument&)") { TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
SECTION("EmptyObject") { SECTION("null char*") {
JsonError err = deserializeJson(doc, "{}"); JsonError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err == JsonError::Ok); REQUIRE(err != JsonError::Ok);
REQUIRE(doc.is<JsonObject>());
} }
SECTION("EmptyArray") { SECTION("null const char*") {
JsonError err = deserializeJson(doc, "[]"); JsonError err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err == JsonError::Ok); REQUIRE(err != JsonError::Ok);
REQUIRE(doc.is<JsonArray>());
} }
SECTION("Integer") { SECTION("Integer") {
@ -58,6 +56,14 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE_THAT(doc.as<char*>(), Equals("hello world")); 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") { SECTION("True") {
JsonError err = deserializeJson(doc, "true"); JsonError err = deserializeJson(doc, "true");
@ -74,25 +80,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.as<bool>() == false); 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") { SECTION("Should clear the JsonVariant") {
deserializeJson(doc, "[1,2,3]"); deserializeJson(doc, "[1,2,3]");
deserializeJson(doc, "{}"); deserializeJson(doc, "{}");
@ -100,4 +87,86 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.is<JsonObject>()); REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); 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);
}
}
} }

View 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()));
}
}

View 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]);
}
}

View File

@ -11,6 +11,7 @@ add_executable(JsonObjectTests
remove.cpp remove.cpp
set.cpp set.cpp
size.cpp size.cpp
std_string.cpp
subscript.cpp subscript.cpp
) )

View 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);
}
}

View File

@ -8,6 +8,8 @@ add_executable(JsonSerializerTests
JsonObject.cpp JsonObject.cpp
JsonObjectPretty.cpp JsonObjectPretty.cpp
JsonVariant.cpp JsonVariant.cpp
std_stream.cpp
std_string.cpp
) )
target_link_libraries(JsonSerializerTests catch) target_link_libraries(JsonSerializerTests catch)

View 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());
}
}

View 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);
}
}

View File

@ -4,8 +4,6 @@
add_executable(MiscTests add_executable(MiscTests
FloatParts.cpp FloatParts.cpp
std_stream.cpp
std_string.cpp
StringBuilder.cpp StringBuilder.cpp
StringTraits.cpp StringTraits.cpp
TypeTraits.cpp TypeTraits.cpp

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -9,26 +9,27 @@
#define CONFLICTS_WITH_BUILTIN_OPERATOR #define CONFLICTS_WITH_BUILTIN_OPERATOR
#endif #endif
TEST_CASE("unsigned char string") { TEST_CASE("unsigned char[]") {
SECTION("JsonBuffer::parseArray") { SECTION("deserializeJson()") {
unsigned char json[] = "[42]"; unsigned char input[] = "{\"a\":42}";
StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc;
JsonError err = deserializeJson(doc, json);
REQUIRE(err == JsonError::Ok);
}
SECTION("JsonBuffer::parseObject") {
unsigned char json[] = "{\"a\":42}";
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
JsonError err = deserializeJson(doc, json); JsonError err = deserializeJson(doc, input);
REQUIRE(err == JsonError::Ok); REQUIRE(err == JsonError::Ok);
} }
SECTION("JsonVariant constructor") { SECTION("deserializeMsgPack()") {
unsigned char input[] = "\xDE\x00\x01\xA5Hello\xA5world";
StaticJsonDocument<JSON_OBJECT_SIZE(2)> doc;
MsgPackError err = deserializeMsgPack(doc, input);
REQUIRE(err == MsgPackError::Ok);
}
SECTION("JsonVariant") {
SECTION("constructor") {
unsigned char value[] = "42"; unsigned char value[] = "42";
JsonVariant variant(value); JsonVariant variant(value);
@ -36,7 +37,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(42 == variant.as<int>()); REQUIRE(42 == variant.as<int>());
} }
SECTION("JsonVariant assignment operator") { SECTION("operator=") {
unsigned char value[] = "42"; unsigned char value[] = "42";
JsonVariant variant(666); JsonVariant variant(666);
@ -46,7 +47,7 @@ TEST_CASE("unsigned char string") {
} }
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant::operator[]") { SECTION("operator[]") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -58,7 +59,7 @@ TEST_CASE("unsigned char string") {
#endif #endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant::operator[] const") { SECTION("operator[] const") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -69,7 +70,7 @@ TEST_CASE("unsigned char string") {
} }
#endif #endif
SECTION("JsonVariant::operator==") { SECTION("operator==") {
unsigned char comparand[] = "hello"; unsigned char comparand[] = "hello";
JsonVariant variant; JsonVariant variant;
@ -81,7 +82,7 @@ TEST_CASE("unsigned char string") {
REQUIRE_FALSE(variant != comparand); REQUIRE_FALSE(variant != comparand);
} }
SECTION("JsonVariant::operator!=") { SECTION("operator!=") {
unsigned char comparand[] = "hello"; unsigned char comparand[] = "hello";
JsonVariant variant; JsonVariant variant;
@ -92,9 +93,11 @@ TEST_CASE("unsigned char string") {
REQUIRE_FALSE(comparand == variant); REQUIRE_FALSE(comparand == variant);
REQUIRE_FALSE(variant == comparand); REQUIRE_FALSE(variant == comparand);
} }
}
SECTION("JsonObject") {
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject::operator[]") { SECTION("operator[]") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -103,29 +106,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == obj["hello"]); REQUIRE(std::string("world") == obj["hello"]);
} }
#endif
SECTION("JsonObjectSubscript::operator=") { // issue #416
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = value;
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("JsonObjectSubscript::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") { SECTION("JsonObject::operator[] const") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
@ -137,7 +118,7 @@ TEST_CASE("unsigned char string") {
} }
#endif #endif
SECTION("JsonObject::get()") { SECTION("get()") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -146,7 +127,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == obj.get<char*>(key)); REQUIRE(std::string("world") == obj.get<char*>(key));
} }
SECTION("JsonObject::set() key") { SECTION("set() key") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -156,7 +137,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == obj["hello"]); REQUIRE(std::string("world") == obj["hello"]);
} }
SECTION("JsonObject::set() value") { SECTION("set() value") {
unsigned char value[] = "world"; unsigned char value[] = "world";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -166,7 +147,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == obj["hello"]); REQUIRE(std::string("world") == obj["hello"]);
} }
SECTION("JsonObject::set key&value") { SECTION("set() key&value") {
unsigned char key[] = "world"; unsigned char key[] = "world";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -176,7 +157,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == obj["world"]); REQUIRE(std::string("world") == obj["world"]);
} }
SECTION("JsonObject::containsKey()") { SECTION("containsKey()") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -185,7 +166,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(true == obj.containsKey(key)); REQUIRE(true == obj.containsKey(key));
} }
SECTION("JsonObject::remove()") { SECTION("remove()") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -196,7 +177,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(0 == obj.size()); REQUIRE(0 == obj.size());
} }
SECTION("JsonObject::is()") { SECTION("is()") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -206,7 +187,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(true == obj.is<int>(key)); REQUIRE(true == obj.is<int>(key));
} }
SECTION("JsonObject::createNestedArray()") { SECTION("createNestedArray()") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -214,15 +195,39 @@ TEST_CASE("unsigned char string") {
obj.createNestedArray(key); obj.createNestedArray(key);
} }
SECTION("JsonObject::createNestedObject()") { SECTION("createNestedObject()") {
unsigned char key[] = "hello"; unsigned char key[] = "hello";
DynamicJsonDocument doc; DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>(); JsonObject& obj = doc.to<JsonObject>();
obj.createNestedObject(key); obj.createNestedObject(key);
} }
}
SECTION("JsonArray::add()") { SECTION("JsonObjectSubscript") {
SECTION("operator=") { // issue #416
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = value;
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"]);
}
}
SECTION("JsonArray") {
SECTION("add()") {
unsigned char value[] = "world"; unsigned char value[] = "world";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -232,7 +237,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
SECTION("JsonArray::set()") { SECTION("set()") {
unsigned char value[] = "world"; unsigned char value[] = "world";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -242,8 +247,10 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
}
SECTION("JsonArraySubscript::set()") { SECTION("JsonArraySubscript") {
SECTION("set()") {
unsigned char value[] = "world"; unsigned char value[] = "world";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -254,7 +261,7 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
SECTION("JsonArraySubscript::operator=") { SECTION("operator=") {
unsigned char value[] = "world"; unsigned char value[] = "world";
DynamicJsonDocument doc; DynamicJsonDocument doc;
@ -265,3 +272,4 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
} }
}

View File

@ -17,40 +17,30 @@
#ifndef VLA_NOT_SUPPORTED #ifndef VLA_NOT_SUPPORTED
TEST_CASE("Variable Length Array") { TEST_CASE("Variable Length Array") {
SECTION("ParseArray") { SECTION("deserializeJson()") {
int i = 8; int i = 9;
char vla[i]; 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); JsonError err = deserializeJson(doc, vla);
REQUIRE(err == JsonError::Ok); REQUIRE(err == JsonError::Ok);
} }
SECTION("ParseObject") { SECTION("deserializeMsgPack()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "{\"a\":42}"); memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15);
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc; 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") { SECTION("JsonVariant") {
int i = 16; SECTION("constructor") {
char vla[i];
strcpy(vla, "42");
StaticJsonDocument<> variant;
deserializeJson(variant, vla);
REQUIRE(42 == variant.as<int>());
}
SECTION("JsonVariant_Constructor") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "42"); strcpy(vla, "42");
@ -60,7 +50,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(42 == variant.as<int>()); REQUIRE(42 == variant.as<int>());
} }
SECTION("JsonVariant_Assign") { SECTION("operator=") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "42"); strcpy(vla, "42");
@ -72,7 +62,7 @@ TEST_CASE("Variable Length Array") {
} }
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant_Subscript") { SECTION("operator[]") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -86,7 +76,7 @@ TEST_CASE("Variable Length Array") {
#endif #endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant_Subscript_Const") { SECTION("operator[] const") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -99,7 +89,7 @@ TEST_CASE("Variable Length Array") {
} }
#endif #endif
SECTION("JsonVariant_Equals") { SECTION("operator==") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -113,7 +103,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE_FALSE((variant != vla)); REQUIRE_FALSE((variant != vla));
} }
SECTION("JsonVariant_Differs") { SECTION("operator!=") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -126,9 +116,11 @@ TEST_CASE("Variable Length Array") {
REQUIRE_FALSE((vla == variant)); REQUIRE_FALSE((vla == variant));
REQUIRE_FALSE((variant == vla)); REQUIRE_FALSE((variant == vla));
} }
}
SECTION("JsonObject") {
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject_Subscript") { SECTION("operator[]") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -141,32 +133,8 @@ TEST_CASE("Variable Length Array") {
} }
#endif #endif
SECTION("JsonObject_Subscript_Assign") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = vla;
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("JsonObject_Subscript_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 #ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject_Subscript_Const") { SECTION("operator[] const") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -179,7 +147,7 @@ TEST_CASE("Variable Length Array") {
} }
#endif #endif
SECTION("JsonObject_Get") { SECTION("get()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -191,7 +159,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == obj.get<char*>(vla)); REQUIRE(std::string("world") == obj.get<char*>(vla));
} }
SECTION("JsonObject_Set_Key") { SECTION("set() key") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -203,7 +171,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == obj["hello"]); REQUIRE(std::string("world") == obj["hello"]);
} }
SECTION("JsonObject_Set_Value") { SECTION("set() value") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "world"); strcpy(vla, "world");
@ -215,7 +183,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == obj["hello"]); REQUIRE(std::string("world") == obj["hello"]);
} }
SECTION("JsonObject_Set_KeyAndValue") { SECTION("set() key&value") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "world"); strcpy(vla, "world");
@ -227,7 +195,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == obj["world"]); REQUIRE(std::string("world") == obj["world"]);
} }
SECTION("JsonObject_ContainsKey") { SECTION("containsKey()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -239,7 +207,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(true == obj.containsKey(vla)); REQUIRE(true == obj.containsKey(vla));
} }
SECTION("JsonObject_Remove") { SECTION("remove()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -252,7 +220,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(0 == obj.size()); REQUIRE(0 == obj.size());
} }
SECTION("JsonObject_Is") { SECTION("is<T>()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -264,7 +232,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(true == obj.is<int>(vla)); REQUIRE(true == obj.is<int>(vla));
} }
SECTION("JsonObject_CreateNestedArray") { SECTION("createNestedArray()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -274,7 +242,7 @@ TEST_CASE("Variable Length Array") {
obj.createNestedArray(vla); obj.createNestedArray(vla);
} }
SECTION("JsonObject_CreateNestedObject") { SECTION("createNestedObject()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "hello"); strcpy(vla, "hello");
@ -283,8 +251,36 @@ TEST_CASE("Variable Length Array") {
JsonObject& obj = doc.to<JsonObject>(); JsonObject& obj = doc.to<JsonObject>();
obj.createNestedObject(vla); obj.createNestedObject(vla);
} }
}
SECTION("JsonArray_Add") { SECTION("JsonObjectSubscript") {
SECTION("operator=") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = vla;
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*>());
}
}
SECTION("JsonArray") {
SECTION("add()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "world"); strcpy(vla, "world");
@ -296,7 +292,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
SECTION("JsonArray_Set") { SECTION("set()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "world"); strcpy(vla, "world");
@ -308,8 +304,10 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
}
SECTION("JsonArraySubscript_Set") { SECTION("JsonArraySubscript") {
SECTION("set()") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "world"); strcpy(vla, "world");
@ -322,7 +320,7 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
SECTION("JsonArraySubscript_Assign") { SECTION("operator=") {
int i = 16; int i = 16;
char vla[i]; char vla[i];
strcpy(vla, "world"); strcpy(vla, "world");
@ -335,4 +333,5 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == arr[0]); REQUIRE(std::string("world") == arr[0]);
} }
} }
}
#endif #endif

View File

@ -3,13 +3,17 @@
# MIT License # MIT License
add_executable(MsgPackTests add_executable(MsgPackTests
deserializationErrors.cpp MsgPackError.cpp
deserializeArray.cpp deserializeArray.cpp
deserializeObject.cpp deserializeObject.cpp
deserializeVariant.cpp
deserializeStaticVariant.cpp deserializeStaticVariant.cpp
deserializeVariant.cpp
doubleToFloat.cpp doubleToFloat.cpp
MsgPackError.cpp incompleteInput.cpp
nestingLimit.cpp
notSupported.cpp
std_string.cpp
std_istream.cpp
) )
target_link_libraries(MsgPackTests catch) target_link_libraries(MsgPackTests catch)

View File

@ -25,6 +25,7 @@ TEST_CASE("MsgPackError") {
TEST_STRINGIFICATION(NotSupported); TEST_STRINGIFICATION(NotSupported);
TEST_STRINGIFICATION(NoMemory); TEST_STRINGIFICATION(NoMemory);
TEST_STRINGIFICATION(TooDeep); TEST_STRINGIFICATION(TooDeep);
TEST_STRINGIFICATION(IncompleteInput);
} }
SECTION("as boolean") { SECTION("as boolean") {
@ -32,6 +33,7 @@ TEST_CASE("MsgPackError") {
TEST_BOOLIFICATION(NotSupported, true); TEST_BOOLIFICATION(NotSupported, true);
TEST_BOOLIFICATION(NoMemory, true); TEST_BOOLIFICATION(NoMemory, true);
TEST_BOOLIFICATION(TooDeep, true); TEST_BOOLIFICATION(TooDeep, true);
TEST_BOOLIFICATION(IncompleteInput, true);
} }
SECTION("ostream") { SECTION("ostream") {

View File

@ -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); // [[]]
}
}

View 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);
}
}

View 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); // [[]]
}
}

View 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");
}
}

View 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);
}
}

View 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);
}
}