mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-27 01:07:30 +02:00
Compare commits
9 Commits
v6.2.2-bet
...
v6.3.0-bet
Author | SHA1 | Date | |
---|---|---|---|
2ec9569b36 | |||
58303d0837 | |||
e3639918eb | |||
6d290bd001 | |||
7683667b3c | |||
9cbc891816 | |||
0454bd1ef6 | |||
f139100b23 | |||
3f666bd5f0 |
68
CHANGELOG.md
68
CHANGELOG.md
@ -1,18 +1,74 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v6.2.2-beta
|
||||
v6.3.0-beta (2018-08-31)
|
||||
-----------
|
||||
|
||||
* Implemented reference semantics for `JsonVariant`
|
||||
* Replace `JsonPair`'s `key` and `value` with `key()` and `value()`
|
||||
* Fixed `serializeJson(obj[key], dst)` (issue #794)
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> #### JsonVariant
|
||||
>
|
||||
> `JsonVariant` now has a semantic similar to `JsonObject` and `JsonArray`.
|
||||
> It's a reference to a value stored in the `JsonDocument`.
|
||||
> As a consequence, a `JsonVariant` cannot be used as a standalone variable anymore.
|
||||
>
|
||||
> Old code:
|
||||
>
|
||||
> ```c++
|
||||
> JsonVariant myValue = 42;
|
||||
> ```
|
||||
>
|
||||
> New code:
|
||||
>
|
||||
> ```c++
|
||||
> DynamicJsonDocument doc;
|
||||
> JsonVariant myValue = doc.to<JsonVariant>();
|
||||
> myValue.set(42);
|
||||
> ```
|
||||
>
|
||||
> #### JsonPair
|
||||
>
|
||||
> Old code:
|
||||
>
|
||||
> ```c++
|
||||
> for(JsonPair p : myObject) {
|
||||
> Serial.println(p.key);
|
||||
> Serial.println(p.value.as<int>());
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> New code:
|
||||
>
|
||||
> ```c++
|
||||
> for(JsonPair p : myObject) {
|
||||
> Serial.println(p.key());
|
||||
> Serial.println(p.value().as<int>());
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> CAUTION: the key is now read only!
|
||||
|
||||
v6.2.3-beta (2018-07-19)
|
||||
-----------
|
||||
|
||||
* Fixed exception when using Flash strings as object keys (issue #784)
|
||||
|
||||
v6.2.2-beta (2018-07-18)
|
||||
-----------
|
||||
|
||||
* Fixed `invalid application of 'sizeof' to incomplete type '__FlashStringHelper'` (issue #783)
|
||||
* Fixed `char[]` not duplicated when passed to `JsonVariant::operator[]`
|
||||
|
||||
v6.2.1-beta
|
||||
v6.2.1-beta (2018-07-17)
|
||||
-----------
|
||||
|
||||
* Fixed `JsonObject` not inserting keys of type `String` (issue #782)
|
||||
|
||||
v6.2.0-beta
|
||||
v6.2.0-beta (2018-07-12)
|
||||
-----------
|
||||
|
||||
* Disabled lazy number deserialization (issue #772)
|
||||
@ -41,7 +97,7 @@ v6.2.0-beta
|
||||
> object["values"] = serialized("[1,2,3,4]");
|
||||
> ```
|
||||
|
||||
v6.1.0-beta
|
||||
v6.1.0-beta (2018-07-02)
|
||||
-----------
|
||||
|
||||
* Return `JsonArray` and `JsonObject` by value instead of reference (issue #309)
|
||||
@ -71,12 +127,12 @@ v6.1.0-beta
|
||||
> }
|
||||
> ```
|
||||
|
||||
v6.0.1-beta
|
||||
v6.0.1-beta (2018-06-11)
|
||||
-----------
|
||||
|
||||
* Fixed conflicts with `isnan()` and `isinf()` macros (issue #752)
|
||||
|
||||
v6.0.0-beta
|
||||
v6.0.0-beta (2018-06-07)
|
||||
-----------
|
||||
|
||||
* Added `DynamicJsonDocument` and `StaticJsonDocument`
|
||||
|
@ -7,7 +7,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||
},
|
||||
"version": "6.2.2-beta",
|
||||
"version": "6.3.0-beta",
|
||||
"authors": {
|
||||
"name": "Benoit Blanchon",
|
||||
"url": "https://blog.benoitblanchon.fr"
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ArduinoJson
|
||||
version=6.2.2-beta
|
||||
version=6.3.0-beta
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=An efficient and elegant JSON library for Arduino.
|
||||
|
44
scripts/publish.sh
Normal file
44
scripts/publish.sh
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
VERSION="$1"
|
||||
DATE=$(date +%F)
|
||||
TAG="v$VERSION"
|
||||
|
||||
update_version_in_source () {
|
||||
IFS=".-" read MAJOR MINOR REVISION EXTRA < <(echo "$VERSION")
|
||||
UNDERLINE=$(printf -- '-%.0s' $(seq 1 ${#TAG}))
|
||||
|
||||
sed -i~ -bE "4s/HEAD/$TAG ($DATE)/; 5s/-+/$UNDERLINE/" CHANGELOG.md
|
||||
rm CHANGELOG.md*~
|
||||
sed -i~ -bE "s/\"version\":.*$/\"version\": \"$VERSION\",/" library.json
|
||||
rm library.json*~
|
||||
|
||||
sed -i~ -bE "s/version=.*$/version=$VERSION/" library.properties
|
||||
rm library.properties*~
|
||||
|
||||
sed -i~ -bE \
|
||||
-e "s/ARDUINOJSON_VERSION .*$/ARDUINOJSON_VERSION \"$VERSION\"/" \
|
||||
-e "s/ARDUINOJSON_VERSION_MAJOR .*$/ARDUINOJSON_VERSION_MAJOR $MAJOR/" \
|
||||
-e "s/ARDUINOJSON_VERSION_MINOR .*$/ARDUINOJSON_VERSION_MINOR $MINOR/" \
|
||||
-e "s/ARDUINOJSON_VERSION_REVISION .*$/ARDUINOJSON_VERSION_REVISION $REVISION/" \
|
||||
src/ArduinoJson/version.hpp
|
||||
rm src/ArduinoJson/version.hpp*~
|
||||
}
|
||||
|
||||
commit_new_version () {
|
||||
git add src/ArduinoJson/version.hpp CHANGELOG.md library.json library.properties
|
||||
git commit -m "Set version to $VERSION"
|
||||
}
|
||||
|
||||
add_tag () {
|
||||
CHANGES=$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' CHANGELOG.md)
|
||||
git tag -m "ArduinoJson $VERSION\n$CHANGES" $TAG
|
||||
}
|
||||
|
||||
update_version_in_source
|
||||
commit_new_version
|
||||
add_tag
|
@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h> // size_t
|
||||
|
||||
#include "JsonFloat.hpp"
|
||||
#include "JsonInteger.hpp"
|
||||
|
||||
|
181
src/ArduinoJson/Data/JsonVariantData.hpp
Normal file
181
src/ArduinoJson/Data/JsonVariantData.hpp
Normal file
@ -0,0 +1,181 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Numbers/parseFloat.hpp"
|
||||
#include "../Numbers/parseInteger.hpp"
|
||||
#include "JsonVariantContent.hpp"
|
||||
#include "JsonVariantType.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
struct JsonVariantData {
|
||||
JsonVariantType type;
|
||||
JsonVariantContent content;
|
||||
|
||||
void setBoolean(bool value) {
|
||||
type = JSON_BOOLEAN;
|
||||
content.asInteger = static_cast<JsonUInt>(value);
|
||||
}
|
||||
|
||||
void setFloat(JsonFloat value) {
|
||||
type = JSON_FLOAT;
|
||||
content.asFloat = value;
|
||||
}
|
||||
|
||||
void setInteger(JsonInteger value) {
|
||||
if (value > 0)
|
||||
setPostiveInteger(static_cast<JsonUInt>(value));
|
||||
else
|
||||
setNegativeInteger(static_cast<JsonUInt>(-value));
|
||||
}
|
||||
|
||||
void setNegativeInteger(JsonUInt value) {
|
||||
type = JSON_NEGATIVE_INTEGER;
|
||||
content.asInteger = value;
|
||||
}
|
||||
|
||||
void setPostiveInteger(JsonUInt value) {
|
||||
type = JSON_POSITIVE_INTEGER;
|
||||
content.asInteger = value;
|
||||
}
|
||||
|
||||
void setString(const char *value) {
|
||||
type = JSON_STRING;
|
||||
content.asString = value;
|
||||
}
|
||||
|
||||
void setRaw(const char *data, size_t size) {
|
||||
type = JSON_RAW;
|
||||
content.asRaw.data = data;
|
||||
content.asRaw.size = size;
|
||||
}
|
||||
|
||||
void setNull() {
|
||||
type = JSON_NULL;
|
||||
}
|
||||
|
||||
void setArray(JsonArrayData &array) {
|
||||
type = JSON_ARRAY;
|
||||
content.asArray = &array;
|
||||
}
|
||||
|
||||
void setObject(JsonObjectData &object) {
|
||||
type = JSON_OBJECT;
|
||||
content.asObject = &object;
|
||||
}
|
||||
|
||||
JsonArrayData *asArray() const {
|
||||
return type == JSON_ARRAY ? content.asArray : 0;
|
||||
}
|
||||
|
||||
JsonObjectData *asObject() const {
|
||||
return type == JSON_OBJECT ? content.asObject : 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T asInteger() const {
|
||||
switch (type) {
|
||||
case JSON_NULL:
|
||||
case JSON_RAW:
|
||||
return 0;
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
case JSON_BOOLEAN:
|
||||
return T(content.asInteger);
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return T(~content.asInteger + 1);
|
||||
case JSON_STRING:
|
||||
return parseInteger<T>(content.asString);
|
||||
default:
|
||||
return T(content.asFloat);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T asFloat() const {
|
||||
switch (type) {
|
||||
case JSON_NULL:
|
||||
case JSON_RAW:
|
||||
return 0;
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
case JSON_BOOLEAN:
|
||||
return static_cast<T>(content.asInteger);
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return -static_cast<T>(content.asInteger);
|
||||
case JSON_STRING:
|
||||
return parseFloat<T>(content.asString);
|
||||
default:
|
||||
return static_cast<T>(content.asFloat);
|
||||
}
|
||||
}
|
||||
|
||||
const char *asString() const {
|
||||
return type == JSON_STRING ? content.asString : NULL;
|
||||
}
|
||||
|
||||
bool isArray() const {
|
||||
return type == Internals::JSON_ARRAY;
|
||||
}
|
||||
|
||||
bool isBoolean() const {
|
||||
return type == JSON_BOOLEAN;
|
||||
}
|
||||
|
||||
bool isFloat() const {
|
||||
return type == JSON_FLOAT || type == JSON_POSITIVE_INTEGER ||
|
||||
type == JSON_NEGATIVE_INTEGER;
|
||||
}
|
||||
|
||||
bool isInteger() const {
|
||||
return type == JSON_POSITIVE_INTEGER || type == JSON_NEGATIVE_INTEGER;
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
return type == JSON_NULL;
|
||||
}
|
||||
|
||||
bool isObject() const {
|
||||
return type == Internals::JSON_OBJECT;
|
||||
}
|
||||
|
||||
bool isString() const {
|
||||
return type == Internals::JSON_STRING;
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor &visitor) const {
|
||||
switch (type) {
|
||||
case JSON_FLOAT:
|
||||
return visitor.acceptFloat(content.asFloat);
|
||||
|
||||
case JSON_ARRAY:
|
||||
return visitor.acceptArray(*content.asArray);
|
||||
|
||||
case JSON_OBJECT:
|
||||
return visitor.acceptObject(*content.asObject);
|
||||
|
||||
case JSON_STRING:
|
||||
return visitor.acceptString(content.asString);
|
||||
|
||||
case JSON_RAW:
|
||||
return visitor.acceptRawJson(content.asRaw.data, content.asRaw.size);
|
||||
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return visitor.acceptNegativeInteger(content.asInteger);
|
||||
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
return visitor.acceptPositiveInteger(content.asInteger);
|
||||
|
||||
case JSON_BOOLEAN:
|
||||
return visitor.acceptBoolean(content.asInteger != 0);
|
||||
|
||||
default:
|
||||
return visitor.acceptNull();
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
@ -1,23 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
template <typename T>
|
||||
struct JsonVariantDefault {
|
||||
static T get() {
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
|
||||
}
|
||||
}
|
@ -11,10 +11,10 @@ namespace Internals {
|
||||
// Enumerated type to know the current type of a JsonVariant.
|
||||
// The value determines which member of JsonVariantContent is used.
|
||||
enum JsonVariantType {
|
||||
JSON_UNDEFINED, // JsonVariant has not been initialized
|
||||
JSON_UNPARSED, // JsonVariant contains an unparsed string
|
||||
JSON_STRING, // JsonVariant stores a const char*
|
||||
JSON_BOOLEAN, // JsonVariant stores a bool
|
||||
JSON_NULL, // JsonVariant has not been initialized
|
||||
JSON_RAW, // JsonVariant contains a raw string that should not be escaped
|
||||
JSON_STRING, // JsonVariant stores a const char*
|
||||
JSON_BOOLEAN, // JsonVariant stores a bool
|
||||
JSON_POSITIVE_INTEGER, // JsonVariant stores an JsonUInt
|
||||
JSON_NEGATIVE_INTEGER, // JsonVariant stores an JsonUInt that must be negated
|
||||
JSON_ARRAY, // JsonVariant stores a pointer to a JsonArrayData
|
||||
|
@ -22,7 +22,7 @@ class List {
|
||||
typedef ListIterator<T> iterator;
|
||||
typedef ListConstIterator<T> const_iterator;
|
||||
|
||||
explicit List(JsonBuffer *buf) : _buffer(buf), _firstNode(NULL) {}
|
||||
List() : _firstNode(NULL) {}
|
||||
|
||||
// Returns the numbers of elements in the list.
|
||||
// For a JsonObjectData, it would return the number of key-value pairs
|
||||
@ -32,8 +32,8 @@ class List {
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
iterator add() {
|
||||
node_type *newNode = new (_buffer) node_type();
|
||||
iterator add(JsonBuffer *buffer) {
|
||||
node_type *newNode = new (buffer) node_type();
|
||||
|
||||
if (_firstNode) {
|
||||
node_type *lastNode = _firstNode;
|
||||
@ -71,11 +71,6 @@ class List {
|
||||
}
|
||||
}
|
||||
|
||||
JsonBuffer &buffer() const {
|
||||
return *_buffer;
|
||||
}
|
||||
JsonBuffer *_buffer; // TODO!!
|
||||
|
||||
protected:
|
||||
void clear() {
|
||||
_firstNode = 0;
|
||||
|
@ -15,7 +15,7 @@ namespace Internals {
|
||||
// Used by List<T> and its iterators.
|
||||
template <typename T>
|
||||
struct ListNode : public Internals::JsonBufferAllocated {
|
||||
ListNode() throw() : next(NULL) {}
|
||||
ListNode() NOEXCEPT : next(NULL) {}
|
||||
|
||||
ListNode<T> *next;
|
||||
T content;
|
||||
|
@ -1,53 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../JsonVariant.hpp"
|
||||
#include "../Memory/JsonBuffer.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "../Strings/StringTypes.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
template <typename Source, typename Enable = void>
|
||||
struct ValueSaver {
|
||||
template <typename Destination>
|
||||
static bool save(JsonBuffer*, Destination& destination, Source source) {
|
||||
destination = source;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// We duplicate all strings except const char*
|
||||
template <typename TString>
|
||||
struct ValueSaver<
|
||||
TString, typename enable_if<IsString<TString>::value &&
|
||||
!is_same<const char*, TString>::value>::type> {
|
||||
template <typename Destination>
|
||||
static bool save(JsonBuffer* buffer, Destination& dest, TString source) {
|
||||
const char* dup = makeString(source).save(buffer);
|
||||
if (!dup) return false;
|
||||
dest = dup;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// We duplicate all SerializedValue<T> except SerializedValue<const char*>
|
||||
template <typename TString>
|
||||
struct ValueSaver<
|
||||
const SerializedValue<TString>&,
|
||||
typename enable_if<!is_same<const char*, TString>::value>::type> {
|
||||
template <typename Destination>
|
||||
static bool save(JsonBuffer* buffer, Destination& dest,
|
||||
const SerializedValue<TString>& source) {
|
||||
const char* dup = makeString(source.data(), source.size()).save(buffer);
|
||||
if (!dup) return false;
|
||||
dest = SerializedValue<const char*>(dup, source.size());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
@ -35,7 +35,7 @@ deserialize(TDocument &doc, const TString &input) {
|
||||
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
|
||||
makeStringStorage(doc.buffer(), input),
|
||||
doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
}
|
||||
//
|
||||
// DeserializationError deserialize(TDocument& doc, TChar* input);
|
||||
@ -48,7 +48,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input) {
|
||||
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
|
||||
makeStringStorage(doc.buffer(), input),
|
||||
doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
}
|
||||
//
|
||||
// DeserializationError deserialize(TDocument& doc, TChar* input, size_t
|
||||
@ -63,7 +63,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input,
|
||||
return makeDeserializer<TDeserializer>(
|
||||
&doc.buffer(), makeReader(input, inputSize),
|
||||
makeStringStorage(doc.buffer(), input), doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
}
|
||||
//
|
||||
// DeserializationError deserialize(TDocument& doc, TStream input);
|
||||
@ -76,7 +76,7 @@ DeserializationError deserialize(TDocument &doc, TStream &input) {
|
||||
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
|
||||
makeStringStorage(doc.buffer(), input),
|
||||
doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
}
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -12,24 +12,21 @@
|
||||
namespace ArduinoJson {
|
||||
|
||||
class DynamicJsonDocument {
|
||||
Internals::DynamicJsonBuffer _buffer;
|
||||
JsonVariant _root;
|
||||
|
||||
public:
|
||||
uint8_t nestingLimit;
|
||||
|
||||
DynamicJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
DynamicJsonDocument(size_t capacity)
|
||||
: _buffer(capacity), nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _buffer(capacity) {}
|
||||
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return _root.is<T>();
|
||||
return getVariant().is<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename Internals::JsonVariantAs<T>::type as() const {
|
||||
return _root.as<T>();
|
||||
return getVariant().as<T>();
|
||||
}
|
||||
|
||||
// JsonObject to<JsonObject>()
|
||||
@ -39,7 +36,7 @@ class DynamicJsonDocument {
|
||||
to() {
|
||||
clear();
|
||||
JsonObject object(&_buffer);
|
||||
_root = object;
|
||||
getVariant().set(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -50,17 +47,27 @@ class DynamicJsonDocument {
|
||||
to() {
|
||||
clear();
|
||||
JsonArray array(&_buffer);
|
||||
_root = array;
|
||||
getVariant().set(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
// JsonVariant& to<JsonVariant>()
|
||||
// JsonVariant to<JsonVariant>()
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
|
||||
T&>::type
|
||||
JsonVariant>::type
|
||||
to() {
|
||||
clear();
|
||||
return _root;
|
||||
return getVariant();
|
||||
}
|
||||
|
||||
// JsonVariantData& to<JsonVariantData>()
|
||||
template <typename T>
|
||||
typename Internals::enable_if<
|
||||
Internals::is_same<T, Internals::JsonVariantData>::value,
|
||||
Internals::JsonVariantData&>::type
|
||||
to() {
|
||||
clear();
|
||||
return _rootData;
|
||||
}
|
||||
|
||||
Internals::DynamicJsonBuffer& buffer() {
|
||||
@ -69,7 +76,7 @@ class DynamicJsonDocument {
|
||||
|
||||
void clear() {
|
||||
_buffer.clear();
|
||||
_root = JsonVariant();
|
||||
_rootData.setNull();
|
||||
}
|
||||
|
||||
size_t memoryUsage() const {
|
||||
@ -78,7 +85,15 @@ class DynamicJsonDocument {
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor& visitor) const {
|
||||
return _root.visit(visitor);
|
||||
return _rootData.visit(visitor);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant getVariant() const {
|
||||
return JsonVariant(&_buffer, &_rootData);
|
||||
}
|
||||
|
||||
mutable Internals::DynamicJsonBuffer _buffer;
|
||||
mutable Internals::JsonVariantData _rootData;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "../Deserialization/deserialize.hpp"
|
||||
#include "../JsonVariant.hpp"
|
||||
#include "../Memory/JsonBuffer.hpp"
|
||||
#include "../Numbers/isFloat.hpp"
|
||||
#include "../Numbers/isInteger.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "./EscapeSequence.hpp"
|
||||
|
||||
@ -23,7 +25,7 @@ class JsonDeserializer {
|
||||
_stringStorage(stringStorage),
|
||||
_nestingLimit(nestingLimit),
|
||||
_loaded(false) {}
|
||||
DeserializationError parse(JsonVariant &variant) {
|
||||
DeserializationError parse(JsonVariantData &variant) {
|
||||
DeserializationError err = skipSpacesAndComments();
|
||||
if (err) return err;
|
||||
|
||||
@ -63,12 +65,12 @@ class JsonDeserializer {
|
||||
return true;
|
||||
}
|
||||
|
||||
DeserializationError parseArray(JsonVariant &variant) {
|
||||
DeserializationError parseArray(JsonVariantData &variant) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
|
||||
JsonArray array(_buffer);
|
||||
if (array.isNull()) return DeserializationError::NoMemory;
|
||||
variant = array;
|
||||
JsonArrayData *array = new (_buffer) JsonArrayData;
|
||||
if (!array) return DeserializationError::NoMemory;
|
||||
variant.setArray(*array);
|
||||
|
||||
// Check opening braket
|
||||
if (!eat('[')) return DeserializationError::InvalidInput;
|
||||
@ -82,13 +84,15 @@ class JsonDeserializer {
|
||||
|
||||
// Read each value
|
||||
for (;;) {
|
||||
// Allocate slot in array
|
||||
JsonVariantData *value = array->addSlot(_buffer);
|
||||
if (!value) return DeserializationError::NoMemory;
|
||||
|
||||
// 1 - Parse value
|
||||
JsonVariant value;
|
||||
_nestingLimit--;
|
||||
err = parse(value);
|
||||
err = parse(*value);
|
||||
_nestingLimit++;
|
||||
if (err) return err;
|
||||
if (!array.add(value)) return DeserializationError::NoMemory;
|
||||
|
||||
// 2 - Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
@ -100,12 +104,12 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError parseObject(JsonVariant &variant) {
|
||||
DeserializationError parseObject(JsonVariantData &variant) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
|
||||
JsonObject object(_buffer);
|
||||
if (object.isNull()) return DeserializationError::NoMemory;
|
||||
variant = object;
|
||||
JsonObjectData *object = new (_buffer) JsonObjectData;
|
||||
if (!object) return DeserializationError::NoMemory;
|
||||
variant.setObject(*object);
|
||||
|
||||
// Check opening brace
|
||||
if (!eat('{')) return DeserializationError::InvalidInput;
|
||||
@ -129,13 +133,15 @@ class JsonDeserializer {
|
||||
if (err) return err; // Colon
|
||||
if (!eat(':')) return DeserializationError::InvalidInput;
|
||||
|
||||
// Allocate slot in object
|
||||
JsonVariantData *value = object->addSlot(_buffer, key);
|
||||
if (!value) return DeserializationError::NoMemory;
|
||||
|
||||
// Parse value
|
||||
JsonVariant value;
|
||||
_nestingLimit--;
|
||||
err = parse(value);
|
||||
err = parse(*value);
|
||||
_nestingLimit++;
|
||||
if (err) return err;
|
||||
if (!object.set(key, value)) return DeserializationError::NoMemory;
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
@ -151,7 +157,7 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError parseValue(JsonVariant &variant) {
|
||||
DeserializationError parseValue(JsonVariantData &variant) {
|
||||
if (isQuote(current())) {
|
||||
return parseStringValue(variant);
|
||||
} else {
|
||||
@ -167,11 +173,11 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError parseStringValue(JsonVariant &variant) {
|
||||
DeserializationError parseStringValue(JsonVariantData &variant) {
|
||||
const char *value;
|
||||
DeserializationError err = parseQuotedString(&value);
|
||||
if (err) return err;
|
||||
variant = value;
|
||||
variant.setString(value);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
@ -229,7 +235,7 @@ class JsonDeserializer {
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError parseNumericValue(JsonVariant &result) {
|
||||
DeserializationError parseNumericValue(JsonVariantData &result) {
|
||||
char buffer[64];
|
||||
uint8_t n = 0;
|
||||
|
||||
@ -242,15 +248,15 @@ class JsonDeserializer {
|
||||
buffer[n] = 0;
|
||||
|
||||
if (isInteger(buffer)) {
|
||||
result = parseInteger<JsonInteger>(buffer);
|
||||
result.setInteger(parseInteger<JsonInteger>(buffer));
|
||||
} else if (isFloat(buffer)) {
|
||||
result = parseFloat<JsonFloat>(buffer);
|
||||
result.setFloat(parseFloat<JsonFloat>(buffer));
|
||||
} else if (!strcmp(buffer, "true")) {
|
||||
result = true;
|
||||
result.setBoolean(true);
|
||||
} else if (!strcmp(buffer, "false")) {
|
||||
result = false;
|
||||
result.setBoolean(false);
|
||||
} else if (!strcmp(buffer, "null")) {
|
||||
result = static_cast<const char *>(0);
|
||||
result.setNull();
|
||||
} else {
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ class JsonSerializer {
|
||||
_writer.writeFloat(value);
|
||||
}
|
||||
|
||||
void acceptArray(const JsonArray &array) {
|
||||
void acceptArray(const JsonArrayData &array) {
|
||||
_writer.beginArray();
|
||||
|
||||
JsonArray::const_iterator it = array.begin();
|
||||
JsonArrayData::const_iterator it = array.begin();
|
||||
while (it != array.end()) {
|
||||
it->visit(*this);
|
||||
|
||||
@ -36,10 +36,10 @@ class JsonSerializer {
|
||||
_writer.endArray();
|
||||
}
|
||||
|
||||
void acceptObject(const JsonObject &object) {
|
||||
void acceptObject(const JsonObjectData &object) {
|
||||
_writer.beginObject();
|
||||
|
||||
JsonObject::const_iterator it = object.begin();
|
||||
JsonObjectData::const_iterator it = object.begin();
|
||||
while (it != object.end()) {
|
||||
_writer.writeString(it->key);
|
||||
_writer.writeColon();
|
||||
@ -91,7 +91,7 @@ class JsonSerializer {
|
||||
} // namespace Internals
|
||||
|
||||
template <typename TSource, typename TDestination>
|
||||
size_t serializeJson(TSource &source, TDestination &destination) {
|
||||
size_t serializeJson(const TSource &source, TDestination &destination) {
|
||||
using namespace Internals;
|
||||
return serialize<JsonSerializer>(source, destination);
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "./JsonArrayData.hpp"
|
||||
#include "JsonArrayData.hpp"
|
||||
#include "JsonArrayIterator.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
@ -18,13 +19,14 @@ class JsonArray {
|
||||
friend class JsonVariant;
|
||||
|
||||
public:
|
||||
typedef Internals::JsonArrayData::iterator iterator;
|
||||
typedef Internals::JsonArrayData::const_iterator const_iterator;
|
||||
typedef JsonArrayIterator iterator;
|
||||
|
||||
JsonArray() : _data(0) {}
|
||||
JsonArray(Internals::JsonArrayData* arr) : _data(arr) {}
|
||||
JsonArray(Internals::JsonBuffer* buf)
|
||||
: _data(new (buf) Internals::JsonArrayData(buf)) {}
|
||||
FORCE_INLINE JsonArray() : _buffer(0), _data(0) {}
|
||||
FORCE_INLINE JsonArray(Internals::JsonBuffer* buf,
|
||||
Internals::JsonArrayData* arr)
|
||||
: _buffer(buf), _data(arr) {}
|
||||
FORCE_INLINE explicit JsonArray(Internals::JsonBuffer* buf)
|
||||
: _buffer(buf), _data(new (buf) Internals::JsonArrayData()) {}
|
||||
|
||||
// Adds the specified value at the end of the array.
|
||||
//
|
||||
@ -32,38 +34,29 @@ class JsonArray {
|
||||
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
|
||||
// std::string, String, JsonArrayData, JsonObject
|
||||
template <typename T>
|
||||
bool add(const T& value) {
|
||||
FORCE_INLINE bool add(const T& value) {
|
||||
return add_impl<const T&>(value);
|
||||
}
|
||||
//
|
||||
// bool add(TValue);
|
||||
// TValue = char*, const char*, const FlashStringHelper*
|
||||
template <typename T>
|
||||
bool add(T* value) {
|
||||
FORCE_INLINE bool add(T* value) {
|
||||
return add_impl<T*>(value);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!_data) return iterator();
|
||||
return _data->begin();
|
||||
return iterator(_buffer, _data->begin());
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (!_data) return const_iterator();
|
||||
return _data->begin();
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
FORCE_INLINE iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
// Imports a 1D array
|
||||
template <typename T, size_t N>
|
||||
bool copyFrom(T (&array)[N]) {
|
||||
FORCE_INLINE bool copyFrom(T (&array)[N]) {
|
||||
return copyFrom(array, N);
|
||||
}
|
||||
|
||||
@ -92,7 +85,7 @@ class JsonArray {
|
||||
|
||||
// Exports a 1D array
|
||||
template <typename T, size_t N>
|
||||
size_t copyTo(T (&array)[N]) const {
|
||||
FORCE_INLINE size_t copyTo(T (&array)[N]) const {
|
||||
return copyTo(array, N);
|
||||
}
|
||||
|
||||
@ -100,8 +93,7 @@ class JsonArray {
|
||||
template <typename T>
|
||||
size_t copyTo(T* array, size_t len) const {
|
||||
size_t i = 0;
|
||||
for (const_iterator it = begin(); it != end() && i < len; ++it)
|
||||
array[i++] = *it;
|
||||
for (iterator it = begin(); it != end() && i < len; ++it) array[i++] = *it;
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -110,44 +102,46 @@ class JsonArray {
|
||||
void copyTo(T (&array)[N1][N2]) const {
|
||||
if (!_data) return;
|
||||
size_t i = 0;
|
||||
for (const_iterator it = begin(); it != end() && i < N1; ++it) {
|
||||
for (iterator it = begin(); it != end() && i < N1; ++it) {
|
||||
it->as<JsonArray>().copyTo(array[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
JsonArray createNestedArray();
|
||||
JsonObject createNestedObject();
|
||||
FORCE_INLINE JsonArray createNestedArray();
|
||||
FORCE_INLINE JsonObject createNestedObject();
|
||||
|
||||
Internals::JsonArraySubscript operator[](size_t index);
|
||||
FORCE_INLINE Internals::JsonArraySubscript operator[](size_t index);
|
||||
|
||||
const Internals::JsonArraySubscript operator[](size_t index) const;
|
||||
FORCE_INLINE const Internals::JsonArraySubscript operator[](
|
||||
size_t index) const;
|
||||
|
||||
bool operator==(const JsonArray& rhs) const {
|
||||
FORCE_INLINE bool operator==(const JsonArray& rhs) const {
|
||||
return _data == rhs._data;
|
||||
}
|
||||
|
||||
// Gets the value at the specified index.
|
||||
template <typename T>
|
||||
typename Internals::JsonVariantAs<T>::type get(size_t index) const {
|
||||
const_iterator it = begin() += index;
|
||||
return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
|
||||
FORCE_INLINE typename Internals::JsonVariantAs<T>::type get(
|
||||
size_t index) const {
|
||||
iterator it = begin() += index;
|
||||
return it != end() ? it->as<T>() : T();
|
||||
}
|
||||
|
||||
// Check the type of the value at specified index.
|
||||
template <typename T>
|
||||
bool is(size_t index) const {
|
||||
const_iterator it = begin() += index;
|
||||
FORCE_INLINE bool is(size_t index) const {
|
||||
iterator it = begin() += index;
|
||||
return it != end() ? it->is<T>() : false;
|
||||
}
|
||||
|
||||
// Removes element at specified position.
|
||||
void remove(iterator it) {
|
||||
FORCE_INLINE void remove(iterator it) {
|
||||
if (!_data) return;
|
||||
_data->remove(it);
|
||||
_data->remove(it.internal());
|
||||
}
|
||||
|
||||
// Removes element at specified index.
|
||||
void remove(size_t index) {
|
||||
FORCE_INLINE void remove(size_t index) {
|
||||
remove(begin() += index);
|
||||
}
|
||||
|
||||
@ -157,7 +151,7 @@ class JsonArray {
|
||||
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
|
||||
// std::string, String, JsonArrayData, JsonObject
|
||||
template <typename T>
|
||||
bool set(size_t index, const T& value) {
|
||||
FORCE_INLINE bool set(size_t index, const T& value) {
|
||||
if (!_data) return false;
|
||||
return set_impl<const T&>(index, value);
|
||||
}
|
||||
@ -165,44 +159,45 @@ class JsonArray {
|
||||
// bool add(size_t index, TValue);
|
||||
// TValue = char*, const char*, const FlashStringHelper*
|
||||
template <typename T>
|
||||
bool set(size_t index, T* value) {
|
||||
FORCE_INLINE bool set(size_t index, T* value) {
|
||||
if (!_data) return false;
|
||||
return set_impl<T*>(index, value);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
FORCE_INLINE size_t size() const {
|
||||
if (!_data) return 0;
|
||||
return _data->size();
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
FORCE_INLINE bool isNull() const {
|
||||
return _data == 0;
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor& visitor) const {
|
||||
FORCE_INLINE void visit(Visitor& visitor) const {
|
||||
if (_data)
|
||||
return visitor.acceptArray(*this);
|
||||
visitor.acceptArray(*_data);
|
||||
else
|
||||
visitor.acceptNull();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename TValueRef>
|
||||
bool set_impl(size_t index, TValueRef value) {
|
||||
FORCE_INLINE bool set_impl(size_t index, TValueRef value) {
|
||||
iterator it = begin() += index;
|
||||
if (it == end()) return false;
|
||||
return Internals::ValueSaver<TValueRef>::save(_data->_buffer, *it, value);
|
||||
return it->set(value);
|
||||
}
|
||||
|
||||
template <typename TValueRef>
|
||||
bool add_impl(TValueRef value) {
|
||||
FORCE_INLINE bool add_impl(TValueRef value) {
|
||||
if (!_data) return false;
|
||||
iterator it = _data->add();
|
||||
iterator it = iterator(_buffer, _data->add(_buffer));
|
||||
if (it == end()) return false;
|
||||
return Internals::ValueSaver<TValueRef>::save(_data->_buffer, *it, value);
|
||||
return it->set(value);
|
||||
}
|
||||
|
||||
Internals::JsonBuffer* _buffer;
|
||||
Internals::JsonArrayData* _data;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -4,9 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/JsonVariantData.hpp"
|
||||
#include "Data/List.hpp"
|
||||
#include "Data/ValueSaver.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "Memory/JsonBufferAllocated.hpp"
|
||||
#include "Polyfills/type_traits.hpp"
|
||||
|
||||
@ -19,8 +18,11 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
struct JsonArrayData : List<JsonVariant>, JsonBufferAllocated {
|
||||
explicit JsonArrayData(JsonBuffer *buf) throw() : List<JsonVariant>(buf) {}
|
||||
struct JsonArrayData : List<JsonVariantData>, JsonBufferAllocated {
|
||||
JsonVariantData* addSlot(JsonBuffer* buffer) {
|
||||
iterator it = add(buffer);
|
||||
return it != end() ? &*it : 0;
|
||||
}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -11,14 +11,14 @@ namespace ArduinoJson {
|
||||
|
||||
inline JsonArray JsonArray::createNestedArray() {
|
||||
if (!_data) return JsonArray();
|
||||
JsonArray array(_data->_buffer);
|
||||
JsonArray array(_buffer);
|
||||
if (!array.isNull()) add(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
inline JsonObject JsonArray::createNestedObject() {
|
||||
if (!_data) return JsonObject();
|
||||
JsonObject object(_data->_buffer);
|
||||
JsonObject object(_buffer);
|
||||
if (!object.isNull()) add(object);
|
||||
return object;
|
||||
}
|
||||
|
72
src/ArduinoJson/JsonArrayIterator.hpp
Normal file
72
src/ArduinoJson/JsonArrayIterator.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/ListIterator.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
class JsonVariantPtr {
|
||||
public:
|
||||
JsonVariantPtr(Internals::JsonBuffer *buffer,
|
||||
Internals::JsonVariantData *data)
|
||||
: _variant(buffer, data) {}
|
||||
|
||||
JsonVariant *operator->() {
|
||||
return &_variant;
|
||||
}
|
||||
|
||||
JsonVariant &operator*() {
|
||||
return _variant;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant _variant;
|
||||
};
|
||||
|
||||
class JsonArrayIterator {
|
||||
typedef Internals::ListIterator<Internals::JsonVariantData> internal_iterator;
|
||||
|
||||
public:
|
||||
JsonArrayIterator() {}
|
||||
explicit JsonArrayIterator(Internals::JsonBuffer *buffer,
|
||||
internal_iterator iterator)
|
||||
: _iterator(iterator), _buffer(buffer) {}
|
||||
|
||||
JsonVariant operator*() const {
|
||||
return JsonVariant(_buffer, &*_iterator);
|
||||
}
|
||||
JsonVariantPtr operator->() {
|
||||
return JsonVariantPtr(_buffer, &*_iterator);
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayIterator &other) const {
|
||||
return _iterator == other._iterator;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayIterator &other) const {
|
||||
return _iterator != other._iterator;
|
||||
}
|
||||
|
||||
JsonArrayIterator &operator++() {
|
||||
++_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonArrayIterator &operator+=(size_t distance) {
|
||||
_iterator += distance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
internal_iterator internal() {
|
||||
return _iterator;
|
||||
}
|
||||
|
||||
private:
|
||||
internal_iterator _iterator;
|
||||
Internals::JsonBuffer *_buffer;
|
||||
};
|
||||
} // namespace ArduinoJson
|
@ -20,7 +20,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
|
||||
: _array(array), _index(index) {}
|
||||
|
||||
FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
|
||||
_array.set(_index, src);
|
||||
_array.set(_index, src.as<JsonVariant>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -5,29 +5,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "./JsonObjectData.hpp"
|
||||
#include "./JsonObjectIterator.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
class JsonObject {
|
||||
friend class JsonVariant;
|
||||
typedef Internals::JsonObjectData::iterator internal_iterator;
|
||||
|
||||
public:
|
||||
typedef Internals::JsonObjectData::iterator iterator;
|
||||
typedef Internals::JsonObjectData::const_iterator const_iterator;
|
||||
typedef JsonObjectIterator iterator;
|
||||
|
||||
JsonObject() : _data(0) {}
|
||||
JsonObject(Internals::JsonObjectData* object) : _data(object) {}
|
||||
JsonObject(Internals::JsonBuffer* buf)
|
||||
: _data(new (buf) Internals::JsonObjectData(buf)) {}
|
||||
FORCE_INLINE JsonObject() : _buffer(0), _data(0) {}
|
||||
FORCE_INLINE JsonObject(Internals::JsonBuffer* buf,
|
||||
Internals::JsonObjectData* object)
|
||||
: _buffer(buf), _data(object) {}
|
||||
FORCE_INLINE explicit JsonObject(Internals::JsonBuffer* buf)
|
||||
: _buffer(buf), _data(new (buf) Internals::JsonObjectData()) {}
|
||||
|
||||
iterator begin() {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!_data) return iterator();
|
||||
return _data->begin();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (!_data) return const_iterator();
|
||||
return _data->begin();
|
||||
return iterator(_buffer, _data->begin());
|
||||
}
|
||||
|
||||
// Tells weither the specified key is present and associated with a value.
|
||||
@ -35,42 +33,38 @@ class JsonObject {
|
||||
// bool containsKey(TKey);
|
||||
// TKey = const std::string&, const String&
|
||||
template <typename TString>
|
||||
bool containsKey(const TString& key) const {
|
||||
FORCE_INLINE bool containsKey(const TString& key) const {
|
||||
return containsKey_impl<const TString&>(key);
|
||||
}
|
||||
//
|
||||
// bool containsKey(TKey);
|
||||
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
|
||||
template <typename TString>
|
||||
bool containsKey(TString* key) const {
|
||||
FORCE_INLINE bool containsKey(TString* key) const {
|
||||
return containsKey_impl<TString*>(key);
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
FORCE_INLINE iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
// Creates and adds a JsonArray.
|
||||
//
|
||||
// JsonArray createNestedArray(TKey);
|
||||
// TKey = const std::string&, const String&
|
||||
template <typename TString>
|
||||
JsonArray createNestedArray(const TString& key);
|
||||
FORCE_INLINE JsonArray createNestedArray(const TString& key);
|
||||
// JsonArray createNestedArray(TKey);
|
||||
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
|
||||
template <typename TString>
|
||||
JsonArray createNestedArray(TString* key);
|
||||
FORCE_INLINE JsonArray createNestedArray(TString* key);
|
||||
|
||||
// Creates and adds a JsonObject.
|
||||
//
|
||||
// JsonObject createNestedObject(TKey);
|
||||
// TKey = const std::string&, const String&
|
||||
template <typename TString>
|
||||
JsonObject createNestedObject(const TString& key) {
|
||||
FORCE_INLINE JsonObject createNestedObject(const TString& key) {
|
||||
if (!_data) return JsonObject();
|
||||
return createNestedObject_impl<const TString&>(key);
|
||||
}
|
||||
@ -78,7 +72,7 @@ class JsonObject {
|
||||
// JsonObject createNestedObject(TKey);
|
||||
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
|
||||
template <typename TString>
|
||||
JsonObject createNestedObject(TString* key) {
|
||||
FORCE_INLINE JsonObject createNestedObject(TString* key) {
|
||||
return createNestedObject_impl<TString*>(key);
|
||||
}
|
||||
|
||||
@ -89,7 +83,7 @@ class JsonObject {
|
||||
// TValue = bool, char, long, int, short, float, double,
|
||||
// std::string, String, JsonArray, JsonObject
|
||||
template <typename TValue, typename TString>
|
||||
typename Internals::JsonVariantAs<TValue>::type get(
|
||||
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get(
|
||||
const TString& key) const {
|
||||
return get_impl<const TString&, TValue>(key);
|
||||
}
|
||||
@ -99,7 +93,8 @@ class JsonObject {
|
||||
// TValue = bool, char, long, int, short, float, double,
|
||||
// std::string, String, JsonArray, JsonObject
|
||||
template <typename TValue, typename TString>
|
||||
typename Internals::JsonVariantAs<TValue>::type get(TString* key) const {
|
||||
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get(
|
||||
TString* key) const {
|
||||
return get_impl<TString*, TValue>(key);
|
||||
}
|
||||
|
||||
@ -111,7 +106,7 @@ class JsonObject {
|
||||
// TValue = bool, char, long, int, short, float, double,
|
||||
// std::string, String, JsonArray, JsonObject
|
||||
template <typename TValue, typename TString>
|
||||
bool is(const TString& key) const {
|
||||
FORCE_INLINE bool is(const TString& key) const {
|
||||
return is_impl<const TString&, TValue>(key);
|
||||
}
|
||||
//
|
||||
@ -120,7 +115,7 @@ class JsonObject {
|
||||
// TValue = bool, char, long, int, short, float, double,
|
||||
// std::string, String, JsonArray, JsonObject
|
||||
template <typename TValue, typename TString>
|
||||
bool is(TString* key) const {
|
||||
FORCE_INLINE bool is(TString* key) const {
|
||||
return is_impl<TString*, TValue>(key);
|
||||
}
|
||||
|
||||
@ -129,7 +124,7 @@ class JsonObject {
|
||||
// JsonObjectSubscript operator[](TKey)
|
||||
// TKey = const std::string&, const String&
|
||||
template <typename TString>
|
||||
Internals::JsonObjectSubscript<const TString&> operator[](
|
||||
FORCE_INLINE Internals::JsonObjectSubscript<const TString&> operator[](
|
||||
const TString& key) {
|
||||
return Internals::JsonObjectSubscript<const TString&>(*this, key);
|
||||
}
|
||||
@ -137,7 +132,8 @@ class JsonObject {
|
||||
// JsonObjectSubscript operator[](TKey)
|
||||
// TKey = char*, const char*, char[], const char[N], const FlashStringHelper*
|
||||
template <typename TString>
|
||||
Internals::JsonObjectSubscript<TString*> operator[](TString* key) {
|
||||
FORCE_INLINE Internals::JsonObjectSubscript<TString*> operator[](
|
||||
TString* key) {
|
||||
return Internals::JsonObjectSubscript<TString*>(*this, key);
|
||||
}
|
||||
|
||||
@ -146,7 +142,7 @@ class JsonObject {
|
||||
// const JsonObjectSubscript operator[](TKey) const;
|
||||
// TKey = const std::string&, const String&
|
||||
template <typename TString>
|
||||
const Internals::JsonObjectSubscript<const TString&> operator[](
|
||||
FORCE_INLINE const Internals::JsonObjectSubscript<const TString&> operator[](
|
||||
const TString& key) const {
|
||||
return Internals::JsonObjectSubscript<const TString&>(*this, key);
|
||||
}
|
||||
@ -154,18 +150,18 @@ class JsonObject {
|
||||
// const JsonObjectSubscript operator[](TKey) const;
|
||||
// TKey = const char*, const char[N], const FlashStringHelper*
|
||||
template <typename TString>
|
||||
const Internals::JsonObjectSubscript<TString*> operator[](
|
||||
FORCE_INLINE const Internals::JsonObjectSubscript<TString*> operator[](
|
||||
TString* key) const {
|
||||
return Internals::JsonObjectSubscript<TString*>(*this, key);
|
||||
}
|
||||
|
||||
bool operator==(const JsonObject& rhs) const {
|
||||
FORCE_INLINE bool operator==(const JsonObject& rhs) const {
|
||||
return _data == rhs._data;
|
||||
}
|
||||
|
||||
void remove(iterator it) {
|
||||
FORCE_INLINE void remove(iterator it) {
|
||||
if (!_data) return;
|
||||
_data->remove(it);
|
||||
_data->remove(it.internal());
|
||||
}
|
||||
|
||||
// Removes the specified key and the associated value.
|
||||
@ -173,14 +169,14 @@ class JsonObject {
|
||||
// void remove(TKey);
|
||||
// TKey = const std::string&, const String&
|
||||
template <typename TString>
|
||||
void remove(const TString& key) {
|
||||
FORCE_INLINE void remove(const TString& key) {
|
||||
remove_impl<const TString&>(key);
|
||||
}
|
||||
//
|
||||
// void remove(TKey);
|
||||
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
|
||||
template <typename TString>
|
||||
void remove(TString* key) {
|
||||
FORCE_INLINE void remove(TString* key) {
|
||||
remove_impl<TString*>(key);
|
||||
}
|
||||
|
||||
@ -191,7 +187,7 @@ class JsonObject {
|
||||
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
|
||||
// std::string, String, JsonArray, JsonObject
|
||||
template <typename TValue, typename TString>
|
||||
bool set(const TString& key, const TValue& value) {
|
||||
FORCE_INLINE bool set(const TString& key, const TValue& value) {
|
||||
return set_impl<const TString&, const TValue&>(key, value);
|
||||
}
|
||||
//
|
||||
@ -199,7 +195,7 @@ class JsonObject {
|
||||
// TKey = const std::string&, const String&
|
||||
// TValue = char*, const char*, const FlashStringHelper*
|
||||
template <typename TValue, typename TString>
|
||||
bool set(const TString& key, TValue* value) {
|
||||
FORCE_INLINE bool set(const TString& key, TValue* value) {
|
||||
return set_impl<const TString&, TValue*>(key, value);
|
||||
}
|
||||
//
|
||||
@ -208,7 +204,7 @@ class JsonObject {
|
||||
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
|
||||
// std::string, String, JsonArray, JsonObject
|
||||
template <typename TValue, typename TString>
|
||||
bool set(TString* key, const TValue& value) {
|
||||
FORCE_INLINE bool set(TString* key, const TValue& value) {
|
||||
return set_impl<TString*, const TValue&>(key, value);
|
||||
}
|
||||
//
|
||||
@ -216,96 +212,110 @@ class JsonObject {
|
||||
// TKey = char*, const char*, const FlashStringHelper*
|
||||
// TValue = char*, const char*, const FlashStringHelper*
|
||||
template <typename TValue, typename TString>
|
||||
bool set(TString* key, TValue* value) {
|
||||
FORCE_INLINE bool set(TString* key, TValue* value) {
|
||||
return set_impl<TString*, TValue*>(key, value);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
FORCE_INLINE size_t size() const {
|
||||
if (!_data) return 0;
|
||||
return _data->size();
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
FORCE_INLINE bool isNull() const {
|
||||
return _data == 0;
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor& visitor) const {
|
||||
FORCE_INLINE void visit(Visitor& visitor) const {
|
||||
if (_data)
|
||||
visitor.acceptObject(*this);
|
||||
visitor.acceptObject(*_data);
|
||||
else
|
||||
return visitor.acceptNull();
|
||||
visitor.acceptNull();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename TStringRef>
|
||||
bool containsKey_impl(TStringRef key) const {
|
||||
return findKey<TStringRef>(key) != end();
|
||||
FORCE_INLINE bool containsKey_impl(TStringRef key) const {
|
||||
return findKey<TStringRef>(key) != _data->end();
|
||||
}
|
||||
|
||||
template <typename TStringRef>
|
||||
JsonArray createNestedArray_impl(TStringRef key);
|
||||
FORCE_INLINE JsonArray createNestedArray_impl(TStringRef key);
|
||||
|
||||
template <typename TStringRef>
|
||||
JsonObject createNestedObject_impl(TStringRef key);
|
||||
FORCE_INLINE JsonObject createNestedObject_impl(TStringRef key);
|
||||
|
||||
// Returns the list node that matches the specified key.
|
||||
template <typename TStringRef>
|
||||
iterator findKey(TStringRef key) {
|
||||
iterator it;
|
||||
for (it = begin(); it != end(); ++it) {
|
||||
internal_iterator findKey(TStringRef key) {
|
||||
if (!_data) return internal_iterator();
|
||||
internal_iterator it;
|
||||
for (it = _data->begin(); it != _data->end(); ++it) {
|
||||
if (Internals::makeString(key).equals(it->key)) break;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
template <typename TStringRef>
|
||||
const_iterator findKey(TStringRef key) const {
|
||||
FORCE_INLINE internal_iterator findKey(TStringRef key) const {
|
||||
return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
|
||||
}
|
||||
|
||||
template <typename TStringRef, typename TValue>
|
||||
typename Internals::JsonVariantAs<TValue>::type get_impl(
|
||||
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get_impl(
|
||||
TStringRef key) const {
|
||||
const_iterator it = findKey<TStringRef>(key);
|
||||
return it != end() ? it->value.as<TValue>()
|
||||
: Internals::JsonVariantDefault<TValue>::get();
|
||||
internal_iterator it = findKey<TStringRef>(key);
|
||||
return it != _data->end() ? JsonVariant(_buffer, &it->value).as<TValue>()
|
||||
: TValue();
|
||||
}
|
||||
|
||||
template <typename TStringRef, typename TValue>
|
||||
bool is_impl(TStringRef key) const {
|
||||
const_iterator it = findKey<TStringRef>(key);
|
||||
return it != end() ? it->value.is<TValue>() : false;
|
||||
FORCE_INLINE bool is_impl(TStringRef key) const {
|
||||
internal_iterator it = findKey<TStringRef>(key);
|
||||
return it != _data->end() ? JsonVariant(_buffer, &it->value).is<TValue>()
|
||||
: false;
|
||||
}
|
||||
|
||||
template <typename TStringRef>
|
||||
void remove_impl(TStringRef key) {
|
||||
FORCE_INLINE void remove_impl(TStringRef key) {
|
||||
if (!_data) return;
|
||||
_data->remove(findKey<TStringRef>(key));
|
||||
}
|
||||
|
||||
template <typename TStringRef, typename TValueRef>
|
||||
bool set_impl(TStringRef key, TValueRef value) {
|
||||
FORCE_INLINE bool set_impl(TStringRef key, TValueRef value) {
|
||||
if (!_data) return false;
|
||||
|
||||
// ignore null key
|
||||
if (Internals::makeString(key).is_null()) return false;
|
||||
|
||||
// search a matching key
|
||||
iterator it = findKey<TStringRef>(key);
|
||||
if (it == end()) {
|
||||
internal_iterator it = findKey<TStringRef>(key);
|
||||
if (it == _data->end()) {
|
||||
// add the key
|
||||
it = _data->add();
|
||||
if (it == end()) return false;
|
||||
bool key_ok =
|
||||
Internals::ValueSaver<TStringRef>::save(_data->_buffer, it->key, key);
|
||||
if (!key_ok) return false;
|
||||
// TODO: use JsonPairData directly, we don't need an iterator
|
||||
it = _data->add(_buffer);
|
||||
if (it == _data->end()) return false;
|
||||
if (!set_key(it, key)) return false;
|
||||
}
|
||||
|
||||
// save the value
|
||||
return Internals::ValueSaver<TValueRef>::save(_data->_buffer, it->value,
|
||||
value);
|
||||
return JsonVariant(_buffer, &it->value).set(value);
|
||||
}
|
||||
|
||||
Internals::JsonObjectData* _data;
|
||||
FORCE_INLINE bool set_key(internal_iterator& it, const char* key) {
|
||||
it->key = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set_key(internal_iterator& it, const T& key) {
|
||||
const char* dup = Internals::makeString(key).save(_buffer);
|
||||
if (!dup) return false;
|
||||
it->key = dup;
|
||||
return true;
|
||||
}
|
||||
|
||||
mutable Internals::JsonBuffer* _buffer;
|
||||
mutable Internals::JsonObjectData* _data;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Data/List.hpp"
|
||||
#include "Data/ValueSaver.hpp"
|
||||
#include "JsonPair.hpp"
|
||||
#include "Memory/JsonBufferAllocated.hpp"
|
||||
#include "Polyfills/type_traits.hpp"
|
||||
@ -19,8 +18,13 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
struct JsonObjectData : List<JsonPair>, JsonBufferAllocated {
|
||||
explicit JsonObjectData(JsonBuffer* buf) throw() : List<JsonPair>(buf) {}
|
||||
struct JsonObjectData : List<JsonPairData>, JsonBufferAllocated {
|
||||
JsonVariantData* addSlot(JsonBuffer* buffer, const char* key) {
|
||||
iterator it = add(buffer);
|
||||
if (it == end()) return 0;
|
||||
it->key = key;
|
||||
return &it->value;
|
||||
}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -22,7 +22,7 @@ inline JsonArray JsonObject::createNestedArray(TString* key) {
|
||||
template <typename TStringRef>
|
||||
inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
|
||||
if (!_data) return JsonArray();
|
||||
JsonArray array(_data->_buffer);
|
||||
JsonArray array(_buffer);
|
||||
if (!array.isNull()) set(key, array);
|
||||
return array;
|
||||
}
|
||||
@ -30,7 +30,7 @@ inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
|
||||
template <typename TStringRef>
|
||||
inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) {
|
||||
if (!_data) return JsonObject();
|
||||
JsonObject object(_data->_buffer);
|
||||
JsonObject object(_buffer);
|
||||
if (!object.isNull()) set(key, object);
|
||||
return object;
|
||||
}
|
||||
|
72
src/ArduinoJson/JsonObjectIterator.hpp
Normal file
72
src/ArduinoJson/JsonObjectIterator.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/ListIterator.hpp"
|
||||
#include "JsonPair.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
class JsonPairPtr {
|
||||
public:
|
||||
JsonPairPtr(Internals::JsonBuffer *buffer, Internals::JsonPairData *data)
|
||||
: _pair(buffer, data) {}
|
||||
|
||||
const JsonPair *operator->() const {
|
||||
return &_pair;
|
||||
}
|
||||
|
||||
const JsonPair &operator*() const {
|
||||
return _pair;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonPair _pair;
|
||||
};
|
||||
|
||||
// A read-write forward iterator for JsonArray
|
||||
class JsonObjectIterator {
|
||||
typedef Internals::ListIterator<Internals::JsonPairData> internal_iterator;
|
||||
|
||||
public:
|
||||
JsonObjectIterator() {}
|
||||
explicit JsonObjectIterator(Internals::JsonBuffer *buffer,
|
||||
internal_iterator iterator)
|
||||
: _buffer(buffer), _iterator(iterator) {}
|
||||
|
||||
JsonPair operator*() const {
|
||||
return JsonPair(_buffer, &*_iterator);
|
||||
}
|
||||
JsonPairPtr operator->() {
|
||||
return JsonPairPtr(_buffer, &*_iterator);
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectIterator &other) const {
|
||||
return _iterator == other._iterator;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectIterator &other) const {
|
||||
return _iterator != other._iterator;
|
||||
}
|
||||
|
||||
JsonObjectIterator &operator++() {
|
||||
++_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonObjectIterator &operator+=(size_t distance) {
|
||||
_iterator += distance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
internal_iterator internal() {
|
||||
return _iterator;
|
||||
}
|
||||
|
||||
private:
|
||||
Internals::JsonBuffer *_buffer;
|
||||
internal_iterator _iterator;
|
||||
};
|
||||
} // namespace ArduinoJson
|
@ -8,9 +8,30 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
// A key value pair for JsonObjectData.
|
||||
struct JsonPair {
|
||||
namespace Internals {
|
||||
|
||||
struct JsonPairData {
|
||||
const char* key;
|
||||
JsonVariant value;
|
||||
JsonVariantData value;
|
||||
};
|
||||
} // namespace Internals
|
||||
|
||||
// A key value pair for JsonObjectData.
|
||||
class JsonPair {
|
||||
public:
|
||||
JsonPair(Internals::JsonBuffer* buffer, Internals::JsonPairData* data)
|
||||
: _key(data->key), _value(buffer, &data->value) {}
|
||||
|
||||
const char* key() const {
|
||||
return _key;
|
||||
}
|
||||
|
||||
JsonVariant value() const {
|
||||
return _value;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* _key;
|
||||
JsonVariant _value;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -7,10 +7,10 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> // for uint8_t
|
||||
|
||||
#include "Data/JsonVariantContent.hpp"
|
||||
#include "Data/JsonVariantDefault.hpp"
|
||||
#include "Data/JsonVariantType.hpp"
|
||||
#include "Data/JsonVariantData.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "JsonVariantBase.hpp"
|
||||
#include "Memory/JsonBuffer.hpp"
|
||||
#include "Polyfills/type_traits.hpp"
|
||||
#include "Serialization/DynamicStringWriter.hpp"
|
||||
#include "SerializedValue.hpp"
|
||||
@ -30,84 +30,146 @@ class JsonObject;
|
||||
// - a reference to a JsonArray or JsonObject
|
||||
class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
public:
|
||||
// Intenal use only
|
||||
FORCE_INLINE JsonVariant(Internals::JsonBuffer *buffer,
|
||||
Internals::JsonVariantData *data)
|
||||
: _buffer(buffer), _data(data) {}
|
||||
|
||||
// Creates an uninitialized JsonVariant
|
||||
JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
|
||||
FORCE_INLINE JsonVariant() : _buffer(0), _data(0) {}
|
||||
|
||||
// Create a JsonVariant containing a boolean value.
|
||||
// It will be serialized as "true" or "false" in JSON.
|
||||
JsonVariant(bool value) {
|
||||
using namespace Internals;
|
||||
_type = JSON_BOOLEAN;
|
||||
_content.asInteger = static_cast<JsonUInt>(value);
|
||||
// set(bool value)
|
||||
FORCE_INLINE bool set(bool value) {
|
||||
if (!_data) return false;
|
||||
_data->setBoolean(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing a floating point value.
|
||||
// JsonVariant(double value);
|
||||
// JsonVariant(float value);
|
||||
// set(double value);
|
||||
// set(float value);
|
||||
template <typename T>
|
||||
JsonVariant(T value,
|
||||
typename Internals::enable_if<
|
||||
Internals::is_floating_point<T>::value>::type * = 0) {
|
||||
using namespace Internals;
|
||||
_type = JSON_FLOAT;
|
||||
_content.asFloat = static_cast<JsonFloat>(value);
|
||||
FORCE_INLINE bool set(
|
||||
T value, typename Internals::enable_if<
|
||||
Internals::is_floating_point<T>::value>::type * = 0) {
|
||||
if (!_data) return false;
|
||||
_data->setFloat(static_cast<Internals::JsonFloat>(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing an integer value.
|
||||
// JsonVariant(char)
|
||||
// JsonVariant(signed short)
|
||||
// JsonVariant(signed int)
|
||||
// JsonVariant(signed long)
|
||||
// JsonVariant(signed char)
|
||||
// set(char)
|
||||
// set(signed short)
|
||||
// set(signed int)
|
||||
// set(signed long)
|
||||
// set(signed char)
|
||||
template <typename T>
|
||||
JsonVariant(
|
||||
FORCE_INLINE bool set(
|
||||
T value,
|
||||
typename Internals::enable_if<Internals::is_integral<T>::value &&
|
||||
Internals::is_signed<T>::value>::type * =
|
||||
0) {
|
||||
using namespace Internals;
|
||||
if (value >= 0) {
|
||||
_type = JSON_POSITIVE_INTEGER;
|
||||
_content.asInteger = static_cast<JsonUInt>(value);
|
||||
} else {
|
||||
_type = JSON_NEGATIVE_INTEGER;
|
||||
_content.asInteger = ~static_cast<JsonUInt>(value) + 1;
|
||||
}
|
||||
if (!_data) return false;
|
||||
if (value >= 0)
|
||||
_data->setPostiveInteger(static_cast<Internals::JsonUInt>(value));
|
||||
else
|
||||
_data->setNegativeInteger(~static_cast<Internals::JsonUInt>(value) + 1);
|
||||
return true;
|
||||
}
|
||||
// JsonVariant(unsigned short)
|
||||
// JsonVariant(unsigned int)
|
||||
// JsonVariant(unsigned long)
|
||||
|
||||
// set(unsigned short)
|
||||
// set(unsigned int)
|
||||
// set(unsigned long)
|
||||
template <typename T>
|
||||
JsonVariant(
|
||||
FORCE_INLINE bool set(
|
||||
T value,
|
||||
typename Internals::enable_if<Internals::is_integral<T>::value &&
|
||||
Internals::is_unsigned<T>::value>::type * =
|
||||
0) {
|
||||
using namespace Internals;
|
||||
_type = JSON_POSITIVE_INTEGER;
|
||||
_content.asInteger = static_cast<JsonUInt>(value);
|
||||
if (!_data) return false;
|
||||
_data->setPostiveInteger(static_cast<Internals::JsonUInt>(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing a string.
|
||||
// JsonVariant(const char*);
|
||||
// JsonVariant(const signed char*);
|
||||
// JsonVariant(const unsigned char*);
|
||||
template <typename TChar>
|
||||
JsonVariant(const TChar *value,
|
||||
typename Internals::enable_if<sizeof(TChar) == 1>::type * = 0) {
|
||||
_type = Internals::JSON_STRING;
|
||||
_content.asString = reinterpret_cast<const char *>(value);
|
||||
// set(SerializedValue<const char *>)
|
||||
FORCE_INLINE bool set(Internals::SerializedValue<const char *> value) {
|
||||
if (!_data) return false;
|
||||
_data->setRaw(value.data(), value.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing an unparsed string
|
||||
JsonVariant(Internals::SerializedValue<const char *> value) {
|
||||
_type = Internals::JSON_UNPARSED;
|
||||
_content.asRaw.data = value.data();
|
||||
_content.asRaw.size = value.size();
|
||||
// set(SerializedValue<std::string>)
|
||||
// set(SerializedValue<String>)
|
||||
// set(SerializedValue<const __FlashStringHelper*>)
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
Internals::SerializedValue<T> value,
|
||||
typename Internals::enable_if<
|
||||
!Internals::is_same<const char *, T>::value>::type * = 0) {
|
||||
if (!_data) return false;
|
||||
const char *dup =
|
||||
Internals::makeString(value.data(), value.size()).save(_buffer);
|
||||
if (dup)
|
||||
_data->setRaw(dup, value.size());
|
||||
else
|
||||
_data->setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
JsonVariant(JsonArray array);
|
||||
JsonVariant(JsonObject object);
|
||||
// set(const std::string&)
|
||||
// set(const String&)
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
const T &value,
|
||||
typename Internals::enable_if<Internals::IsString<T>::value>::type * =
|
||||
0) {
|
||||
if (!_data) return false;
|
||||
const char *dup = Internals::makeString(value).save(_buffer);
|
||||
if (dup) {
|
||||
_data->setString(dup);
|
||||
return true;
|
||||
} else {
|
||||
_data->setNull();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// set(char*)
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
T *value,
|
||||
typename Internals::enable_if<Internals::IsString<T *>::value>::type * =
|
||||
0) {
|
||||
if (!_data) return false;
|
||||
const char *dup = Internals::makeString(value).save(_buffer);
|
||||
if (dup) {
|
||||
_data->setString(dup);
|
||||
return true;
|
||||
} else {
|
||||
_data->setNull();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// set(const char*);
|
||||
FORCE_INLINE bool set(const char *value) {
|
||||
if (!_data) return false;
|
||||
_data->setString(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool set(const JsonVariant &value) {
|
||||
if (!_data) return false;
|
||||
if (value._data)
|
||||
*_data = *value._data;
|
||||
else
|
||||
_data->setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool set(const JsonArray &array);
|
||||
FORCE_INLINE bool set(const Internals::JsonArraySubscript &);
|
||||
FORCE_INLINE bool set(const JsonObject &object);
|
||||
template <typename TString>
|
||||
FORCE_INLINE bool set(const Internals::JsonObjectSubscript<TString> &);
|
||||
|
||||
// Get the variant as the specified type.
|
||||
//
|
||||
@ -121,43 +183,47 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
// unsigned int as<unsigned int>() const;
|
||||
// unsigned long as<unsigned long>() const;
|
||||
template <typename T>
|
||||
const typename Internals::enable_if<Internals::is_integral<T>::value, T>::type
|
||||
FORCE_INLINE const typename Internals::enable_if<
|
||||
Internals::is_integral<T>::value, T>::type
|
||||
as() const {
|
||||
return variantAsInteger<T>();
|
||||
return _data ? _data->asInteger<T>() : T();
|
||||
}
|
||||
// bool as<bool>() const
|
||||
template <typename T>
|
||||
const typename Internals::enable_if<Internals::is_same<T, bool>::value,
|
||||
T>::type
|
||||
FORCE_INLINE const typename Internals::enable_if<
|
||||
Internals::is_same<T, bool>::value, T>::type
|
||||
as() const {
|
||||
return variantAsInteger<int>() != 0;
|
||||
return _data && _data->asInteger<int>() != 0;
|
||||
}
|
||||
//
|
||||
// double as<double>() const;
|
||||
// float as<float>() const;
|
||||
template <typename T>
|
||||
const typename Internals::enable_if<Internals::is_floating_point<T>::value,
|
||||
T>::type
|
||||
FORCE_INLINE const typename Internals::enable_if<
|
||||
Internals::is_floating_point<T>::value, T>::type
|
||||
as() const {
|
||||
return variantAsFloat<T>();
|
||||
return _data ? _data->asFloat<T>() : 0;
|
||||
}
|
||||
//
|
||||
// const char* as<const char*>() const;
|
||||
// const char* as<char*>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_same<T, const char *>::value ||
|
||||
Internals::is_same<T, char *>::value,
|
||||
const char *>::type
|
||||
FORCE_INLINE typename Internals::enable_if<
|
||||
Internals::is_same<T, const char *>::value ||
|
||||
Internals::is_same<T, char *>::value,
|
||||
const char *>::type
|
||||
as() const {
|
||||
return variantAsString();
|
||||
return _data ? _data->asString() : 0;
|
||||
}
|
||||
//
|
||||
// std::string as<std::string>() const;
|
||||
// String as<String>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::IsWriteableString<T>::value, T>::type
|
||||
as() const {
|
||||
const char *cstr = variantAsString();
|
||||
FORCE_INLINE
|
||||
typename Internals::enable_if<Internals::IsWriteableString<T>::value,
|
||||
T>::type
|
||||
as() const {
|
||||
const char *cstr = _data ? _data->asString() : 0;
|
||||
if (cstr) return T(cstr);
|
||||
T s;
|
||||
serializeJson(*this, s);
|
||||
@ -167,7 +233,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
// JsonArray as<JsonArray>() const;
|
||||
// const JsonArray as<const JsonArray>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<
|
||||
FORCE_INLINE typename Internals::enable_if<
|
||||
Internals::is_same<typename Internals::remove_const<T>::type,
|
||||
JsonArray>::value,
|
||||
JsonArray>::type
|
||||
@ -176,7 +242,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
// JsonObject as<JsonObject>() const;
|
||||
// const JsonObject as<const JsonObject>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<
|
||||
FORCE_INLINE typename Internals::enable_if<
|
||||
Internals::is_same<typename Internals::remove_const<T>::type,
|
||||
JsonObject>::value,
|
||||
T>::type
|
||||
@ -184,9 +250,10 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
//
|
||||
// JsonVariant as<JsonVariant> const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
|
||||
T>::type
|
||||
as() const {
|
||||
FORCE_INLINE
|
||||
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
|
||||
T>::type
|
||||
as() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -203,122 +270,78 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
// bool is<unsigned int>() const;
|
||||
// bool is<unsigned long>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_integral<T>::value, bool>::type
|
||||
FORCE_INLINE typename Internals::enable_if<Internals::is_integral<T>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return variantIsInteger();
|
||||
return _data && _data->isInteger();
|
||||
}
|
||||
//
|
||||
// bool is<double>() const;
|
||||
// bool is<float>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_floating_point<T>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return variantIsFloat();
|
||||
FORCE_INLINE
|
||||
typename Internals::enable_if<Internals::is_floating_point<T>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return _data && _data->isFloat();
|
||||
}
|
||||
//
|
||||
// bool is<bool>() const
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_same<T, bool>::value, bool>::type
|
||||
FORCE_INLINE typename Internals::enable_if<Internals::is_same<T, bool>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return variantIsBoolean();
|
||||
return _data && _data->isBoolean();
|
||||
}
|
||||
//
|
||||
// bool is<const char*>() const;
|
||||
// bool is<char*>() const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_same<T, const char *>::value ||
|
||||
Internals::is_same<T, char *>::value,
|
||||
bool>::type
|
||||
FORCE_INLINE typename Internals::enable_if<
|
||||
Internals::is_same<T, const char *>::value ||
|
||||
Internals::is_same<T, char *>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return variantIsString();
|
||||
return _data && _data->isString();
|
||||
}
|
||||
//
|
||||
// bool is<JsonArray> const;
|
||||
// bool is<const JsonArray> const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<
|
||||
FORCE_INLINE typename Internals::enable_if<
|
||||
Internals::is_same<typename Internals::remove_const<T>::type,
|
||||
JsonArray>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return variantIsArray();
|
||||
return _data && _data->isArray();
|
||||
}
|
||||
//
|
||||
// bool is<JsonObject> const;
|
||||
// bool is<const JsonObject> const;
|
||||
template <typename T>
|
||||
typename Internals::enable_if<
|
||||
FORCE_INLINE typename Internals::enable_if<
|
||||
Internals::is_same<typename Internals::remove_const<T>::type,
|
||||
JsonObject>::value,
|
||||
bool>::type
|
||||
is() const {
|
||||
return variantIsObject();
|
||||
return _data && _data->isObject();
|
||||
}
|
||||
|
||||
// Returns true if the variant has a value
|
||||
bool isNull() const {
|
||||
return _type == Internals::JSON_UNDEFINED;
|
||||
FORCE_INLINE bool isNull() const {
|
||||
return _data == 0 || _data->isNull();
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor &visitor) const {
|
||||
using namespace Internals;
|
||||
switch (_type) {
|
||||
case JSON_FLOAT:
|
||||
return visitor.acceptFloat(_content.asFloat);
|
||||
|
||||
case JSON_ARRAY:
|
||||
return visitor.acceptArray(_content.asArray);
|
||||
|
||||
case JSON_OBJECT:
|
||||
return visitor.acceptObject(_content.asObject);
|
||||
|
||||
case JSON_STRING:
|
||||
return visitor.acceptString(_content.asString);
|
||||
|
||||
case JSON_UNPARSED:
|
||||
return visitor.acceptRawJson(_content.asRaw.data, _content.asRaw.size);
|
||||
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return visitor.acceptNegativeInteger(_content.asInteger);
|
||||
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
return visitor.acceptPositiveInteger(_content.asInteger);
|
||||
|
||||
case JSON_BOOLEAN:
|
||||
return visitor.acceptBoolean(_content.asInteger != 0);
|
||||
|
||||
default: // JSON_UNDEFINED
|
||||
return visitor.acceptNull();
|
||||
}
|
||||
FORCE_INLINE void visit(Visitor &visitor) const {
|
||||
if (_data)
|
||||
_data->visit(visitor);
|
||||
else
|
||||
visitor.acceptNull();
|
||||
}
|
||||
|
||||
private:
|
||||
JsonArray variantAsArray() const;
|
||||
JsonObject variantAsObject() const;
|
||||
const char *variantAsString() const;
|
||||
template <typename T>
|
||||
T variantAsFloat() const;
|
||||
template <typename T>
|
||||
T variantAsInteger() const;
|
||||
bool variantIsBoolean() const;
|
||||
bool variantIsFloat() const;
|
||||
bool variantIsInteger() const;
|
||||
bool variantIsArray() const {
|
||||
return _type == Internals::JSON_ARRAY;
|
||||
}
|
||||
bool variantIsObject() const {
|
||||
return _type == Internals::JSON_OBJECT;
|
||||
}
|
||||
bool variantIsString() const {
|
||||
return _type == Internals::JSON_STRING;
|
||||
}
|
||||
|
||||
// The current type of the variant
|
||||
Internals::JsonVariantType _type;
|
||||
|
||||
// The various alternatives for the value of the variant.
|
||||
Internals::JsonVariantContent _content;
|
||||
};
|
||||
Internals::JsonBuffer *_buffer;
|
||||
Internals::JsonVariantData *_data;
|
||||
}; // namespace ArduinoJson
|
||||
} // namespace ArduinoJson
|
||||
|
@ -5,6 +5,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Data/IsVariant.hpp"
|
||||
#include "Data/JsonFloat.hpp"
|
||||
#include "Data/JsonInteger.hpp"
|
||||
#include "Polyfills/type_traits.hpp"
|
||||
#include "Strings/StringTypes.hpp"
|
||||
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include "JsonArrayData.hpp"
|
||||
#include "JsonObjectData.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "Numbers/isFloat.hpp"
|
||||
#include "Numbers/isInteger.hpp"
|
||||
#include "Numbers/parseFloat.hpp"
|
||||
#include "Numbers/parseInteger.hpp"
|
||||
|
||||
@ -17,22 +15,32 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
inline JsonVariant::JsonVariant(JsonArray array) {
|
||||
if (!array.isNull()) {
|
||||
_type = Internals::JSON_ARRAY;
|
||||
_content.asArray = array._data;
|
||||
} else {
|
||||
_type = Internals::JSON_UNDEFINED;
|
||||
}
|
||||
inline bool JsonVariant::set(const JsonArray& array) {
|
||||
if (!_data) return false;
|
||||
if (array._data)
|
||||
_data->setArray(*array._data);
|
||||
else
|
||||
_data->setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(JsonObject object) {
|
||||
if (!object.isNull()) {
|
||||
_type = Internals::JSON_OBJECT;
|
||||
_content.asObject = object._data;
|
||||
} else {
|
||||
_type = Internals::JSON_UNDEFINED;
|
||||
}
|
||||
inline bool JsonVariant::set(const Internals::JsonArraySubscript& value) {
|
||||
return set(value.as<JsonVariant>());
|
||||
}
|
||||
|
||||
inline bool JsonVariant::set(const JsonObject& object) {
|
||||
if (!_data) return false;
|
||||
if (object._data)
|
||||
_data->setObject(*object._data);
|
||||
else
|
||||
_data->setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TString>
|
||||
inline bool JsonVariant::set(
|
||||
const Internals::JsonObjectSubscript<TString>& value) {
|
||||
return set(value.template as<JsonVariant>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -41,7 +49,7 @@ inline typename Internals::enable_if<
|
||||
JsonArray>::value,
|
||||
JsonArray>::type
|
||||
JsonVariant::as() const {
|
||||
return variantAsArray();
|
||||
return _data ? JsonArray(_buffer, _data->asArray()) : JsonArray();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -50,78 +58,6 @@ inline typename Internals::enable_if<
|
||||
JsonObject>::value,
|
||||
T>::type
|
||||
JsonVariant::as() const {
|
||||
return variantAsObject();
|
||||
return _data ? JsonObject(_buffer, _data->asObject()) : JsonObject();
|
||||
}
|
||||
|
||||
inline JsonArray JsonVariant::variantAsArray() const {
|
||||
if (_type == Internals::JSON_ARRAY) return _content.asArray;
|
||||
return JsonArray();
|
||||
}
|
||||
|
||||
inline JsonObject JsonVariant::variantAsObject() const {
|
||||
if (_type == Internals::JSON_OBJECT) return _content.asObject;
|
||||
return JsonObject();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T JsonVariant::variantAsInteger() const {
|
||||
using namespace Internals;
|
||||
switch (_type) {
|
||||
case JSON_UNDEFINED:
|
||||
case JSON_UNPARSED:
|
||||
return 0;
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
case JSON_BOOLEAN:
|
||||
return T(_content.asInteger);
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return T(~_content.asInteger + 1);
|
||||
case JSON_STRING:
|
||||
return parseInteger<T>(_content.asString);
|
||||
default:
|
||||
return T(_content.asFloat);
|
||||
}
|
||||
}
|
||||
|
||||
inline const char *JsonVariant::variantAsString() const {
|
||||
using namespace Internals;
|
||||
return _type == JSON_STRING ? _content.asString : NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T JsonVariant::variantAsFloat() const {
|
||||
using namespace Internals;
|
||||
switch (_type) {
|
||||
case JSON_UNDEFINED:
|
||||
case JSON_UNPARSED:
|
||||
return 0;
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
case JSON_BOOLEAN:
|
||||
return static_cast<T>(_content.asInteger);
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return -static_cast<T>(_content.asInteger);
|
||||
case JSON_STRING:
|
||||
return parseFloat<T>(_content.asString);
|
||||
default:
|
||||
return static_cast<T>(_content.asFloat);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool JsonVariant::variantIsBoolean() const {
|
||||
using namespace Internals;
|
||||
return _type == JSON_BOOLEAN;
|
||||
}
|
||||
|
||||
inline bool JsonVariant::variantIsInteger() const {
|
||||
using namespace Internals;
|
||||
|
||||
return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER;
|
||||
}
|
||||
|
||||
inline bool JsonVariant::variantIsFloat() const {
|
||||
using namespace Internals;
|
||||
|
||||
return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
|
||||
_type == JSON_NEGATIVE_INTEGER;
|
||||
}
|
||||
|
||||
} // namespace ArduinoJson
|
||||
|
@ -11,12 +11,12 @@ namespace Internals {
|
||||
|
||||
class JsonBufferAllocated {
|
||||
public:
|
||||
void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() {
|
||||
void *operator new(size_t n, JsonBuffer *jsonBuffer) NOEXCEPT {
|
||||
if (!jsonBuffer) return NULL;
|
||||
return jsonBuffer->alloc(n);
|
||||
}
|
||||
|
||||
void operator delete(void *, JsonBuffer *)throw();
|
||||
void operator delete(void *, JsonBuffer *)NOEXCEPT {}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -24,17 +24,17 @@ class MsgPackDeserializer {
|
||||
_stringStorage(stringStorage),
|
||||
_nestingLimit(nestingLimit) {}
|
||||
|
||||
DeserializationError parse(JsonVariant &variant) {
|
||||
DeserializationError parse(JsonVariantData &variant) {
|
||||
uint8_t code;
|
||||
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
||||
|
||||
if ((code & 0x80) == 0) {
|
||||
variant = code;
|
||||
variant.setInteger(code);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
if ((code & 0xe0) == 0xe0) {
|
||||
variant = static_cast<int8_t>(code);
|
||||
variant.setInteger(static_cast<int8_t>(code));
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
@ -48,15 +48,15 @@ class MsgPackDeserializer {
|
||||
|
||||
switch (code) {
|
||||
case 0xc0:
|
||||
variant = static_cast<char *>(0);
|
||||
variant.setNull();
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc2:
|
||||
variant = false;
|
||||
variant.setBoolean(false);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc3:
|
||||
variant = true;
|
||||
variant.setBoolean(true);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xcc:
|
||||
@ -171,54 +171,54 @@ class MsgPackDeserializer {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError readInteger(JsonVariant &variant) {
|
||||
DeserializationError readInteger(JsonVariantData &variant) {
|
||||
T value;
|
||||
if (!readInteger(value)) return DeserializationError::IncompleteInput;
|
||||
variant = value;
|
||||
variant.setInteger(value);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
||||
JsonVariant &variant) {
|
||||
JsonVariantData &variant) {
|
||||
T value;
|
||||
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
||||
fixEndianess(value);
|
||||
variant = value;
|
||||
variant.setFloat(value);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
||||
JsonVariant &variant) {
|
||||
JsonVariantData &variant) {
|
||||
T value;
|
||||
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
||||
fixEndianess(value);
|
||||
variant = value;
|
||||
variant.setFloat(value);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
|
||||
JsonVariant &variant) {
|
||||
JsonVariantData &variant) {
|
||||
uint8_t i[8]; // input is 8 bytes
|
||||
T value; // output is 4 bytes
|
||||
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
||||
if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
|
||||
doubleToFloat(i, o);
|
||||
fixEndianess(value);
|
||||
variant = value;
|
||||
variant.setFloat(value);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError readString(JsonVariant &variant) {
|
||||
DeserializationError readString(JsonVariantData &variant) {
|
||||
T size;
|
||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||
return readString(variant, size);
|
||||
}
|
||||
|
||||
DeserializationError readString(JsonVariant &variant, size_t n) {
|
||||
DeserializationError readString(JsonVariantData &variant, size_t n) {
|
||||
typename remove_reference<TStringStorage>::type::String str =
|
||||
_stringStorage.startString();
|
||||
for (; n; --n) {
|
||||
@ -228,64 +228,68 @@ class MsgPackDeserializer {
|
||||
}
|
||||
const char *s = str.c_str();
|
||||
if (s == NULL) return DeserializationError::NoMemory;
|
||||
variant = s;
|
||||
variant.setString(s);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TSize>
|
||||
DeserializationError readArray(JsonVariant &variant) {
|
||||
DeserializationError readArray(JsonVariantData &variant) {
|
||||
TSize size;
|
||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||
return readArray(variant, size);
|
||||
}
|
||||
|
||||
DeserializationError readArray(JsonVariant &variant, size_t n) {
|
||||
JsonArray array(_buffer);
|
||||
if (array.isNull()) return DeserializationError::NoMemory;
|
||||
variant = array;
|
||||
return readArray(array, n);
|
||||
DeserializationError readArray(JsonVariantData &variant, size_t n) {
|
||||
JsonArrayData *array = new (_buffer) JsonArrayData;
|
||||
if (!array) return DeserializationError::NoMemory;
|
||||
|
||||
variant.setArray(*array);
|
||||
return readArray(*array, n);
|
||||
}
|
||||
|
||||
DeserializationError readArray(JsonArray array, size_t n) {
|
||||
DeserializationError readArray(JsonArrayData &array, size_t n) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
--_nestingLimit;
|
||||
for (; n; --n) {
|
||||
JsonVariant variant;
|
||||
DeserializationError err = parse(variant);
|
||||
JsonVariantData *value = array.addSlot(_buffer);
|
||||
if (!value) return DeserializationError::NoMemory;
|
||||
|
||||
DeserializationError err = parse(*value);
|
||||
if (err) return err;
|
||||
if (!array.add(variant)) return DeserializationError::NoMemory;
|
||||
}
|
||||
++_nestingLimit;
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TSize>
|
||||
DeserializationError readObject(JsonVariant &variant) {
|
||||
DeserializationError readObject(JsonVariantData &variant) {
|
||||
TSize size;
|
||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||
return readObject(variant, size);
|
||||
}
|
||||
|
||||
DeserializationError readObject(JsonVariant &variant, size_t n) {
|
||||
JsonObject object(_buffer);
|
||||
if (object.isNull()) return DeserializationError::NoMemory;
|
||||
variant = object;
|
||||
return readObject(object, n);
|
||||
DeserializationError readObject(JsonVariantData &variant, size_t n) {
|
||||
JsonObjectData *object = new (_buffer) JsonObjectData;
|
||||
if (!object) return DeserializationError::NoMemory;
|
||||
variant.setObject(*object);
|
||||
|
||||
return readObject(*object, n);
|
||||
}
|
||||
|
||||
DeserializationError readObject(JsonObject object, size_t n) {
|
||||
DeserializationError readObject(JsonObjectData &object, size_t n) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
--_nestingLimit;
|
||||
for (; n; --n) {
|
||||
DeserializationError err;
|
||||
JsonVariant variant;
|
||||
err = parse(variant);
|
||||
JsonVariantData key;
|
||||
DeserializationError err = parse(key);
|
||||
if (err) return err;
|
||||
const char *key = variant.as<char *>();
|
||||
if (!key) return DeserializationError::NotSupported;
|
||||
err = parse(variant);
|
||||
if (!key.isString()) return DeserializationError::NotSupported;
|
||||
|
||||
JsonVariantData *value = object.addSlot(_buffer, key.asString());
|
||||
if (!value) return DeserializationError::NoMemory;
|
||||
|
||||
err = parse(*value);
|
||||
if (err) return err;
|
||||
if (!object.set(key, variant)) return DeserializationError::NoMemory;
|
||||
}
|
||||
++_nestingLimit;
|
||||
return DeserializationError::Ok;
|
||||
|
@ -36,7 +36,7 @@ class MsgPackSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
void acceptArray(const JsonArray& array) {
|
||||
void acceptArray(const JsonArrayData& array) {
|
||||
size_t n = array.size();
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x90 + array.size()));
|
||||
@ -47,13 +47,13 @@ class MsgPackSerializer {
|
||||
writeByte(0xDD);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (JsonArray::const_iterator it = array.begin(); it != array.end();
|
||||
for (JsonArrayData::const_iterator it = array.begin(); it != array.end();
|
||||
++it) {
|
||||
it->visit(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void acceptObject(const JsonObject& object) {
|
||||
void acceptObject(const JsonObjectData& object) {
|
||||
size_t n = object.size();
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x80 + n));
|
||||
@ -64,7 +64,7 @@ class MsgPackSerializer {
|
||||
writeByte(0xDF);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (JsonObject::const_iterator it = object.begin(); it != object.end();
|
||||
for (JsonObjectData::const_iterator it = object.begin(); it != object.end();
|
||||
++it) {
|
||||
acceptString(it->key);
|
||||
it->value.visit(*this);
|
||||
|
@ -27,3 +27,9 @@
|
||||
#define DEPRECATED(msg)
|
||||
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define NOEXCEPT noexcept
|
||||
#else
|
||||
#define NOEXCEPT throw()
|
||||
#endif
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Configuration.hpp"
|
||||
#include "is_same.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
@ -9,11 +9,8 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
template <size_t CAPACITY = sizeof(JsonVariant)>
|
||||
template <size_t CAPACITY>
|
||||
class StaticJsonDocument {
|
||||
Internals::StaticJsonBuffer<CAPACITY> _buffer;
|
||||
JsonVariant _root;
|
||||
|
||||
public:
|
||||
uint8_t nestingLimit;
|
||||
|
||||
@ -25,12 +22,12 @@ class StaticJsonDocument {
|
||||
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return _root.is<T>();
|
||||
return getVariant().template is<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename Internals::JsonVariantAs<T>::type as() const {
|
||||
return _root.as<T>();
|
||||
return getVariant().template as<T>();
|
||||
}
|
||||
|
||||
// JsonObject to<JsonObject>()
|
||||
@ -40,7 +37,7 @@ class StaticJsonDocument {
|
||||
to() {
|
||||
clear();
|
||||
JsonObject object(&_buffer);
|
||||
_root = object;
|
||||
getVariant().set(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -51,22 +48,32 @@ class StaticJsonDocument {
|
||||
to() {
|
||||
clear();
|
||||
JsonArray array(&_buffer);
|
||||
_root = array;
|
||||
getVariant().set(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
// JsonVariant to<JsonVariant>()
|
||||
template <typename T>
|
||||
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
|
||||
T&>::type
|
||||
JsonVariant>::type
|
||||
to() {
|
||||
clear();
|
||||
return _root;
|
||||
return getVariant();
|
||||
}
|
||||
|
||||
// JsonVariantData& to<JsonVariantData>()
|
||||
template <typename T>
|
||||
typename Internals::enable_if<
|
||||
Internals::is_same<T, Internals::JsonVariantData>::value,
|
||||
Internals::JsonVariantData&>::type
|
||||
to() {
|
||||
clear();
|
||||
return _rootData;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_buffer.clear();
|
||||
_root = JsonVariant();
|
||||
_rootData.setNull();
|
||||
}
|
||||
|
||||
size_t memoryUsage() const {
|
||||
@ -75,8 +82,16 @@ class StaticJsonDocument {
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor& visitor) const {
|
||||
return _root.visit(visitor);
|
||||
return getVariant().visit(visitor);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant getVariant() const {
|
||||
return JsonVariant(&_buffer, &_rootData);
|
||||
}
|
||||
|
||||
mutable Internals::StaticJsonBuffer<CAPACITY> _buffer;
|
||||
mutable Internals::JsonVariantData _rootData;
|
||||
};
|
||||
|
||||
} // namespace ArduinoJson
|
||||
|
@ -15,7 +15,7 @@ class FixedSizeFlashString {
|
||||
bool equals(const char* expected) const {
|
||||
const char* actual = reinterpret_cast<const char*>(_str);
|
||||
if (!actual || !expected) return actual == expected;
|
||||
return strcmp_P(actual, expected) == 0;
|
||||
return strncmp_P(expected, actual, _size) == 0;
|
||||
}
|
||||
|
||||
bool is_null() const {
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h> // strcmp
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
|
@ -26,6 +26,7 @@ class StlString {
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
if (!expected) return false;
|
||||
return *_str == expected;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ class ZeroTerminatedFlashString {
|
||||
bool equals(const char* expected) const {
|
||||
const char* actual = reinterpret_cast<const char*>(_str);
|
||||
if (!actual || !expected) return actual == expected;
|
||||
return strcmp_P(actual, expected) == 0;
|
||||
return strcmp_P(expected, actual) == 0;
|
||||
}
|
||||
|
||||
bool is_null() const {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ARDUINOJSON_VERSION "6.2.2-beta"
|
||||
#define ARDUINOJSON_VERSION "6.3.0-beta"
|
||||
#define ARDUINOJSON_VERSION_MAJOR 6
|
||||
#define ARDUINOJSON_VERSION_MINOR 2
|
||||
#define ARDUINOJSON_VERSION_REVISION 2
|
||||
#define ARDUINOJSON_VERSION_MINOR 3
|
||||
#define ARDUINOJSON_VERSION_REVISION 0
|
||||
|
@ -38,7 +38,9 @@ endif()
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
add_compile_options(
|
||||
-Wstrict-null-sentinel
|
||||
-Wno-vla # Allow VLA in tests
|
||||
)
|
||||
add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
|
||||
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
|
||||
@ -53,6 +55,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(
|
||||
-Wc++11-compat
|
||||
-Wdeprecated-register
|
||||
-Wno-vla-extension # Allow VLA in tests
|
||||
)
|
||||
add_definitions(
|
||||
-DHAS_VARIABLE_LENGTH_ARRAY
|
||||
-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -68,6 +75,7 @@ add_subdirectory(DynamicJsonBuffer)
|
||||
add_subdirectory(IntegrationTests)
|
||||
add_subdirectory(JsonArray)
|
||||
add_subdirectory(JsonDeserializer)
|
||||
add_subdirectory(JsonDocument)
|
||||
add_subdirectory(JsonObject)
|
||||
add_subdirectory(JsonSerializer)
|
||||
add_subdirectory(JsonVariant)
|
||||
|
@ -7,57 +7,69 @@
|
||||
|
||||
TEST_CASE("JsonArray::add()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray _array = doc.to<JsonArray>();
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
|
||||
SECTION("int") {
|
||||
_array.add(123);
|
||||
REQUIRE(123 == _array[0].as<int>());
|
||||
REQUIRE(_array[0].is<int>());
|
||||
REQUIRE(_array[0].is<double>());
|
||||
array.add(123);
|
||||
REQUIRE(123 == array[0].as<int>());
|
||||
REQUIRE(array[0].is<int>());
|
||||
REQUIRE(array[0].is<double>());
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
_array.add(123.45);
|
||||
REQUIRE(123.45 == _array[0].as<double>());
|
||||
REQUIRE(_array[0].is<double>());
|
||||
REQUIRE_FALSE(_array[0].is<bool>());
|
||||
array.add(123.45);
|
||||
REQUIRE(123.45 == array[0].as<double>());
|
||||
REQUIRE(array[0].is<double>());
|
||||
REQUIRE_FALSE(array[0].is<bool>());
|
||||
}
|
||||
|
||||
SECTION("bool") {
|
||||
_array.add(true);
|
||||
REQUIRE(true == _array[0].as<bool>());
|
||||
REQUIRE(_array[0].is<bool>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
array.add(true);
|
||||
REQUIRE(true == array[0].as<bool>());
|
||||
REQUIRE(array[0].is<bool>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* str = "hello";
|
||||
_array.add(str);
|
||||
REQUIRE(str == _array[0].as<std::string>());
|
||||
REQUIRE(_array[0].is<const char*>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
array.add(str);
|
||||
REQUIRE(str == array[0].as<std::string>());
|
||||
REQUIRE(array[0].is<const char*>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("vla") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add(vla);
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("nested array") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
|
||||
_array.add(arr);
|
||||
array.add(arr);
|
||||
|
||||
REQUIRE(arr == _array[0].as<JsonArray>());
|
||||
REQUIRE(_array[0].is<JsonArray>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
REQUIRE(arr == array[0].as<JsonArray>());
|
||||
REQUIRE(array[0].is<JsonArray>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("nested object") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
_array.add(obj);
|
||||
array.add(obj);
|
||||
|
||||
REQUIRE(obj == _array[0].as<JsonObject>());
|
||||
REQUIRE(_array[0].is<JsonObject>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
REQUIRE(obj == array[0].as<JsonObject>());
|
||||
REQUIRE(array[0].is<JsonObject>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("array subscript") {
|
||||
@ -66,9 +78,9 @@ TEST_CASE("JsonArray::add()") {
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
arr.add(str);
|
||||
|
||||
_array.add(arr[0]);
|
||||
array.add(arr[0]);
|
||||
|
||||
REQUIRE(str == _array[0]);
|
||||
REQUIRE(str == array[0]);
|
||||
}
|
||||
|
||||
SECTION("object subscript") {
|
||||
@ -77,49 +89,49 @@ TEST_CASE("JsonArray::add()") {
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
obj["x"] = str;
|
||||
|
||||
_array.add(obj["x"]);
|
||||
array.add(obj["x"]);
|
||||
|
||||
REQUIRE(str == _array[0]);
|
||||
REQUIRE(str == array[0]);
|
||||
}
|
||||
|
||||
SECTION("should not duplicate const char*") {
|
||||
_array.add("world");
|
||||
array.add("world");
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1);
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate char*") {
|
||||
_array.add(const_cast<char*>("world"));
|
||||
array.add(const_cast<char*>("world"));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
_array.add(std::string("world"));
|
||||
array.add(std::string("world"));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should not duplicate serialized(const char*)") {
|
||||
_array.add(serialized("{}"));
|
||||
array.add(serialized("{}"));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1);
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(char*)") {
|
||||
_array.add(serialized(const_cast<char*>("{}")));
|
||||
array.add(serialized(const_cast<char*>("{}")));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(std::string)") {
|
||||
_array.add(serialized(std::string("{}")));
|
||||
array.add(serialized(std::string("{}")));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(std::string)") {
|
||||
_array.add(serialized(std::string("\0XX", 3)));
|
||||
array.add(serialized(std::string("\0XX", 3)));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
@ -30,8 +30,4 @@ TEST_CASE("JsonArray::begin()/end()") {
|
||||
SECTION("Mutable") {
|
||||
run_iterator_test<JsonArray::iterator>();
|
||||
}
|
||||
|
||||
SECTION("Const") {
|
||||
run_iterator_test<JsonArray::const_iterator>();
|
||||
}
|
||||
}
|
||||
|
@ -9,57 +9,70 @@ using namespace Catch::Matchers;
|
||||
|
||||
TEST_CASE("JsonArray::set()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray _array = doc.to<JsonArray>();
|
||||
_array.add(0);
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
array.add(0);
|
||||
|
||||
SECTION("int") {
|
||||
_array.set(0, 123);
|
||||
REQUIRE(123 == _array[0].as<int>());
|
||||
REQUIRE(_array[0].is<int>());
|
||||
REQUIRE_FALSE(_array[0].is<bool>());
|
||||
array.set(0, 123);
|
||||
REQUIRE(123 == array[0].as<int>());
|
||||
REQUIRE(array[0].is<int>());
|
||||
REQUIRE_FALSE(array[0].is<bool>());
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
_array.set(0, 123.45);
|
||||
REQUIRE(123.45 == _array[0].as<double>());
|
||||
REQUIRE(_array[0].is<double>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
array.set(0, 123.45);
|
||||
REQUIRE(123.45 == array[0].as<double>());
|
||||
REQUIRE(array[0].is<double>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("bool") {
|
||||
_array.set(0, true);
|
||||
REQUIRE(true == _array[0].as<bool>());
|
||||
REQUIRE(_array[0].is<bool>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
array.set(0, true);
|
||||
REQUIRE(true == array[0].as<bool>());
|
||||
REQUIRE(array[0].is<bool>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
_array.set(0, "hello");
|
||||
REQUIRE_THAT(_array[0].as<const char*>(), Equals("hello"));
|
||||
REQUIRE(_array[0].is<const char*>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
array.set(0, "hello");
|
||||
REQUIRE_THAT(array[0].as<const char*>(), Equals("hello"));
|
||||
REQUIRE(array[0].is<const char*>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set()") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add("hello");
|
||||
array.set(0, vla);
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("nested array") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
|
||||
_array.set(0, arr);
|
||||
array.set(0, arr);
|
||||
|
||||
REQUIRE(arr == _array[0].as<JsonArray>());
|
||||
REQUIRE(_array[0].is<JsonArray>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
REQUIRE(arr == array[0].as<JsonArray>());
|
||||
REQUIRE(array[0].is<JsonArray>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("nested object") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
_array.set(0, obj);
|
||||
array.set(0, obj);
|
||||
|
||||
REQUIRE(obj == _array[0].as<JsonObject>());
|
||||
REQUIRE(_array[0].is<JsonObject>());
|
||||
REQUIRE_FALSE(_array[0].is<int>());
|
||||
REQUIRE(obj == array[0].as<JsonObject>());
|
||||
REQUIRE(array[0].is<JsonObject>());
|
||||
REQUIRE_FALSE(array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("array subscript") {
|
||||
@ -67,9 +80,9 @@ TEST_CASE("JsonArray::set()") {
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
arr.add("hello");
|
||||
|
||||
_array.set(0, arr[0]);
|
||||
array.set(0, arr[0]);
|
||||
|
||||
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello"));
|
||||
REQUIRE_THAT(array[0].as<char*>(), Equals("hello"));
|
||||
}
|
||||
|
||||
SECTION("object subscript") {
|
||||
@ -77,25 +90,25 @@ TEST_CASE("JsonArray::set()") {
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
obj["x"] = "hello";
|
||||
|
||||
_array.set(0, obj["x"]);
|
||||
array.set(0, obj["x"]);
|
||||
|
||||
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello"));
|
||||
REQUIRE_THAT(array[0].as<char*>(), Equals("hello"));
|
||||
}
|
||||
|
||||
SECTION("should not duplicate const char*") {
|
||||
_array.set(0, "world");
|
||||
array.set(0, "world");
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1);
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate char*") {
|
||||
_array.set(0, const_cast<char*>("world"));
|
||||
array.set(0, const_cast<char*>("world"));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
_array.set(0, std::string("world"));
|
||||
array.set(0, std::string("world"));
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
@ -8,85 +8,85 @@
|
||||
|
||||
TEST_CASE("JsonArray::operator[]") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray _array = doc.to<JsonArray>();
|
||||
_array.add(0);
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
array.add(0);
|
||||
|
||||
SECTION("int") {
|
||||
_array[0] = 123;
|
||||
REQUIRE(123 == _array[0].as<int>());
|
||||
REQUIRE(true == _array[0].is<int>());
|
||||
REQUIRE(false == _array[0].is<bool>());
|
||||
array[0] = 123;
|
||||
REQUIRE(123 == array[0].as<int>());
|
||||
REQUIRE(true == array[0].is<int>());
|
||||
REQUIRE(false == array[0].is<bool>());
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
|
||||
SECTION("long long") {
|
||||
_array[0] = 9223372036854775807;
|
||||
REQUIRE(9223372036854775807 == _array[0].as<long long>());
|
||||
REQUIRE(true == _array[0].is<int>());
|
||||
REQUIRE(false == _array[0].is<bool>());
|
||||
array[0] = 9223372036854775807;
|
||||
REQUIRE(9223372036854775807 == array[0].as<long long>());
|
||||
REQUIRE(true == array[0].is<int>());
|
||||
REQUIRE(false == array[0].is<bool>());
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("double") {
|
||||
_array[0] = 123.45;
|
||||
REQUIRE(123.45 == _array[0].as<double>());
|
||||
REQUIRE(true == _array[0].is<double>());
|
||||
REQUIRE(false == _array[0].is<int>());
|
||||
array[0] = 123.45;
|
||||
REQUIRE(123.45 == array[0].as<double>());
|
||||
REQUIRE(true == array[0].is<double>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("bool") {
|
||||
_array[0] = true;
|
||||
REQUIRE(true == _array[0].as<bool>());
|
||||
REQUIRE(true == _array[0].is<bool>());
|
||||
REQUIRE(false == _array[0].is<int>());
|
||||
array[0] = true;
|
||||
REQUIRE(true == array[0].as<bool>());
|
||||
REQUIRE(true == array[0].is<bool>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
const char* str = "hello";
|
||||
|
||||
_array[0] = str;
|
||||
REQUIRE(str == _array[0].as<const char*>());
|
||||
REQUIRE(str == _array[0].as<char*>()); // <- short hand
|
||||
REQUIRE(true == _array[0].is<const char*>());
|
||||
REQUIRE(false == _array[0].is<int>());
|
||||
array[0] = str;
|
||||
REQUIRE(str == array[0].as<const char*>());
|
||||
REQUIRE(str == array[0].as<char*>()); // <- short hand
|
||||
REQUIRE(true == array[0].is<const char*>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("nested array") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
JsonArray arr2 = doc2.to<JsonArray>();
|
||||
|
||||
_array[0] = arr;
|
||||
array[0] = arr2;
|
||||
|
||||
REQUIRE(arr == _array[0].as<JsonArray>());
|
||||
REQUIRE(arr == _array[0].as<JsonArray>()); // <- short hand
|
||||
// REQUIRE(arr == _array[0].as<const JsonArray>());
|
||||
// REQUIRE(arr == _array[0].as<const JsonArray>()); // <- short hand
|
||||
REQUIRE(true == _array[0].is<JsonArray>());
|
||||
REQUIRE(false == _array[0].is<int>());
|
||||
REQUIRE(arr2 == array[0].as<JsonArray>());
|
||||
REQUIRE(arr2 == array[0].as<JsonArray>()); // <- short hand
|
||||
// REQUIRE(arr2 == array[0].as<const JsonArray>());
|
||||
// REQUIRE(arr2 == array[0].as<const JsonArray>()); // <- short hand
|
||||
REQUIRE(true == array[0].is<JsonArray>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("nested object") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
_array[0] = obj;
|
||||
array[0] = obj;
|
||||
|
||||
REQUIRE(obj == _array[0].as<JsonObject>());
|
||||
REQUIRE(obj == _array[0].as<const JsonObject>()); // <- short hand
|
||||
REQUIRE(true == _array[0].is<JsonObject>());
|
||||
REQUIRE(false == _array[0].is<int>());
|
||||
REQUIRE(obj == array[0].as<JsonObject>());
|
||||
REQUIRE(obj == array[0].as<const JsonObject>()); // <- short hand
|
||||
REQUIRE(true == array[0].is<JsonObject>());
|
||||
REQUIRE(false == array[0].is<int>());
|
||||
}
|
||||
|
||||
SECTION("array subscript") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
JsonArray arr2 = doc2.to<JsonArray>();
|
||||
const char* str = "hello";
|
||||
|
||||
arr.add(str);
|
||||
arr2.add(str);
|
||||
|
||||
_array[0] = arr[0];
|
||||
array[0] = arr2[0];
|
||||
|
||||
REQUIRE(str == _array[0]);
|
||||
REQUIRE(str == array[0]);
|
||||
}
|
||||
|
||||
SECTION("object subscript") {
|
||||
@ -96,26 +96,50 @@ TEST_CASE("JsonArray::operator[]") {
|
||||
|
||||
obj["x"] = str;
|
||||
|
||||
_array[0] = obj["x"];
|
||||
array[0] = obj["x"];
|
||||
|
||||
REQUIRE(str == _array[0]);
|
||||
REQUIRE(str == array[0]);
|
||||
}
|
||||
|
||||
SECTION("should not duplicate const char*") {
|
||||
_array[0] = "world";
|
||||
array[0] = "world";
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1);
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate char*") {
|
||||
_array[0] = const_cast<char*>("world");
|
||||
array[0] = const_cast<char*>("world");
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
_array[0] = std::string("world");
|
||||
array[0] = std::string("world");
|
||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||
REQUIRE(expectedSize == doc.memoryUsage());
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(VLA)") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add("hello");
|
||||
array[0].set(vla);
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
}
|
||||
|
||||
SECTION("operator=(VLA)") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
array.add("hello");
|
||||
array[0] = vla;
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -3,15 +3,14 @@
|
||||
# MIT License
|
||||
|
||||
add_executable(JsonDeserializerTests
|
||||
DeserializationError.cpp
|
||||
deserializeJsonArray.cpp
|
||||
deserializeJsonArrayStatic.cpp
|
||||
deserializeJsonObject.cpp
|
||||
deserializeJsonObjectStatic.cpp
|
||||
deserializeJsonValue.cpp
|
||||
DeserializationError.cpp
|
||||
input_types.cpp
|
||||
nestingLimit.cpp
|
||||
std_istream.cpp
|
||||
std_string.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(JsonDeserializerTests catch)
|
||||
|
@ -6,6 +6,35 @@
|
||||
#include <catch.hpp>
|
||||
#include <sstream>
|
||||
|
||||
TEST_CASE("deserializeJson(const std::string&)") {
|
||||
DynamicJsonDocument doc;
|
||||
|
||||
SECTION("should accept const string") {
|
||||
const std::string input("[42]");
|
||||
|
||||
DeserializationError err = deserializeJson(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("should accept temporary string") {
|
||||
DeserializationError err = deserializeJson(doc, std::string("[42]"));
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("should duplicate content") {
|
||||
std::string input("[\"hello\"]");
|
||||
|
||||
DeserializationError err = deserializeJson(doc, input);
|
||||
input[2] = 'X'; // alter the string tomake sure we made a copy
|
||||
|
||||
JsonArray array = doc.as<JsonArray>();
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(std::string("hello") == array[0]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeJson(std::istream&)") {
|
||||
DynamicJsonDocument doc;
|
||||
|
||||
@ -71,3 +100,16 @@ TEST_CASE("deserializeJson(std::istream&)") {
|
||||
REQUIRE('1' == char(json.get()));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
TEST_CASE("deserializeJson(VLA)") {
|
||||
int i = 9;
|
||||
char vla[i];
|
||||
strcpy(vla, "{\"a\":42}");
|
||||
|
||||
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
|
||||
DeserializationError err = deserializeJson(doc, vla);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
#endif
|
@ -1,35 +0,0 @@
|
||||
// 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]");
|
||||
|
||||
DeserializationError err = deserializeJson(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("should accept temporary string") {
|
||||
DeserializationError err = deserializeJson(doc, std::string("[42]"));
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("should duplicate content") {
|
||||
std::string input("[\"hello\"]");
|
||||
|
||||
DeserializationError err = deserializeJson(doc, input);
|
||||
input[2] = 'X'; // alter the string tomake sure we made a copy
|
||||
|
||||
JsonArray array = doc.as<JsonArray>();
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(std::string("hello") == array[0]);
|
||||
}
|
||||
}
|
11
test/JsonDocument/CMakeLists.txt
Normal file
11
test/JsonDocument/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# ArduinoJson - arduinojson.org
|
||||
# Copyright Benoit Blanchon 2014-2018
|
||||
# MIT License
|
||||
|
||||
add_executable(JsonDocumentTests
|
||||
DynamicJsonDocument.cpp
|
||||
StaticJsonDocument.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(JsonDocumentTests catch)
|
||||
add_test(JsonDocument JsonDocumentTests)
|
20
test/JsonDocument/DynamicJsonDocument.cpp
Normal file
20
test/JsonDocument/DynamicJsonDocument.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("DynamicJsonDocument") {
|
||||
DynamicJsonDocument doc;
|
||||
|
||||
SECTION("serializeJson()") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = "world";
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
|
||||
REQUIRE(json == "{\"hello\":\"world\"}");
|
||||
}
|
||||
}
|
20
test/JsonDocument/StaticJsonDocument.cpp
Normal file
20
test/JsonDocument/StaticJsonDocument.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("StaticJsonDocument") {
|
||||
StaticJsonDocument<200> doc;
|
||||
|
||||
SECTION("serializeJson()") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = "world";
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
|
||||
REQUIRE(json == "{\"hello\":\"world\"}");
|
||||
}
|
||||
}
|
@ -4,8 +4,11 @@
|
||||
|
||||
add_executable(JsonObjectTests
|
||||
containsKey.cpp
|
||||
createNestedArray.cpp
|
||||
createNestedObject.cpp
|
||||
get.cpp
|
||||
invalid.cpp
|
||||
is.cpp
|
||||
isNull.cpp
|
||||
iterator.cpp
|
||||
remove.cpp
|
||||
|
@ -8,23 +8,29 @@
|
||||
TEST_CASE("JsonObject::containsKey()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj.set("hello", 42);
|
||||
|
||||
SECTION("ContainsKeyReturnsFalseForNonExistingKey") {
|
||||
obj.set("hello", 42);
|
||||
|
||||
SECTION("returns false if key not present") {
|
||||
REQUIRE(false == obj.containsKey("world"));
|
||||
}
|
||||
|
||||
SECTION("ContainsKeyReturnsTrueForDefinedValue") {
|
||||
obj.set("hello", 42);
|
||||
|
||||
SECTION("returns true if key present") {
|
||||
REQUIRE(true == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
SECTION("ContainsKeyReturnsFalseAfterRemove") {
|
||||
obj.set("hello", 42);
|
||||
SECTION("returns false after remove()") {
|
||||
obj.remove("hello");
|
||||
|
||||
REQUIRE(false == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a VLA") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == obj.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
25
test/JsonObject/createNestedArray.cpp
Normal file
25
test/JsonObject/createNestedArray.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonObject::createNestedArray()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
|
||||
SECTION("key is a const char*") {
|
||||
obj.createNestedArray("hello");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a VLA") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
obj.createNestedArray(vla);
|
||||
}
|
||||
#endif
|
||||
}
|
25
test/JsonObject/createNestedObject.cpp
Normal file
25
test/JsonObject/createNestedObject.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonObject::createNestedObject()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
|
||||
SECTION("key is a const char*") {
|
||||
obj.createNestedObject("hello");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a VLA") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
obj.createNestedObject(vla);
|
||||
}
|
||||
#endif
|
||||
}
|
@ -11,9 +11,20 @@ TEST_CASE("JsonObject::get()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
|
||||
SECTION("GetConstCharPointer_GivenStringLiteral") {
|
||||
SECTION("get<const char*>(const char*)") {
|
||||
obj.set("hello", "world");
|
||||
const char* value = obj.get<const char*>("hello");
|
||||
REQUIRE_THAT(value, Equals("world"));
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("get<const char*>(VLA)") {
|
||||
obj.set("hello", "world");
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(std::string("world") == obj.get<char*>(vla));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
28
test/JsonObject/is.cpp
Normal file
28
test/JsonObject/is.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonObject::is<T>()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["int"] = 42;
|
||||
obj["str"] = "hello";
|
||||
|
||||
SECTION("is<int>(const char*)") {
|
||||
REQUIRE(true == obj.is<int>("int"));
|
||||
REQUIRE(false == obj.is<int>("str"));
|
||||
}
|
||||
|
||||
#if HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("is<T>(VLA)") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "int");
|
||||
|
||||
REQUIRE(true == obj.is<int>(vla));
|
||||
}
|
||||
#endif
|
||||
}
|
@ -16,36 +16,28 @@ TEST_CASE("JsonObject::begin()/end()") {
|
||||
SECTION("NonConstIterator") {
|
||||
JsonObject::iterator it = obj.begin();
|
||||
REQUIRE(obj.end() != it);
|
||||
REQUIRE_THAT(it->key, Equals("ab"));
|
||||
REQUIRE(12 == it->value);
|
||||
it->key = "a.b";
|
||||
it->value = 1.2;
|
||||
REQUIRE_THAT(it->key(), Equals("ab"));
|
||||
REQUIRE(12 == it->value());
|
||||
++it;
|
||||
REQUIRE(obj.end() != it);
|
||||
REQUIRE_THAT(it->key, Equals("cd"));
|
||||
REQUIRE(34 == it->value);
|
||||
it->key = "c.d";
|
||||
it->value = 3.4;
|
||||
REQUIRE_THAT(it->key(), Equals("cd"));
|
||||
REQUIRE(34 == it->value());
|
||||
++it;
|
||||
REQUIRE(obj.end() == it);
|
||||
|
||||
REQUIRE(2 == obj.size());
|
||||
REQUIRE(1.2 == obj["a.b"]);
|
||||
REQUIRE(3.4 == obj["c.d"]);
|
||||
}
|
||||
|
||||
SECTION("ConstIterator") {
|
||||
const JsonObject const_object = obj;
|
||||
JsonObject::const_iterator it = const_object.begin();
|
||||
// SECTION("ConstIterator") {
|
||||
// const JsonObject const_object = obj;
|
||||
// JsonObject::iterator it = const_object.begin();
|
||||
|
||||
REQUIRE(const_object.end() != it);
|
||||
REQUIRE_THAT(it->key, Equals("ab"));
|
||||
REQUIRE(12 == it->value);
|
||||
++it;
|
||||
REQUIRE(const_object.end() != it);
|
||||
REQUIRE_THAT(it->key, Equals("cd"));
|
||||
REQUIRE(34 == it->value);
|
||||
++it;
|
||||
REQUIRE(const_object.end() == it);
|
||||
}
|
||||
// REQUIRE(const_object.end() != it);
|
||||
// REQUIRE_THAT(it->key(), Equals("ab"));
|
||||
// REQUIRE(12 == it->value());
|
||||
// ++it;
|
||||
// REQUIRE(const_object.end() != it);
|
||||
// REQUIRE_THAT(it->key(), Equals("cd"));
|
||||
// REQUIRE(34 == it->value());
|
||||
// ++it;
|
||||
// REQUIRE(const_object.end() == it);
|
||||
// }
|
||||
}
|
||||
|
@ -32,11 +32,24 @@ TEST_CASE("JsonObject::remove()") {
|
||||
obj["c"] = 2;
|
||||
|
||||
for (JsonObject::iterator it = obj.begin(); it != obj.end(); ++it) {
|
||||
if (it->value == 1) obj.remove(it);
|
||||
if (it->value() == 1) obj.remove(it);
|
||||
}
|
||||
|
||||
std::string result;
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"a\":0,\"c\":2}" == result);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a vla") {
|
||||
obj["hello"] = 1;
|
||||
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
obj.remove(vla);
|
||||
|
||||
REQUIRE(0 == obj.size());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -42,6 +42,38 @@ TEST_CASE("JsonObject::set()") {
|
||||
REQUIRE_FALSE(obj["hello"].is<long>());
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a VLA") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
obj.set(vla, "world");
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("value is a VLA") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
obj.set("hello", vla);
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("key and value are VLAs") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
obj.set(vla, vla);
|
||||
|
||||
REQUIRE(std::string("world") == obj["world"]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("nested array") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
|
@ -159,4 +159,58 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
REQUIRE(obj.size() == 1);
|
||||
REQUIRE(obj[null] == 0);
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
|
||||
SECTION("obj[VLA] = str") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
obj[vla] = "world";
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("obj[str] = VLA") { // issue #416
|
||||
int i = 32;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
obj["hello"] = vla;
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"].as<char*>());
|
||||
}
|
||||
|
||||
SECTION("obj.set(VLA, str)") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
obj[vla] = "world";
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("obj.set(str, VLA)") {
|
||||
int i = 32;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
obj["hello"].set(vla);
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"].as<char*>());
|
||||
}
|
||||
|
||||
SECTION("obj[VLA]") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
|
||||
obj = doc.as<JsonObject>();
|
||||
REQUIRE(std::string("world") == obj[vla]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ add_executable(JsonSerializerTests
|
||||
JsonObject.cpp
|
||||
JsonObjectPretty.cpp
|
||||
JsonVariant.cpp
|
||||
misc.cpp
|
||||
std_stream.cpp
|
||||
std_string.cpp
|
||||
)
|
||||
|
@ -6,9 +6,12 @@
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
void check(JsonVariant variant, const std::string &expected) {
|
||||
template <typename T>
|
||||
void check(T value, const std::string &expected) {
|
||||
DynamicJsonDocument doc;
|
||||
doc.to<JsonVariant>().set(value);
|
||||
char buffer[256] = "";
|
||||
size_t returnValue = serializeJson(variant, buffer, sizeof(buffer));
|
||||
size_t returnValue = serializeJson(doc, buffer, sizeof(buffer));
|
||||
REQUIRE(expected == buffer);
|
||||
REQUIRE(expected.size() == returnValue);
|
||||
}
|
||||
@ -22,10 +25,22 @@ TEST_CASE("serializeJson(JsonVariant)") {
|
||||
check(static_cast<char *>(0), "null");
|
||||
}
|
||||
|
||||
SECTION("String") {
|
||||
SECTION("const char*") {
|
||||
check("hello", "\"hello\"");
|
||||
}
|
||||
|
||||
SECTION("string") {
|
||||
check(std::string("hello"), "\"hello\"");
|
||||
}
|
||||
|
||||
SECTION("SerializedValue<const char*>") {
|
||||
check(serialized("[1,2]"), "[1,2]");
|
||||
}
|
||||
|
||||
SECTION("SerializedValue<std::string>") {
|
||||
check(serialized(std::string("[1,2]")), "[1,2]");
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
check(3.1415927, "3.1415927");
|
||||
}
|
||||
|
46
test/JsonSerializer/misc.cpp
Normal file
46
test/JsonSerializer/misc.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
template <typename T>
|
||||
void check(T value, const std::string &expected) {
|
||||
DynamicJsonDocument doc;
|
||||
doc.to<JsonVariant>().set(value);
|
||||
char buffer[256] = "";
|
||||
size_t returnValue = serializeJson(doc, buffer, sizeof(buffer));
|
||||
REQUIRE(expected == buffer);
|
||||
REQUIRE(expected.size() == returnValue);
|
||||
}
|
||||
|
||||
TEST_CASE("serializeJson(JsonObjectSubscript)") {
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":42}");
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
std::string result;
|
||||
|
||||
serializeJson(obj["hello"], result);
|
||||
|
||||
REQUIRE(result == "42");
|
||||
}
|
||||
|
||||
TEST_CASE("serializeJson(JsonArraySubscript)") {
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "[42]");
|
||||
JsonArray arr = doc.as<JsonArray>();
|
||||
std::string result;
|
||||
|
||||
serializeJson(arr[0], result);
|
||||
|
||||
REQUIRE(result == "42");
|
||||
}
|
||||
|
||||
TEST_CASE("serializeJson(JsonVariantSubscript)") {
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "[42]");
|
||||
JsonVariant var = doc.as<JsonVariant>();
|
||||
std::string result;
|
||||
|
||||
serializeJson(var[0], result);
|
||||
|
||||
REQUIRE(result == "42");
|
||||
}
|
@ -11,16 +11,18 @@ TEST_CASE("operator<<(std::ostream)") {
|
||||
std::ostringstream os;
|
||||
|
||||
SECTION("JsonVariant containing false") {
|
||||
JsonVariant variant = false;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
variant.set(false);
|
||||
os << variant;
|
||||
|
||||
REQUIRE("false" == os.str());
|
||||
}
|
||||
|
||||
SECTION("JsonVariant containing string") {
|
||||
JsonVariant variant = "coucou";
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
variant.set("coucou");
|
||||
os << variant;
|
||||
|
||||
REQUIRE("\"coucou\"" == os.str());
|
||||
|
@ -5,7 +5,6 @@
|
||||
add_executable(JsonVariantTests
|
||||
as.cpp
|
||||
compare.cpp
|
||||
copy.cpp
|
||||
is.cpp
|
||||
isnull.cpp
|
||||
or.cpp
|
||||
|
@ -9,222 +9,225 @@
|
||||
static const char* null = 0;
|
||||
|
||||
TEST_CASE("JsonVariant::as()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("DoubleAsBool") {
|
||||
JsonVariant variant = 4.2;
|
||||
variant.set(4.2);
|
||||
REQUIRE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("DoubleAsCstr") {
|
||||
JsonVariant variant = 4.2;
|
||||
variant.set(4.2);
|
||||
REQUIRE_FALSE(variant.as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("DoubleAsString") {
|
||||
JsonVariant variant = 4.2;
|
||||
variant.set(4.2);
|
||||
REQUIRE(std::string("4.2") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("DoubleAsLong") {
|
||||
JsonVariant variant = 4.2;
|
||||
variant.set(4.2);
|
||||
REQUIRE(4L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("DoubleAsUnsigned") {
|
||||
JsonVariant variant = 4.2;
|
||||
variant.set(4.2);
|
||||
REQUIRE(4U == variant.as<unsigned>());
|
||||
}
|
||||
|
||||
SECTION("DoubleZeroAsBool") {
|
||||
JsonVariant variant = 0.0;
|
||||
variant.set(0.0);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("DoubleZeroAsLong") {
|
||||
JsonVariant variant = 0.0;
|
||||
variant.set(0.0);
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsBool") {
|
||||
JsonVariant variant = false;
|
||||
variant.set(false);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsDouble") {
|
||||
JsonVariant variant = false;
|
||||
variant.set(false);
|
||||
REQUIRE(0.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsLong") {
|
||||
JsonVariant variant = false;
|
||||
variant.set(false);
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsString") {
|
||||
JsonVariant variant = false;
|
||||
variant.set(false);
|
||||
REQUIRE(std::string("false") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("TrueAsBool") {
|
||||
JsonVariant variant = true;
|
||||
variant.set(true);
|
||||
REQUIRE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("TrueAsDouble") {
|
||||
JsonVariant variant = true;
|
||||
variant.set(true);
|
||||
REQUIRE(1.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("TrueAsLong") {
|
||||
JsonVariant variant = true;
|
||||
variant.set(true);
|
||||
REQUIRE(1L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("TrueAsString") {
|
||||
JsonVariant variant = true;
|
||||
variant.set(true);
|
||||
REQUIRE(std::string("true") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("LongAsBool") {
|
||||
JsonVariant variant = 42L;
|
||||
variant.set(42L);
|
||||
REQUIRE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("LongZeroAsBool") {
|
||||
JsonVariant variant = 0L;
|
||||
variant.set(0L);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("PositiveLongAsDouble") {
|
||||
JsonVariant variant = 42L;
|
||||
variant.set(42L);
|
||||
REQUIRE(42.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("NegativeLongAsDouble") {
|
||||
JsonVariant variant = -42L;
|
||||
variant.set(-42L);
|
||||
REQUIRE(-42.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("LongAsString") {
|
||||
JsonVariant variant = 42L;
|
||||
variant.set(42L);
|
||||
REQUIRE(std::string("42") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("LongZeroAsDouble") {
|
||||
JsonVariant variant = 0L;
|
||||
variant.set(0L);
|
||||
REQUIRE(0.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("NullAsBool") {
|
||||
JsonVariant variant = null;
|
||||
variant.set(null);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("NullAsDouble") {
|
||||
JsonVariant variant = null;
|
||||
variant.set(null);
|
||||
REQUIRE(0.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("NullAsLong") {
|
||||
JsonVariant variant = null;
|
||||
variant.set(null);
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("NullAsString") {
|
||||
JsonVariant variant = null;
|
||||
variant.set(null);
|
||||
REQUIRE(std::string("null") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("NumberStringAsBool") {
|
||||
JsonVariant variant = "42";
|
||||
variant.set("42");
|
||||
REQUIRE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("NumberStringAsLong") {
|
||||
JsonVariant variant = "42";
|
||||
variant.set("42");
|
||||
REQUIRE(42L == variant.as<long>());
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
|
||||
SECTION("NumberStringAsInt64Negative") {
|
||||
JsonVariant variant = "-9223372036854775808";
|
||||
variant.set("-9223372036854775808");
|
||||
REQUIRE(-9223372036854775807 - 1 == variant.as<long long>());
|
||||
}
|
||||
|
||||
SECTION("NumberStringAsInt64Positive") {
|
||||
JsonVariant variant = "9223372036854775807";
|
||||
variant.set("9223372036854775807");
|
||||
REQUIRE(9223372036854775807 == variant.as<long long>());
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("RandomStringAsBool") {
|
||||
JsonVariant variant = "hello";
|
||||
variant.set("hello");
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsLong") {
|
||||
JsonVariant variant = "hello";
|
||||
variant.set("hello");
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsConstCharPtr") {
|
||||
JsonVariant variant = "hello";
|
||||
variant.set("hello");
|
||||
REQUIRE(std::string("hello") == variant.as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsCharPtr") {
|
||||
JsonVariant variant = "hello";
|
||||
variant.set("hello");
|
||||
REQUIRE(std::string("hello") == variant.as<char*>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsString") {
|
||||
JsonVariant variant = "hello";
|
||||
variant.set("hello");
|
||||
REQUIRE(std::string("hello") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("TrueStringAsBool") {
|
||||
JsonVariant variant = "true";
|
||||
variant.set("true");
|
||||
REQUIRE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("TrueStringAsLong") {
|
||||
JsonVariant variant = "true";
|
||||
variant.set("true");
|
||||
REQUIRE(1L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("ObjectAsString") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
obj["key"] = "value";
|
||||
|
||||
JsonVariant variant = obj;
|
||||
variant.set(obj);
|
||||
REQUIRE(std::string("{\"key\":\"value\"}") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("ArrayAsString") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray arr = doc.to<JsonArray>();
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
arr.add(4);
|
||||
arr.add(2);
|
||||
|
||||
JsonVariant variant = arr;
|
||||
variant.set(arr);
|
||||
REQUIRE(std::string("[4,2]") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("ArrayAsJsonArray") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray arr = doc.to<JsonArray>();
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
|
||||
JsonVariant variant = arr;
|
||||
variant.set(arr);
|
||||
REQUIRE(arr == variant.as<JsonArray>());
|
||||
REQUIRE(arr == variant.as<JsonArray>()); // <- shorthand
|
||||
}
|
||||
|
||||
SECTION("ObjectAsJsonObject") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
JsonVariant variant = obj;
|
||||
variant.set(obj);
|
||||
REQUIRE(obj == variant.as<JsonObject>());
|
||||
REQUIRE(obj == variant.as<JsonObject>()); // <- shorthand
|
||||
}
|
||||
|
@ -8,46 +8,58 @@
|
||||
static const char* null = 0;
|
||||
|
||||
template <typename T>
|
||||
void checkEquals(JsonVariant a, T b) {
|
||||
REQUIRE(b == a);
|
||||
REQUIRE(a == b);
|
||||
REQUIRE(b <= a);
|
||||
REQUIRE(a <= b);
|
||||
REQUIRE(b >= a);
|
||||
REQUIRE(a >= b);
|
||||
void checkEquals(T a, T b) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set(a);
|
||||
|
||||
REQUIRE_FALSE(b != a);
|
||||
REQUIRE_FALSE(a != b);
|
||||
REQUIRE_FALSE(b > a);
|
||||
REQUIRE_FALSE(a > b);
|
||||
REQUIRE_FALSE(b < a);
|
||||
REQUIRE_FALSE(a < b);
|
||||
REQUIRE(b == variant);
|
||||
REQUIRE(variant == b);
|
||||
REQUIRE(b <= variant);
|
||||
REQUIRE(variant <= b);
|
||||
REQUIRE(b >= variant);
|
||||
REQUIRE(variant >= b);
|
||||
|
||||
REQUIRE_FALSE(b != variant);
|
||||
REQUIRE_FALSE(variant != b);
|
||||
REQUIRE_FALSE(b > variant);
|
||||
REQUIRE_FALSE(variant > b);
|
||||
REQUIRE_FALSE(b < variant);
|
||||
REQUIRE_FALSE(variant < b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void checkGreater(JsonVariant a, T b) {
|
||||
REQUIRE(a > b);
|
||||
REQUIRE(b < a);
|
||||
REQUIRE(a != b);
|
||||
REQUIRE(b != a);
|
||||
void checkGreater(T a, T b) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set(a);
|
||||
|
||||
REQUIRE_FALSE(a < b);
|
||||
REQUIRE_FALSE(b > a);
|
||||
REQUIRE_FALSE(a == b);
|
||||
REQUIRE_FALSE(b == a);
|
||||
REQUIRE(variant > b);
|
||||
REQUIRE(b < variant);
|
||||
REQUIRE(variant != b);
|
||||
REQUIRE(b != variant);
|
||||
|
||||
REQUIRE_FALSE(variant < b);
|
||||
REQUIRE_FALSE(b > variant);
|
||||
REQUIRE_FALSE(variant == b);
|
||||
REQUIRE_FALSE(b == variant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void checkLower(JsonVariant a, T b) {
|
||||
REQUIRE(a < b);
|
||||
REQUIRE(b > a);
|
||||
REQUIRE(a != b);
|
||||
REQUIRE(b != a);
|
||||
void checkLower(T a, T b) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set(a);
|
||||
|
||||
REQUIRE_FALSE(a > b);
|
||||
REQUIRE_FALSE(b < a);
|
||||
REQUIRE_FALSE(a == b);
|
||||
REQUIRE_FALSE(b == a);
|
||||
REQUIRE(variant < b);
|
||||
REQUIRE(b > variant);
|
||||
REQUIRE(variant != b);
|
||||
REQUIRE(b != variant);
|
||||
|
||||
REQUIRE_FALSE(variant > b);
|
||||
REQUIRE_FALSE(b < variant);
|
||||
REQUIRE_FALSE(variant == b);
|
||||
REQUIRE_FALSE(b == variant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -99,7 +111,9 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("null") {
|
||||
JsonVariant variant = null;
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set(null);
|
||||
|
||||
REQUIRE(variant == variant);
|
||||
REQUIRE_FALSE(variant != variant);
|
||||
@ -139,7 +153,9 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("String") {
|
||||
JsonVariant variant = "hello";
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set("hello");
|
||||
|
||||
REQUIRE(variant == variant);
|
||||
REQUIRE_FALSE(variant != variant);
|
||||
@ -163,10 +179,47 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
REQUIRE_FALSE(null == variant);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA equals") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set("hello");
|
||||
|
||||
REQUIRE((vla == variant));
|
||||
REQUIRE((variant == vla));
|
||||
REQUIRE_FALSE((vla != variant));
|
||||
REQUIRE_FALSE((variant != vla));
|
||||
}
|
||||
|
||||
SECTION("VLA differs") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set("world");
|
||||
|
||||
REQUIRE((vla != variant));
|
||||
REQUIRE((variant != vla));
|
||||
REQUIRE_FALSE((vla == variant));
|
||||
REQUIRE_FALSE((variant == vla));
|
||||
}
|
||||
#endif
|
||||
|
||||
DynamicJsonDocument doc1, doc2, doc3;
|
||||
JsonVariant variant1 = doc1.to<JsonVariant>();
|
||||
JsonVariant variant2 = doc2.to<JsonVariant>();
|
||||
JsonVariant variant3 = doc3.to<JsonVariant>();
|
||||
|
||||
SECTION("IntegerInVariant") {
|
||||
JsonVariant variant1 = 42;
|
||||
JsonVariant variant2 = 42;
|
||||
JsonVariant variant3 = 666;
|
||||
variant1.set(42);
|
||||
variant2.set(42);
|
||||
variant3.set(666);
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
REQUIRE_FALSE(variant1 != variant2);
|
||||
@ -176,9 +229,9 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("StringInVariant") {
|
||||
JsonVariant variant1 = "0hello" + 1; // make sure they have
|
||||
JsonVariant variant2 = "1hello" + 1; // different addresses
|
||||
JsonVariant variant3 = "world";
|
||||
variant1.set("0hello" + 1); // make sure they have
|
||||
variant2.set("1hello" + 1); // different addresses
|
||||
variant3.set("world");
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
REQUIRE_FALSE(variant1 != variant2);
|
||||
@ -188,9 +241,9 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("DoubleInVariant") {
|
||||
JsonVariant variant1 = 42.0;
|
||||
JsonVariant variant2 = 42.0;
|
||||
JsonVariant variant3 = 666.0;
|
||||
variant1.set(42.0);
|
||||
variant2.set(42.0);
|
||||
variant3.set(666.0);
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
REQUIRE_FALSE(variant1 != variant2);
|
||||
@ -200,9 +253,9 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("BoolInVariant") {
|
||||
JsonVariant variant1 = true;
|
||||
JsonVariant variant2 = true;
|
||||
JsonVariant variant3 = false;
|
||||
variant1.set(true);
|
||||
variant2.set(true);
|
||||
variant3.set(false);
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
REQUIRE_FALSE(variant1 != variant2);
|
||||
@ -212,14 +265,13 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("ArrayInVariant") {
|
||||
DynamicJsonDocument doc1;
|
||||
JsonArray array1 = doc1.to<JsonArray>();
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray array2 = doc2.to<JsonArray>();
|
||||
DynamicJsonDocument docArr1, docArr2;
|
||||
JsonArray array1 = docArr1.to<JsonArray>();
|
||||
JsonArray array2 = docArr2.to<JsonArray>();
|
||||
|
||||
JsonVariant variant1 = array1;
|
||||
JsonVariant variant2 = array1;
|
||||
JsonVariant variant3 = array2;
|
||||
variant1.set(array1);
|
||||
variant2.set(array1);
|
||||
variant3.set(array2);
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
REQUIRE_FALSE(variant1 != variant2);
|
||||
@ -229,14 +281,13 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("ObjectInVariant") {
|
||||
DynamicJsonDocument doc1;
|
||||
JsonObject obj1 = doc1.to<JsonObject>();
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj2 = doc2.to<JsonObject>();
|
||||
DynamicJsonDocument docObj1, docObj2;
|
||||
JsonObject obj1 = docObj1.to<JsonObject>();
|
||||
JsonObject obj2 = docObj2.to<JsonObject>();
|
||||
|
||||
JsonVariant variant1 = obj1;
|
||||
JsonVariant variant2 = obj1;
|
||||
JsonVariant variant3 = obj2;
|
||||
variant1.set(obj1);
|
||||
variant2.set(obj1);
|
||||
variant3.set(obj2);
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
REQUIRE_FALSE(variant1 != variant2);
|
||||
@ -245,22 +296,22 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
REQUIRE_FALSE(variant1 == variant3);
|
||||
}
|
||||
|
||||
SECTION("VariantsOfDifferentTypes") {
|
||||
DynamicJsonDocument doc1;
|
||||
JsonObject obj = doc1.to<JsonObject>();
|
||||
// SECTION("VariantsOfDifferentTypes") {
|
||||
// DynamicJsonDocument doc1;
|
||||
// JsonObject obj = doc1.to<JsonObject>();
|
||||
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
JsonVariant variants[] = {
|
||||
true, 42, 666.667, "hello", arr, obj,
|
||||
};
|
||||
size_t n = sizeof(variants) / sizeof(variants[0]);
|
||||
// DynamicJsonDocument doc2;
|
||||
// JsonArray arr = doc2.to<JsonArray>();
|
||||
// JsonVariant variants[] = {
|
||||
// true, 42, 666.667, "hello", arr, obj,
|
||||
// };
|
||||
// size_t n = sizeof(variants) / sizeof(variants[0]);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
for (size_t j = i + 1; j < n; j++) {
|
||||
REQUIRE(variants[i] != variants[j]);
|
||||
REQUIRE_FALSE(variants[i] == variants[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// for (size_t i = 0; i < n; i++) {
|
||||
// for (size_t j = i + 1; j < n; j++) {
|
||||
// REQUIRE(variants[i] != variants[j]);
|
||||
// REQUIRE_FALSE(variants[i] == variants[j]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonVariant copy") {
|
||||
JsonVariant _variant1;
|
||||
JsonVariant _variant2;
|
||||
|
||||
SECTION("IntegersAreCopiedByValue") {
|
||||
_variant1 = 123;
|
||||
_variant2 = _variant1;
|
||||
_variant1 = 456;
|
||||
|
||||
REQUIRE(123 == _variant2.as<int>());
|
||||
}
|
||||
|
||||
SECTION("DoublesAreCopiedByValue") {
|
||||
_variant1 = 123.45;
|
||||
_variant2 = _variant1;
|
||||
_variant1 = 456.78;
|
||||
|
||||
REQUIRE(123.45 == _variant2.as<double>());
|
||||
}
|
||||
|
||||
SECTION("BooleansAreCopiedByValue") {
|
||||
_variant1 = true;
|
||||
_variant2 = _variant1;
|
||||
_variant1 = false;
|
||||
|
||||
REQUIRE(_variant2.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("StringsAreCopiedByValue") {
|
||||
_variant1 = "hello";
|
||||
_variant2 = _variant1;
|
||||
_variant1 = "world";
|
||||
|
||||
REQUIRE(std::string("hello") == _variant2.as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("ObjectsAreCopiedByReference") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject object = doc.to<JsonObject>();
|
||||
|
||||
_variant1 = object;
|
||||
|
||||
object["hello"] = "world";
|
||||
|
||||
REQUIRE(1 == _variant1.as<JsonObject>().size());
|
||||
}
|
||||
|
||||
SECTION("ArraysAreCopiedByReference") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
|
||||
_variant1 = array;
|
||||
|
||||
array.add("world");
|
||||
|
||||
REQUIRE(1 == _variant1.as<JsonArray>().size());
|
||||
}
|
||||
}
|
@ -5,7 +5,11 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
void checkIsArray(JsonVariant var) {
|
||||
void checkIsArray(JsonArray value) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
var.set(value);
|
||||
|
||||
REQUIRE(var.is<JsonArray>());
|
||||
REQUIRE(var.is<JsonArray>());
|
||||
REQUIRE(var.is<const JsonArray>());
|
||||
@ -16,48 +20,65 @@ void checkIsArray(JsonVariant var) {
|
||||
REQUIRE_FALSE(var.is<float>());
|
||||
REQUIRE_FALSE(var.is<int>());
|
||||
REQUIRE_FALSE(var.is<long>());
|
||||
REQUIRE_FALSE(var.is<const char*>());
|
||||
REQUIRE_FALSE(var.is<const char *>());
|
||||
REQUIRE_FALSE(var.is<JsonObject>());
|
||||
}
|
||||
|
||||
void checkIsBool(JsonVariant var) {
|
||||
void checkIsBool(bool value) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
var.set(value);
|
||||
|
||||
REQUIRE(var.is<bool>());
|
||||
|
||||
REQUIRE_FALSE(var.is<double>());
|
||||
REQUIRE_FALSE(var.is<float>());
|
||||
REQUIRE_FALSE(var.is<int>());
|
||||
REQUIRE_FALSE(var.is<long>());
|
||||
REQUIRE_FALSE(var.is<const char*>());
|
||||
REQUIRE_FALSE(var.is<const char *>());
|
||||
REQUIRE_FALSE(var.is<JsonArray>());
|
||||
REQUIRE_FALSE(var.is<JsonObject>());
|
||||
}
|
||||
|
||||
void checkIsFloat(JsonVariant var) {
|
||||
void checkIsFloat(double value) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
var.set(value);
|
||||
|
||||
REQUIRE(var.is<double>());
|
||||
REQUIRE(var.is<float>());
|
||||
|
||||
REQUIRE_FALSE(var.is<bool>());
|
||||
REQUIRE_FALSE(var.is<int>());
|
||||
REQUIRE_FALSE(var.is<long>());
|
||||
REQUIRE_FALSE(var.is<const char*>());
|
||||
REQUIRE_FALSE(var.is<const char *>());
|
||||
REQUIRE_FALSE(var.is<JsonArray>());
|
||||
REQUIRE_FALSE(var.is<JsonObject>());
|
||||
}
|
||||
|
||||
void checkIsInteger(JsonVariant var) {
|
||||
template <typename T>
|
||||
void checkIsInteger(T value) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
var.set(value);
|
||||
|
||||
REQUIRE(var.is<long>());
|
||||
REQUIRE(var.is<int>());
|
||||
REQUIRE(var.is<float>());
|
||||
REQUIRE(var.is<double>());
|
||||
|
||||
REQUIRE_FALSE(var.is<bool>());
|
||||
REQUIRE_FALSE(var.is<const char*>());
|
||||
REQUIRE_FALSE(var.is<const char *>());
|
||||
REQUIRE_FALSE(var.is<JsonArray>());
|
||||
REQUIRE_FALSE(var.is<JsonObject>());
|
||||
}
|
||||
|
||||
void checkIsString(JsonVariant var) {
|
||||
REQUIRE(var.is<const char*>());
|
||||
void checkIsString(const char *value) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
var.set(value);
|
||||
|
||||
REQUIRE(var.is<const char *>());
|
||||
|
||||
REQUIRE_FALSE(var.is<bool>());
|
||||
REQUIRE_FALSE(var.is<int>());
|
||||
|
@ -6,39 +6,42 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonVariant::isNull()") {
|
||||
SECTION("ReturnsFalse_WhenUndefined") {
|
||||
JsonVariant variant;
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("return true when Undefined") {
|
||||
REQUIRE(variant.isNull() == true);
|
||||
}
|
||||
|
||||
SECTION("ReturnsTrue_WhenInteger") {
|
||||
JsonVariant variant = 0;
|
||||
SECTION("return false when Integer") {
|
||||
variant.set(42);
|
||||
|
||||
REQUIRE(variant.isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("ReturnsTrue_WhenEmptyArray") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
SECTION("return false when EmptyArray") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray array = doc2.to<JsonArray>();
|
||||
|
||||
JsonVariant variant = array;
|
||||
variant.set(array);
|
||||
REQUIRE(variant.isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("ReturnsTrue_WhenEmptyObject") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
SECTION("return false when EmptyObject") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
JsonVariant variant = obj;
|
||||
variant.set(obj);
|
||||
REQUIRE(variant.isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("ReturnsFalse_WhenInvalidArray") {
|
||||
JsonVariant variant = JsonArray();
|
||||
SECTION("return true when InvalidArray") {
|
||||
variant.set(JsonArray());
|
||||
REQUIRE(variant.isNull() == true);
|
||||
}
|
||||
|
||||
SECTION("ReturnsFalse_WhenInvalidObject") {
|
||||
JsonVariant variant = JsonObject();
|
||||
SECTION("return true when InvalidObject") {
|
||||
variant.set(JsonObject());
|
||||
REQUIRE(variant.isNull() == true);
|
||||
}
|
||||
}
|
||||
|
@ -5,78 +5,84 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
static const JsonVariant undefined;
|
||||
static const JsonVariant null = static_cast<const char*>(0);
|
||||
|
||||
TEST_CASE("JsonVariant::operator|()") {
|
||||
SECTION("undefined | const char*") {
|
||||
std::string result = undefined | "default";
|
||||
REQUIRE(result == "default");
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("undefined") {
|
||||
SECTION("undefined | const char*") {
|
||||
std::string result = variant | "default";
|
||||
REQUIRE(result == "default");
|
||||
}
|
||||
|
||||
SECTION("undefined | int") {
|
||||
int result = variant | 42;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
||||
SECTION("undefined | bool") {
|
||||
bool result = variant | true;
|
||||
REQUIRE(result == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("undefined | int") {
|
||||
int result = undefined | 42;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
SECTION("null") {
|
||||
variant.set(static_cast<const char*>(0));
|
||||
|
||||
SECTION("undefined | bool") {
|
||||
bool result = undefined | true;
|
||||
REQUIRE(result == true);
|
||||
}
|
||||
SECTION("null | const char*") {
|
||||
std::string result = variant | "default";
|
||||
REQUIRE(result == "default");
|
||||
}
|
||||
|
||||
SECTION("null | const char*") {
|
||||
std::string result = null | "default";
|
||||
REQUIRE(result == "default");
|
||||
}
|
||||
SECTION("null | int") {
|
||||
int result = variant | 42;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
||||
SECTION("null | int") {
|
||||
int result = null | 42;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
||||
SECTION("null | bool") {
|
||||
bool result = null | true;
|
||||
REQUIRE(result == true);
|
||||
SECTION("null | bool") {
|
||||
bool result = variant | true;
|
||||
REQUIRE(result == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("int | const char*") {
|
||||
JsonVariant variant = 42;
|
||||
variant.set(42);
|
||||
std::string result = variant | "default";
|
||||
REQUIRE(result == "default");
|
||||
}
|
||||
|
||||
SECTION("int | int") {
|
||||
JsonVariant variant = 0;
|
||||
variant.set(0);
|
||||
int result = variant | 666;
|
||||
REQUIRE(result == 0);
|
||||
}
|
||||
|
||||
SECTION("double | int") {
|
||||
JsonVariant variant = 42.0;
|
||||
variant.set(42.0);
|
||||
int result = variant | 666;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
||||
SECTION("bool | bool") {
|
||||
JsonVariant variant = false;
|
||||
variant.set(false);
|
||||
bool result = variant | true;
|
||||
REQUIRE(result == false);
|
||||
}
|
||||
|
||||
SECTION("int | bool") {
|
||||
JsonVariant variant = 0;
|
||||
variant.set(0);
|
||||
bool result = variant | true;
|
||||
REQUIRE(result == true);
|
||||
}
|
||||
|
||||
SECTION("const char* | const char*") {
|
||||
JsonVariant variant = "not default";
|
||||
variant.set("not default");
|
||||
std::string result = variant | "default";
|
||||
REQUIRE(result == "not default");
|
||||
}
|
||||
|
||||
SECTION("const char* | int") {
|
||||
JsonVariant variant = "not default";
|
||||
variant.set("not default");
|
||||
int result = variant | 42;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
@ -9,7 +9,10 @@
|
||||
|
||||
template <typename T>
|
||||
void checkValue(T expected) {
|
||||
JsonVariant variant = expected;
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
variant.set(expected);
|
||||
REQUIRE(expected == variant.as<T>());
|
||||
}
|
||||
|
||||
@ -21,11 +24,15 @@ void checkReference(T &expected) {
|
||||
|
||||
template <typename T>
|
||||
void checkNumericType() {
|
||||
DynamicJsonDocument docMin, docMax;
|
||||
JsonVariant variantMin = docMin.to<JsonVariant>();
|
||||
JsonVariant variantMax = docMax.to<JsonVariant>();
|
||||
|
||||
T min = std::numeric_limits<T>::min();
|
||||
T max = std::numeric_limits<T>::max();
|
||||
|
||||
JsonVariant variantMin(min);
|
||||
JsonVariant variantMax(max);
|
||||
variantMin.set(min);
|
||||
variantMax.set(max);
|
||||
|
||||
REQUIRE(min == variantMin.as<T>());
|
||||
REQUIRE(max == variantMax.as<T>());
|
||||
@ -41,9 +48,12 @@ TEST_CASE("JsonVariant set()/get()") {
|
||||
SECTION("Null") {
|
||||
checkValue<const char *>(NULL);
|
||||
}
|
||||
SECTION("String") {
|
||||
SECTION("const char*") {
|
||||
checkValue<const char *>("hello");
|
||||
}
|
||||
SECTION("std::string") {
|
||||
checkValue<std::string>("hello");
|
||||
}
|
||||
|
||||
SECTION("False") {
|
||||
checkValue<bool>(false);
|
||||
@ -128,3 +138,74 @@ TEST_CASE("JsonVariant set()/get()") {
|
||||
checkValue<JsonObject>(object);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant and strings") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("stores const char* by reference") {
|
||||
char str[16];
|
||||
|
||||
strcpy(str, "hello");
|
||||
variant.set(static_cast<const char *>(str));
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(variant == "world");
|
||||
}
|
||||
|
||||
SECTION("stores char* by copy") {
|
||||
char str[16];
|
||||
|
||||
strcpy(str, "hello");
|
||||
variant.set(str);
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(variant == "hello");
|
||||
}
|
||||
|
||||
SECTION("stores unsigned char* by copy") {
|
||||
char str[16];
|
||||
|
||||
strcpy(str, "hello");
|
||||
variant.set(reinterpret_cast<unsigned char *>(str));
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(variant == "hello");
|
||||
}
|
||||
|
||||
SECTION("stores signed char* by copy") {
|
||||
char str[16];
|
||||
|
||||
strcpy(str, "hello");
|
||||
variant.set(reinterpret_cast<signed char *>(str));
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(variant == "hello");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("stores VLA by copy") {
|
||||
int n = 16;
|
||||
char str[n];
|
||||
|
||||
strcpy(str, "hello");
|
||||
variant.set(str);
|
||||
strcpy(str, "world");
|
||||
|
||||
REQUIRE(variant == "hello");
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("stores std::string by copy") {
|
||||
std::string str;
|
||||
|
||||
str = "hello";
|
||||
variant.set(str);
|
||||
str.replace(0, 5, "world");
|
||||
|
||||
REQUIRE(variant == "hello");
|
||||
}
|
||||
|
||||
// TODO: string
|
||||
// TODO: serialized()
|
||||
}
|
||||
|
@ -6,24 +6,26 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonVariant::operator[]") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("The JsonVariant is undefined") {
|
||||
JsonVariant var = JsonVariant();
|
||||
REQUIRE(0 == var.size());
|
||||
REQUIRE(var["0"].isNull());
|
||||
REQUIRE(var[0].isNull());
|
||||
}
|
||||
|
||||
SECTION("The JsonVariant is a string") {
|
||||
JsonVariant var = "hello world";
|
||||
var.set("hello world");
|
||||
REQUIRE(0 == var.size());
|
||||
REQUIRE(var["0"].isNull());
|
||||
REQUIRE(var[0].isNull());
|
||||
}
|
||||
|
||||
SECTION("The JsonVariant is a JsonArray") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
JsonVariant var = array;
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray array = doc2.to<JsonArray>();
|
||||
var.set(array);
|
||||
|
||||
SECTION("get value") {
|
||||
array.add("element at index 0");
|
||||
@ -60,9 +62,9 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("The JsonVariant is a JsonObject") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject object = doc.to<JsonObject>();
|
||||
JsonVariant var = object;
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject object = doc2.to<JsonObject>();
|
||||
var.set(object);
|
||||
|
||||
SECTION("get value") {
|
||||
object["a"] = "element at key \"a\"";
|
||||
@ -91,4 +93,29 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
REQUIRE(std::string("world") == var["hello"]);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
|
||||
SECTION("key is a VLA") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[vla]);
|
||||
}
|
||||
|
||||
SECTION("key is a VLA, const JsonVariant") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
const JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[vla]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ add_executable(MiscTests
|
||||
TypeTraits.cpp
|
||||
unsigned_char.cpp
|
||||
version.cpp
|
||||
vla.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(MiscTests catch)
|
||||
|
@ -29,19 +29,13 @@ TEST_CASE("unsigned char[]") {
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
SECTION("constructor") {
|
||||
DynamicJsonDocument doc;
|
||||
|
||||
SECTION("set") {
|
||||
unsigned char value[] = "42";
|
||||
|
||||
JsonVariant variant(value);
|
||||
|
||||
REQUIRE(42 == variant.as<int>());
|
||||
}
|
||||
|
||||
SECTION("operator=") {
|
||||
unsigned char value[] = "42";
|
||||
|
||||
JsonVariant variant(666);
|
||||
variant = value;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set(value);
|
||||
|
||||
REQUIRE(42 == variant.as<int>());
|
||||
}
|
||||
@ -50,7 +44,6 @@ TEST_CASE("unsigned char[]") {
|
||||
SECTION("operator[]") {
|
||||
unsigned char key[] = "hello";
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
@ -62,7 +55,6 @@ TEST_CASE("unsigned char[]") {
|
||||
SECTION("operator[] const") {
|
||||
unsigned char key[] = "hello";
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
const JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
@ -73,8 +65,8 @@ TEST_CASE("unsigned char[]") {
|
||||
SECTION("operator==") {
|
||||
unsigned char comparand[] = "hello";
|
||||
|
||||
JsonVariant variant;
|
||||
variant = "hello";
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set("hello");
|
||||
|
||||
REQUIRE(comparand == variant);
|
||||
REQUIRE(variant == comparand);
|
||||
@ -85,8 +77,8 @@ TEST_CASE("unsigned char[]") {
|
||||
SECTION("operator!=") {
|
||||
unsigned char comparand[] = "hello";
|
||||
|
||||
JsonVariant variant;
|
||||
variant = "world";
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set("world");
|
||||
|
||||
REQUIRE(comparand != variant);
|
||||
REQUIRE(variant != comparand);
|
||||
|
@ -1,337 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wvla-extension"
|
||||
#define CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wvla"
|
||||
#else
|
||||
#define VLA_NOT_SUPPORTED
|
||||
#endif
|
||||
|
||||
#ifndef VLA_NOT_SUPPORTED
|
||||
|
||||
TEST_CASE("Variable Length Array") {
|
||||
SECTION("deserializeJson()") {
|
||||
int i = 9;
|
||||
char vla[i];
|
||||
strcpy(vla, "{\"a\":42}");
|
||||
|
||||
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
|
||||
DeserializationError err = deserializeJson(doc, vla);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("deserializeMsgPack()") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15);
|
||||
|
||||
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
|
||||
DeserializationError err = deserializeMsgPack(doc, vla);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
SECTION("constructor") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "42");
|
||||
|
||||
JsonVariant variant(vla);
|
||||
|
||||
REQUIRE(42 == variant.as<int>());
|
||||
}
|
||||
|
||||
SECTION("operator=") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "42");
|
||||
|
||||
JsonVariant variant(666);
|
||||
variant = vla;
|
||||
|
||||
REQUIRE(42 == variant.as<int>());
|
||||
}
|
||||
|
||||
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
SECTION("operator[]") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[vla]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
SECTION("operator[] const") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
const JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[vla]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("operator==") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
JsonVariant variant;
|
||||
variant = "hello";
|
||||
|
||||
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("JsonObject") {
|
||||
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
SECTION("operator[]") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj[vla] = "world";
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
SECTION("operator[] const") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
REQUIRE(std::string("world") == obj[vla]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("get()") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
|
||||
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("JsonObjectSubscript") {
|
||||
SECTION("operator=") { // issue #416
|
||||
int i = 32;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = vla;
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"].as<char*>());
|
||||
}
|
||||
|
||||
SECTION("set()") {
|
||||
int i = 32;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"].set(vla);
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"].as<char*>());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("JsonArray") {
|
||||
SECTION("add()") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
DynamicJsonDocument doc;
|
||||
JsonArray arr = doc.to<JsonArray>();
|
||||
arr.add(vla);
|
||||
|
||||
REQUIRE(std::string("world") == arr[0]);
|
||||
}
|
||||
|
||||
SECTION("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") {
|
||||
SECTION("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("operator=") {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -9,10 +9,9 @@ add_executable(MsgPackDeserializerTests
|
||||
deserializeVariant.cpp
|
||||
doubleToFloat.cpp
|
||||
incompleteInput.cpp
|
||||
input_types.cpp
|
||||
nestingLimit.cpp
|
||||
notSupported.cpp
|
||||
std_string.cpp
|
||||
std_istream.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(MsgPackDeserializerTests catch)
|
||||
|
@ -16,10 +16,18 @@ static void check(const char* input, U expected) {
|
||||
REQUIRE(variant.as<T>() == expected);
|
||||
}
|
||||
|
||||
static void checkIsNull(const char* input) {
|
||||
DynamicJsonDocument variant;
|
||||
|
||||
DeserializationError error = deserializeMsgPack(variant, input);
|
||||
|
||||
REQUIRE(error == DeserializationError::Ok);
|
||||
REQUIRE(variant.as<JsonVariant>().isNull());
|
||||
}
|
||||
|
||||
TEST_CASE("deserialize MsgPack value") {
|
||||
SECTION("nil") {
|
||||
const char* nil = 0; // ArduinoJson uses a string for null
|
||||
check<const char*>("\xc0", nil);
|
||||
checkIsNull("\xc0");
|
||||
}
|
||||
|
||||
SECTION("bool") {
|
||||
|
@ -44,3 +44,39 @@ TEST_CASE("deserializeMsgPack(const std::string&)") {
|
||||
REQUIRE(arr[1] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeMsgPack(std::istream&)") {
|
||||
DynamicJsonDocument doc;
|
||||
|
||||
SECTION("should accept a zero in input") {
|
||||
std::istringstream input(std::string("\x92\x00\x02", 3));
|
||||
|
||||
DeserializationError err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::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");
|
||||
|
||||
DeserializationError err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::IncompleteInput);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
TEST_CASE("deserializeMsgPack(VLA)") {
|
||||
int i = 16;
|
||||
char vla[i];
|
||||
memcpy(vla, "\xDE\x00\x01\xA5Hello\xA5world", 15);
|
||||
|
||||
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
|
||||
DeserializationError err = deserializeMsgPack(doc, vla);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
#endif
|
@ -1,29 +0,0 @@
|
||||
// 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));
|
||||
|
||||
DeserializationError err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::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");
|
||||
|
||||
DeserializationError err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::IncompleteInput);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
add_executable(MsgPackSerializerTests
|
||||
destination_types.cpp
|
||||
measure.cpp
|
||||
misc.cpp
|
||||
serializeArray.cpp
|
||||
serializeObject.cpp
|
||||
serializeVariant.cpp
|
||||
|
46
test/MsgPackSerializer/misc.cpp
Normal file
46
test/MsgPackSerializer/misc.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
template <typename T>
|
||||
void check(T value, const std::string &expected) {
|
||||
DynamicJsonDocument doc;
|
||||
doc.to<JsonVariant>().set(value);
|
||||
char buffer[256] = "";
|
||||
size_t returnValue = serializeMsgPack(doc, buffer, sizeof(buffer));
|
||||
REQUIRE(expected == buffer);
|
||||
REQUIRE(expected.size() == returnValue);
|
||||
}
|
||||
|
||||
TEST_CASE("serializeMsgPack(JsonObjectSubscript)") {
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":42}");
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
std::string result;
|
||||
|
||||
serializeMsgPack(obj["hello"], result);
|
||||
|
||||
REQUIRE(result == "*");
|
||||
}
|
||||
|
||||
TEST_CASE("serializeMsgPack(JsonArraySubscript)") {
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "[42]");
|
||||
JsonArray arr = doc.as<JsonArray>();
|
||||
std::string result;
|
||||
|
||||
serializeMsgPack(arr[0], result);
|
||||
|
||||
REQUIRE(result == "*");
|
||||
}
|
||||
|
||||
TEST_CASE("serializeMsgPack(JsonVariantSubscript)") {
|
||||
DynamicJsonDocument doc;
|
||||
deserializeJson(doc, "[42]");
|
||||
JsonVariant var = doc.as<JsonVariant>();
|
||||
std::string result;
|
||||
|
||||
serializeMsgPack(var[0], result);
|
||||
|
||||
REQUIRE(result == "*");
|
||||
}
|
@ -5,8 +5,11 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
void check(JsonVariant variant, const char* expected_data,
|
||||
size_t expected_len) {
|
||||
template <typename T>
|
||||
void check(T value, const char* expected_data, size_t expected_len) {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
variant.set(value);
|
||||
std::string expected(expected_data, expected_data + expected_len);
|
||||
std::string actual;
|
||||
size_t len = serializeMsgPack(variant, actual);
|
||||
@ -15,14 +18,15 @@ void check(JsonVariant variant, const char* expected_data,
|
||||
REQUIRE(actual == expected);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void check(JsonVariant variant, const char (&expected_data)[N]) {
|
||||
template <typename T, size_t N>
|
||||
void check(T value, const char (&expected_data)[N]) {
|
||||
const size_t expected_len = N - 1;
|
||||
check(variant, expected_data, expected_len);
|
||||
check(value, expected_data, expected_len);
|
||||
}
|
||||
|
||||
void check(JsonVariant variant, const std::string& expected) {
|
||||
check(variant, expected.data(), expected.length());
|
||||
template <typename T>
|
||||
void check(T value, const std::string& expected) {
|
||||
check(value, expected.data(), expected.length());
|
||||
}
|
||||
|
||||
TEST_CASE("serialize MsgPack value") {
|
||||
|
Reference in New Issue
Block a user