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:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env: SCRIPT=cmake GCC=5 SANITIZE=undefined
env: SCRIPT=cmake GCC=5 # SANITIZE=undefined
- compiler: gcc
addons:
apt:

View File

@ -12,6 +12,7 @@ HEAD
* Added `measureJson()` and `measureJsonPretty()`
* Added `deserializeMsgPack()` (issue #358)
* Added example `MsgPackParser.ino` (issue #358)
* Added support for non zero-terminated strings (issue #704)
* Removed `JsonBuffer::parseArray()`, `parseObject()` and `parse()`
* Removed `JsonBuffer::createArray()` and `createObject()`
* Removed `printTo()` and `prettyPrintTo()`

View File

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

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

View File

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

View File

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

View File

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

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>
struct CharPointerTraits {
class Reader {
const TChar* _ptr;
public:
Reader(const TChar* ptr)
: _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
void move() {
++_ptr;
}
char current() const {
return char(_ptr[0]);
}
char next() const {
return char(_ptr[1]);
}
};
static bool equals(const TChar* str, const char* expected) {
return strcmp(reinterpret_cast<const char*>(str), expected) == 0;
}

View File

@ -10,26 +10,6 @@ namespace ArduinoJson {
namespace Internals {
template <>
struct StringTraits<const __FlashStringHelper*, void> {
class Reader {
const char* _ptr;
public:
Reader(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {}
void move() {
_ptr++;
}
char current() const {
return pgm_read_byte_near(_ptr);
}
char next() const {
return pgm_read_byte_near(_ptr + 1);
}
};
static bool equals(const __FlashStringHelper* str, const char* expected) {
return strcmp_P(expected, (const char*)str) == 0;
}

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();
}
struct Reader : CharPointerTraits<char>::Reader {
Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
};
static bool equals(const TString& str, const char* expected) {
return 0 == strcmp(str.c_str(), expected);
}

View File

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

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

View File

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

View File

@ -12,6 +12,7 @@ add_executable(JsonArrayTests
remove.cpp
set.cpp
size.cpp
std_string.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
JsonError.cpp
nestingLimit.cpp
std_istream.cpp
std_string.cpp
)
target_link_libraries(JsonDeserializerTests catch)

View File

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

View File

@ -164,13 +164,13 @@ TEST_CASE("deserialize JSON array") {
SECTION("Closing single quotes missing") {
JsonError err = deserializeJson(doc, "[\"]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Closing double quotes missing") {
JsonError err = deserializeJson(doc, "[\']");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
}
@ -233,21 +233,21 @@ TEST_CASE("deserialize JSON array") {
SECTION("/*/") {
JsonError err = deserializeJson(doc, "[/*/\n]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Unfinished comment") {
JsonError err = deserializeJson(doc, "[/*COMMENT]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Final slash missing") {
JsonError err = deserializeJson(doc, "[/*COMMENT*]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Line comments") {
SECTION("Trailing comments") {
SECTION("Before opening bracket") {
JsonError err = deserializeJson(doc, "//COMMENT\n\t[\"hello\"]");
JsonArray& arr = doc.as<JsonArray>();
@ -311,39 +311,53 @@ TEST_CASE("deserialize JSON array") {
SECTION("End document with comment") {
JsonError err = deserializeJson(doc, "[//COMMENT");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Premature null-terminator") {
SECTION("After opening bracket") {
JsonError err = deserializeJson(doc, "[");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After value") {
JsonError err = deserializeJson(doc, "[1");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After comma") {
JsonError err = deserializeJson(doc, "[1,");
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Premature end of input") {
const char* input = "[1,2]";
SECTION("After opening bracket") {
JsonError err = deserializeJson(doc, input, 1);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After value") {
JsonError err = deserializeJson(doc, input, 2);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After comma") {
JsonError err = deserializeJson(doc, input, 3);
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Misc") {
SECTION("Garbage") {
JsonError err = deserializeJson(doc, "%*$£¤");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("The opening bracket is missing") {
JsonError err = deserializeJson(doc, "]");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("The closing bracket is missing") {
JsonError err = deserializeJson(doc, "[");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Escape sequences") {
JsonError err =
deserializeJson(doc, "[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]");
JsonArray& arr = doc.as<JsonArray>();
REQUIRE(err == JsonError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(arr[0] == "1\"2\\3/4\b5\f6\n7\r8\t9");
}
SECTION("Nested objects") {
char jsonString[] =
" [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] ";

View File

@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok);
REQUIRE(err == JsonError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithOneValue") {
@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok);
REQUIRE(err == JsonError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithNestedObject") {
@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
REQUIRE(err == JsonError::Ok);
}
SECTION("CharPtrNull") {
StaticJsonDocument<100> doc;
JsonError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err != JsonError::Ok);
}
SECTION("ConstCharPtrNull") {
StaticJsonDocument<100> doc;
JsonError err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err != JsonError::Ok);
}
SECTION("CopyStringNotSpaces") {
StaticJsonDocument<100> doc;

View File

@ -212,19 +212,39 @@ TEST_CASE("deserialize JSON object") {
}
}
SECTION("Misc") {
SECTION("The opening brace is missing") {
JsonError err = deserializeJson(doc, "}");
SECTION("Premature null terminator") {
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("The closing brace is missing") {
SECTION("After key") {
JsonError err = deserializeJson(doc, "{\"hello\"");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\":");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After value") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After comma") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\",");
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Misc") {
SECTION("A quoted key without value") {
JsonError err = deserializeJson(doc, "{\"key\"}");
@ -250,6 +270,200 @@ TEST_CASE("deserialize JSON object") {
}
}
SECTION("Block comments") {
SECTION("Before opening brace") {
JsonError err = deserializeJson(doc, "/*COMMENT*/ {\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{/*COMMENT*/\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before colon") {
JsonError err = deserializeJson(doc, "{\"hello\"/*COMMENT*/:\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\":/*COMMENT*/\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"/*COMMENT*/}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}/*COMMENT*/");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\"/*COMMENT*/,\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
SECTION("After comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\",/*COMMENT*/\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
}
SECTION("Trailing comments") {
SECTION("Before opening brace") {
JsonError err = deserializeJson(doc, "//COMMENT\n {\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{//COMMENT\n\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before colon") {
JsonError err = deserializeJson(doc, "{\"hello\"//COMMENT\n:\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\"://COMMENT\n\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"//COMMENT\n}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}//COMMENT\n");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\"//COMMENT\n,\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
SECTION("After comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\",//COMMENT\n\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
}
SECTION("Dangling slash") {
SECTION("Before opening brace") {
JsonError err = deserializeJson(doc, "/{\"hello\":\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{/\"hello\":\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Before colon") {
JsonError err = deserializeJson(doc, "{\"hello\"/:\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\":/\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Before closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"/}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}/");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before comma") {
JsonError err =
deserializeJson(doc, "{\"hello\":\"world\"/,\"answer\":42}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After comma") {
JsonError err =
deserializeJson(doc, "{\"hello\":\"world\",/\"answer\":42}");
REQUIRE(err == JsonError::InvalidInput);
}
}
SECTION("Should clear the JsonObject") {
deserializeJson(doc, "{\"hello\":\"world\"}");
deserializeJson(doc, "{}");

View File

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

View File

@ -10,18 +10,16 @@ using namespace Catch::Matchers;
TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
DynamicJsonDocument doc;
SECTION("EmptyObject") {
JsonError err = deserializeJson(doc, "{}");
SECTION("null char*") {
JsonError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.is<JsonObject>());
REQUIRE(err != JsonError::Ok);
}
SECTION("EmptyArray") {
JsonError err = deserializeJson(doc, "[]");
SECTION("null const char*") {
JsonError err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.is<JsonArray>());
REQUIRE(err != JsonError::Ok);
}
SECTION("Integer") {
@ -58,6 +56,14 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE_THAT(doc.as<char*>(), Equals("hello world"));
}
SECTION("Escape sequences") {
JsonError err =
deserializeJson(doc, "\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.as<std::string>() == "1\"2\\3/4\b5\f6\n7\r8\t9");
}
SECTION("True") {
JsonError err = deserializeJson(doc, "true");
@ -74,25 +80,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.as<bool>() == false);
}
SECTION("OpenBrace") {
JsonError err = deserializeJson(doc, "{");
REQUIRE(err != JsonError::Ok);
}
SECTION("Incomplete string") {
JsonError err = deserializeJson(doc, "\"hello");
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.is<char*>());
REQUIRE_THAT(doc.as<char*>(), Equals("hello"));
}
SECTION("Unterminated escape sequence") {
JsonError err = deserializeJson(doc, "\"\\\0\"");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Should clear the JsonVariant") {
deserializeJson(doc, "[1,2,3]");
deserializeJson(doc, "{}");
@ -100,4 +87,86 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0));
}
SECTION("Empty input") {
JsonError err = deserializeJson(doc, "");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Just a trailing comment") {
JsonError err = deserializeJson(doc, "// comment");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Just a block comment") {
JsonError err = deserializeJson(doc, "/*comment*/");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Just a slash") {
JsonError err = deserializeJson(doc, "/");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Garbage") {
JsonError err = deserializeJson(doc, "%*$£¤");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Premature null-terminator") {
SECTION("In escape sequence") {
JsonError err = deserializeJson(doc, "\"\\");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In block comment") {
JsonError err = deserializeJson(doc, "/* comment");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In double quoted string") {
JsonError err = deserializeJson(doc, "\"hello");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In single quoted string") {
JsonError err = deserializeJson(doc, "'hello");
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Premature end of input") {
SECTION("In escape sequence") {
JsonError err = deserializeJson(doc, "\"\\n\"", 2);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In block comment") {
JsonError err = deserializeJson(doc, "/* comment */", 10);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In double quoted string") {
JsonError err = deserializeJson(doc, "\"hello\"", 6);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In single quoted string") {
JsonError err = deserializeJson(doc, "'hello'", 6);
REQUIRE(err == JsonError::IncompleteInput);
}
}
}

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
set.cpp
size.cpp
std_string.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
JsonObjectPretty.cpp
JsonVariant.cpp
std_stream.cpp
std_string.cpp
)
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
FloatParts.cpp
std_stream.cpp
std_string.cpp
StringBuilder.cpp
StringTraits.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,259 +9,267 @@
#define CONFLICTS_WITH_BUILTIN_OPERATOR
#endif
TEST_CASE("unsigned char string") {
SECTION("JsonBuffer::parseArray") {
unsigned char json[] = "[42]";
StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc;
JsonError err = deserializeJson(doc, json);
REQUIRE(err == JsonError::Ok);
}
SECTION("JsonBuffer::parseObject") {
unsigned char json[] = "{\"a\":42}";
TEST_CASE("unsigned char[]") {
SECTION("deserializeJson()") {
unsigned char input[] = "{\"a\":42}";
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
JsonError err = deserializeJson(doc, json);
JsonError err = deserializeJson(doc, input);
REQUIRE(err == JsonError::Ok);
}
SECTION("JsonVariant constructor") {
unsigned char value[] = "42";
SECTION("deserializeMsgPack()") {
unsigned char input[] = "\xDE\x00\x01\xA5Hello\xA5world";
JsonVariant variant(value);
StaticJsonDocument<JSON_OBJECT_SIZE(2)> doc;
MsgPackError err = deserializeMsgPack(doc, input);
REQUIRE(42 == variant.as<int>());
REQUIRE(err == MsgPackError::Ok);
}
SECTION("JsonVariant assignment operator") {
unsigned char value[] = "42";
SECTION("JsonVariant") {
SECTION("constructor") {
unsigned char value[] = "42";
JsonVariant variant(666);
variant = value;
JsonVariant variant(value);
REQUIRE(42 == variant.as<int>());
}
REQUIRE(42 == variant.as<int>());
}
SECTION("operator=") {
unsigned char value[] = "42";
JsonVariant variant(666);
variant = value;
REQUIRE(42 == variant.as<int>());
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant::operator[]") {
unsigned char key[] = "hello";
SECTION("operator[]") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[key]);
}
REQUIRE(std::string("world") == variant[key]);
}
#endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant::operator[] const") {
unsigned char key[] = "hello";
SECTION("operator[] const") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[key]);
}
REQUIRE(std::string("world") == variant[key]);
}
#endif
SECTION("JsonVariant::operator==") {
unsigned char comparand[] = "hello";
SECTION("operator==") {
unsigned char comparand[] = "hello";
JsonVariant variant;
variant = "hello";
JsonVariant variant;
variant = "hello";
REQUIRE(comparand == variant);
REQUIRE(variant == comparand);
REQUIRE_FALSE(comparand != variant);
REQUIRE_FALSE(variant != comparand);
}
SECTION("JsonVariant::operator!=") {
unsigned char comparand[] = "hello";
JsonVariant variant;
variant = "world";
REQUIRE(comparand != variant);
REQUIRE(variant != comparand);
REQUIRE_FALSE(comparand == variant);
REQUIRE_FALSE(variant == comparand);
REQUIRE(comparand == variant);
REQUIRE(variant == comparand);
REQUIRE_FALSE(comparand != variant);
REQUIRE_FALSE(variant != comparand);
}
SECTION("operator!=") {
unsigned char comparand[] = "hello";
JsonVariant variant;
variant = "world";
REQUIRE(comparand != variant);
REQUIRE(variant != comparand);
REQUIRE_FALSE(comparand == variant);
REQUIRE_FALSE(variant == comparand);
}
}
SECTION("JsonObject") {
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject::operator[]") {
unsigned char key[] = "hello";
SECTION("operator[]") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj[key] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj[key] = "world";
REQUIRE(std::string("world") == obj["hello"]);
}
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("JsonObject::operator[] const") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[key]);
}
#endif
SECTION("JsonObjectSubscript::operator=") { // issue #416
unsigned char value[] = "world";
SECTION("get()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = value;
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj.get<char*>(key));
}
REQUIRE(std::string("world") == obj["hello"]);
SECTION("set() key") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(key, "world");
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set() value") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set("hello", value);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set() key&value") {
unsigned char key[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(key, key);
REQUIRE(std::string("world") == obj["world"]);
}
SECTION("containsKey()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.containsKey(key));
}
SECTION("remove()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
obj.remove(key);
REQUIRE(0 == obj.size());
}
SECTION("is()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.is<int>(key));
}
SECTION("createNestedArray()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedArray(key);
}
SECTION("createNestedObject()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedObject(key);
}
}
SECTION("JsonObjectSubscript::set()") {
unsigned char value[] = "world";
SECTION("JsonObjectSubscript") {
SECTION("operator=") { // issue #416
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"].set(value);
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = value;
REQUIRE(std::string("world") == obj["hello"]);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"].set(value);
REQUIRE(std::string("world") == obj["hello"]);
}
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject::operator[] const") {
unsigned char key[] = "hello";
SECTION("JsonArray") {
SECTION("add()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add(value);
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[key]);
}
#endif
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonObject::get()") {
unsigned char key[] = "hello";
SECTION("set()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj.get<char*>(key));
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr.set(0, value);
REQUIRE(std::string("world") == arr[0]);
}
}
SECTION("JsonObject::set() key") {
unsigned char key[] = "hello";
SECTION("JsonArraySubscript") {
SECTION("set()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(key, "world");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0].set(value);
REQUIRE(std::string("world") == obj["hello"]);
}
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonObject::set() value") {
unsigned char value[] = "world";
SECTION("operator=") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set("hello", value);
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0] = value;
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("JsonObject::set key&value") {
unsigned char key[] = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(key, key);
REQUIRE(std::string("world") == obj["world"]);
}
SECTION("JsonObject::containsKey()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.containsKey(key));
}
SECTION("JsonObject::remove()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
obj.remove(key);
REQUIRE(0 == obj.size());
}
SECTION("JsonObject::is()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.is<int>(key));
}
SECTION("JsonObject::createNestedArray()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedArray(key);
}
SECTION("JsonObject::createNestedObject()") {
unsigned char key[] = "hello";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedObject(key);
}
SECTION("JsonArray::add()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add(value);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonArray::set()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr.set(0, value);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonArraySubscript::set()") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0].set(value);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonArraySubscript::operator=") {
unsigned char value[] = "world";
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0] = value;
REQUIRE(std::string("world") == arr[0]);
REQUIRE(std::string("world") == arr[0]);
}
}
}

View File

@ -17,322 +17,321 @@
#ifndef VLA_NOT_SUPPORTED
TEST_CASE("Variable Length Array") {
SECTION("ParseArray") {
int i = 8;
SECTION("deserializeJson()") {
int i = 9;
char vla[i];
strcpy(vla, "[42]");
strcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc;
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
JsonError err = deserializeJson(doc, vla);
REQUIRE(err == JsonError::Ok);
}
SECTION("ParseObject") {
SECTION("deserializeMsgPack()") {
int i = 16;
char vla[i];
strcpy(vla, "{\"a\":42}");
memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15);
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
JsonError error = deserializeJson(doc, vla);
MsgPackError err = deserializeMsgPack(doc, vla);
REQUIRE(error == JsonError::Ok);
REQUIRE(err == MsgPackError::Ok);
}
SECTION("Parse") {
int i = 16;
char vla[i];
strcpy(vla, "42");
SECTION("JsonVariant") {
SECTION("constructor") {
int i = 16;
char vla[i];
strcpy(vla, "42");
StaticJsonDocument<> variant;
deserializeJson(variant, vla);
JsonVariant variant(vla);
REQUIRE(42 == variant.as<int>());
}
REQUIRE(42 == variant.as<int>());
}
SECTION("JsonVariant_Constructor") {
int i = 16;
char vla[i];
strcpy(vla, "42");
SECTION("operator=") {
int i = 16;
char vla[i];
strcpy(vla, "42");
JsonVariant variant(vla);
JsonVariant variant(666);
variant = vla;
REQUIRE(42 == variant.as<int>());
}
SECTION("JsonVariant_Assign") {
int i = 16;
char vla[i];
strcpy(vla, "42");
JsonVariant variant(666);
variant = vla;
REQUIRE(42 == variant.as<int>());
}
REQUIRE(42 == variant.as<int>());
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant_Subscript") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("operator[]") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
}
REQUIRE(std::string("world") == variant[vla]);
}
#endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonVariant_Subscript_Const") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("operator[] const") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(std::string("world") == variant[vla]);
}
REQUIRE(std::string("world") == variant[vla]);
}
#endif
SECTION("JsonVariant_Equals") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("operator==") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
JsonVariant variant;
variant = "hello";
JsonVariant variant;
variant = "hello";
REQUIRE((vla == variant));
REQUIRE((variant == vla));
REQUIRE_FALSE((vla != variant));
REQUIRE_FALSE((variant != vla));
REQUIRE((vla == variant));
REQUIRE((variant == vla));
REQUIRE_FALSE((vla != variant));
REQUIRE_FALSE((variant != vla));
}
SECTION("operator!=") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
JsonVariant variant;
variant = "world";
REQUIRE((vla != variant));
REQUIRE((variant != vla));
REQUIRE_FALSE((vla == variant));
REQUIRE_FALSE((variant == vla));
}
}
SECTION("JsonVariant_Differs") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("JsonObject") {
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("operator[]") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
JsonVariant variant;
variant = "world";
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj[vla] = "world";
REQUIRE((vla != variant));
REQUIRE((variant != vla));
REQUIRE_FALSE((vla == variant));
REQUIRE_FALSE((variant == vla));
}
REQUIRE(std::string("world") == obj["hello"]);
}
#endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject_Subscript") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("operator[] const") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj[vla] = "world";
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
REQUIRE(std::string("world") == obj["hello"]);
}
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[vla]);
}
#endif
SECTION("JsonObject_Subscript_Assign") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
SECTION("get()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = vla;
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
REQUIRE(std::string("world") == obj["hello"].as<char*>());
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj.get<char*>(vla));
}
SECTION("set() key") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(vla, "world");
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set() value") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set("hello", vla);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("set() key&value") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(vla, vla);
REQUIRE(std::string("world") == obj["world"]);
}
SECTION("containsKey()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.containsKey(vla));
}
SECTION("remove()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
obj.remove(vla);
REQUIRE(0 == obj.size());
}
SECTION("is<T>()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.is<int>(vla));
}
SECTION("createNestedArray()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedArray(vla);
}
SECTION("createNestedObject()") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedObject(vla);
}
}
SECTION("JsonObject_Subscript_Set") {
int i = 32;
char vla[i];
strcpy(vla, "world");
SECTION("JsonObjectSubscript") {
SECTION("operator=") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"].set(vla);
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"] = vla;
REQUIRE(std::string("world") == obj["hello"].as<char*>());
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("set()") {
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj["hello"].set(vla);
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
SECTION("JsonObject_Subscript_Const") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("JsonArray") {
SECTION("add()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add(vla);
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[vla]);
}
#endif
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonObject_Get") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr.set(0, vla);
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj.get<char*>(vla));
REQUIRE(std::string("world") == arr[0]);
}
}
SECTION("JsonObject_Set_Key") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
SECTION("JsonArraySubscript") {
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(vla, "world");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0].set(vla);
REQUIRE(std::string("world") == obj["hello"]);
}
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonObject_Set_Value") {
int i = 16;
char vla[i];
strcpy(vla, "world");
SECTION("operator=") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set("hello", vla);
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0] = vla;
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("JsonObject_Set_KeyAndValue") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.set(vla, vla);
REQUIRE(std::string("world") == obj["world"]);
}
SECTION("JsonObject_ContainsKey") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.containsKey(vla));
}
SECTION("JsonObject_Remove") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
obj.remove(vla);
REQUIRE(0 == obj.size());
}
SECTION("JsonObject_Is") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
deserializeJson(doc, "{\"hello\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(true == obj.is<int>(vla));
}
SECTION("JsonObject_CreateNestedArray") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedArray(vla);
}
SECTION("JsonObject_CreateNestedObject") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonDocument doc;
JsonObject& obj = doc.to<JsonObject>();
obj.createNestedObject(vla);
}
SECTION("JsonArray_Add") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add(vla);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonArray_Set") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr.set(0, vla);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonArraySubscript_Set") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0].set(vla);
REQUIRE(std::string("world") == arr[0]);
}
SECTION("JsonArraySubscript_Assign") {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonDocument doc;
JsonArray& arr = doc.to<JsonArray>();
arr.add("hello");
arr[0] = vla;
REQUIRE(std::string("world") == arr[0]);
REQUIRE(std::string("world") == arr[0]);
}
}
}
#endif

View File

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

View File

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

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