diff --git a/CHANGELOG.md b/CHANGELOG.md index 4faf0572..a3757bd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,56 @@ ArduinoJson: change log ======================= +HEAD +---- + +* Implemented reference semantics for `JsonVariant` +* Replace `JsonPair`'s `key` and `value` with `key()` and `value()` + +> ### 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(); +> myValue.set(42); +> ``` +> +> #### JsonPair +> +> Old code: +> +> ```c++ +> for(JsonPair p : myObject) { +> Serial.println(p.key); +> Serial.println(p.value.as()); +> } +> ``` +> +> New code: +> +> ```c++ +> for(JsonPair p : myObject) { +> Serial.println(p.key()); +> Serial.println(p.value().as()); +> } +> ``` +> +> CAUTION: the key is now read only! + v6.2.3-beta ----------- diff --git a/src/ArduinoJson/Data/JsonVariantContent.hpp b/src/ArduinoJson/Data/JsonVariantContent.hpp index 97a84a0c..389c5379 100644 --- a/src/ArduinoJson/Data/JsonVariantContent.hpp +++ b/src/ArduinoJson/Data/JsonVariantContent.hpp @@ -4,6 +4,8 @@ #pragma once +#include // size_t + #include "JsonFloat.hpp" #include "JsonInteger.hpp" diff --git a/src/ArduinoJson/Data/JsonVariantData.hpp b/src/ArduinoJson/Data/JsonVariantData.hpp new file mode 100644 index 00000000..81653cc7 --- /dev/null +++ b/src/ArduinoJson/Data/JsonVariantData.hpp @@ -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(value); + } + + void setFloat(JsonFloat value) { + type = JSON_FLOAT; + content.asFloat = value; + } + + void setInteger(JsonInteger value) { + if (value > 0) + setPostiveInteger(static_cast(value)); + else + setNegativeInteger(static_cast(-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 + 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(content.asString); + default: + return T(content.asFloat); + } + } + + template + T asFloat() const { + switch (type) { + case JSON_NULL: + case JSON_RAW: + return 0; + case JSON_POSITIVE_INTEGER: + case JSON_BOOLEAN: + return static_cast(content.asInteger); + case JSON_NEGATIVE_INTEGER: + return -static_cast(content.asInteger); + case JSON_STRING: + return parseFloat(content.asString); + default: + return static_cast(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 + 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 diff --git a/src/ArduinoJson/Data/JsonVariantDefault.hpp b/src/ArduinoJson/Data/JsonVariantDefault.hpp deleted file mode 100644 index 57ecc83e..00000000 --- a/src/ArduinoJson/Data/JsonVariantDefault.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -namespace ArduinoJson { -namespace Internals { - -template -struct JsonVariantDefault { - static T get() { - return T(); - } -}; - -template -struct JsonVariantDefault : JsonVariantDefault {}; - -template -struct JsonVariantDefault : JsonVariantDefault {}; -} -} diff --git a/src/ArduinoJson/Data/JsonVariantType.hpp b/src/ArduinoJson/Data/JsonVariantType.hpp index 838460a3..43d9e8d9 100644 --- a/src/ArduinoJson/Data/JsonVariantType.hpp +++ b/src/ArduinoJson/Data/JsonVariantType.hpp @@ -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 diff --git a/src/ArduinoJson/Data/List.hpp b/src/ArduinoJson/Data/List.hpp index 0982c012..5a1a91c3 100644 --- a/src/ArduinoJson/Data/List.hpp +++ b/src/ArduinoJson/Data/List.hpp @@ -22,7 +22,7 @@ class List { typedef ListIterator iterator; typedef ListConstIterator 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; diff --git a/src/ArduinoJson/Data/ValueSaver.hpp b/src/ArduinoJson/Data/ValueSaver.hpp deleted file mode 100644 index 5912629b..00000000 --- a/src/ArduinoJson/Data/ValueSaver.hpp +++ /dev/null @@ -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 -struct ValueSaver { - template - static bool save(JsonBuffer*, Destination& destination, Source source) { - destination = source; - return true; - } -}; - -// We duplicate all strings except const char* -template -struct ValueSaver< - TString, typename enable_if::value && - !is_same::value>::type> { - template - 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 except SerializedValue -template -struct ValueSaver< - const SerializedValue&, - typename enable_if::value>::type> { - template - static bool save(JsonBuffer* buffer, Destination& dest, - const SerializedValue& source) { - const char* dup = makeString(source.data(), source.size()).save(buffer); - if (!dup) return false; - dest = SerializedValue(dup, source.size()); - return true; - } -}; -} // namespace Internals -} // namespace ArduinoJson diff --git a/src/ArduinoJson/Deserialization/deserialize.hpp b/src/ArduinoJson/Deserialization/deserialize.hpp index 25abe9de..736e1bad 100644 --- a/src/ArduinoJson/Deserialization/deserialize.hpp +++ b/src/ArduinoJson/Deserialization/deserialize.hpp @@ -35,7 +35,7 @@ deserialize(TDocument &doc, const TString &input) { return makeDeserializer(&doc.buffer(), makeReader(input), makeStringStorage(doc.buffer(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } // // DeserializationError deserialize(TDocument& doc, TChar* input); @@ -48,7 +48,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input) { return makeDeserializer(&doc.buffer(), makeReader(input), makeStringStorage(doc.buffer(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } // // DeserializationError deserialize(TDocument& doc, TChar* input, size_t @@ -63,7 +63,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input, return makeDeserializer( &doc.buffer(), makeReader(input, inputSize), makeStringStorage(doc.buffer(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } // // DeserializationError deserialize(TDocument& doc, TStream input); @@ -76,7 +76,7 @@ DeserializationError deserialize(TDocument &doc, TStream &input) { return makeDeserializer(&doc.buffer(), makeReader(input), makeStringStorage(doc.buffer(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } } // namespace Internals } // namespace ArduinoJson diff --git a/src/ArduinoJson/DynamicJsonDocument.hpp b/src/ArduinoJson/DynamicJsonDocument.hpp index 4f5378e7..3da4f509 100644 --- a/src/ArduinoJson/DynamicJsonDocument.hpp +++ b/src/ArduinoJson/DynamicJsonDocument.hpp @@ -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 bool is() const { - return _root.is(); + return getVariant().is(); } template typename Internals::JsonVariantAs::type as() const { - return _root.as(); + return getVariant().as(); } // JsonObject to() @@ -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 to() template typename Internals::enable_if::value, - T&>::type + JsonVariant>::type to() { clear(); - return _root; + return getVariant(); + } + + // JsonVariantData& to() + template + typename Internals::enable_if< + Internals::is_same::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 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 diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index 6ab00779..465ce1af 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -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(buffer); + result.setInteger(parseInteger(buffer)); } else if (isFloat(buffer)) { - result = parseFloat(buffer); + result.setFloat(parseFloat(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(0); + result.setNull(); } else { return DeserializationError::InvalidInput; } diff --git a/src/ArduinoJson/Json/JsonSerializer.hpp b/src/ArduinoJson/Json/JsonSerializer.hpp index 97c21ab1..494075bc 100644 --- a/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/src/ArduinoJson/Json/JsonSerializer.hpp @@ -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(); diff --git a/src/ArduinoJson/JsonArray.hpp b/src/ArduinoJson/JsonArray.hpp index 2410a8c3..235bcda0 100644 --- a/src/ArduinoJson/JsonArray.hpp +++ b/src/ArduinoJson/JsonArray.hpp @@ -4,7 +4,8 @@ #pragma once -#include "./JsonArrayData.hpp" +#include "JsonArrayData.hpp" +#include "JsonArrayIterator.hpp" namespace ArduinoJson { @@ -18,13 +19,13 @@ 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)) {} + JsonArray() : _buffer(0), _data(0) {} + explicit JsonArray(Internals::JsonBuffer* buf, Internals::JsonArrayData* arr) + : _buffer(buf), _data(arr) {} + explicit JsonArray(Internals::JsonBuffer* buf) + : _buffer(buf), _data(new (buf) Internals::JsonArrayData()) {} // Adds the specified value at the end of the array. // @@ -43,24 +44,15 @@ class JsonArray { return add_impl(value); } - iterator begin() { + 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() { + iterator end() const { return iterator(); } - const_iterator end() const { - return const_iterator(); - } - // Imports a 1D array template bool copyFrom(T (&array)[N]) { @@ -100,8 +92,7 @@ class JsonArray { template 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,7 +101,7 @@ 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().copyTo(array[i++]); } } @@ -129,21 +120,21 @@ class JsonArray { // Gets the value at the specified index. template typename Internals::JsonVariantAs::type get(size_t index) const { - const_iterator it = begin() += index; - return it != end() ? it->as() : Internals::JsonVariantDefault::get(); + iterator it = begin() += index; + return it != end() ? it->as() : T(); } // Check the type of the value at specified index. template bool is(size_t index) const { - const_iterator it = begin() += index; + iterator it = begin() += index; return it != end() ? it->is() : false; } // Removes element at specified position. void remove(iterator it) { if (!_data) return; - _data->remove(it); + _data->remove(it.internal()); } // Removes element at specified index. @@ -182,7 +173,7 @@ class JsonArray { template void visit(Visitor& visitor) const { if (_data) - return visitor.acceptArray(*this); + visitor.acceptArray(*_data); else visitor.acceptNull(); } @@ -192,17 +183,18 @@ class JsonArray { bool set_impl(size_t index, TValueRef value) { iterator it = begin() += index; if (it == end()) return false; - return Internals::ValueSaver::save(_data->_buffer, *it, value); + return it->set(value); } template 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::save(_data->_buffer, *it, value); + return it->set(value); } + Internals::JsonBuffer* _buffer; Internals::JsonArrayData* _data; }; } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonArrayData.hpp b/src/ArduinoJson/JsonArrayData.hpp index 38bd7055..46b9cabf 100644 --- a/src/ArduinoJson/JsonArrayData.hpp +++ b/src/ArduinoJson/JsonArrayData.hpp @@ -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, JsonBufferAllocated { - explicit JsonArrayData(JsonBuffer *buf) throw() : List(buf) {} +struct JsonArrayData : List, JsonBufferAllocated { + JsonVariantData* addSlot(JsonBuffer* buffer) { + iterator it = add(buffer); + return it != end() ? &*it : 0; + } }; } // namespace Internals } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonArrayImpl.hpp b/src/ArduinoJson/JsonArrayImpl.hpp index 7f8f9018..0b175988 100644 --- a/src/ArduinoJson/JsonArrayImpl.hpp +++ b/src/ArduinoJson/JsonArrayImpl.hpp @@ -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; } diff --git a/src/ArduinoJson/JsonArrayIterator.hpp b/src/ArduinoJson/JsonArrayIterator.hpp new file mode 100644 index 00000000..68456e5c --- /dev/null +++ b/src/ArduinoJson/JsonArrayIterator.hpp @@ -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 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 diff --git a/src/ArduinoJson/JsonArraySubscript.hpp b/src/ArduinoJson/JsonArraySubscript.hpp index 474f2dff..abd42bc6 100644 --- a/src/ArduinoJson/JsonArraySubscript.hpp +++ b/src/ArduinoJson/JsonArraySubscript.hpp @@ -20,7 +20,7 @@ class JsonArraySubscript : public JsonVariantBase { : _array(array), _index(index) {} FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) { - _array.set(_index, src); + _array.set(_index, src.as()); return *this; } diff --git a/src/ArduinoJson/JsonObject.hpp b/src/ArduinoJson/JsonObject.hpp index 29aa1ffc..61c71f1f 100644 --- a/src/ArduinoJson/JsonObject.hpp +++ b/src/ArduinoJson/JsonObject.hpp @@ -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)) {} + JsonObject() : _buffer(0), _data(0) {} + explicit JsonObject(Internals::JsonBuffer* buf, + Internals::JsonObjectData* object) + : _buffer(buf), _data(object) {} + explicit JsonObject(Internals::JsonBuffer* buf) + : _buffer(buf), _data(new (buf) Internals::JsonObjectData()) {} - iterator begin() { + 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. @@ -46,14 +44,10 @@ class JsonObject { return containsKey_impl(key); } - iterator end() { + iterator end() const { return iterator(); } - const_iterator end() const { - return const_iterator(); - } - // Creates and adds a JsonArray. // // JsonArray createNestedArray(TKey); @@ -165,7 +159,7 @@ class JsonObject { void remove(iterator it) { if (!_data) return; - _data->remove(it); + _data->remove(it.internal()); } // Removes the specified key and the associated value. @@ -232,15 +226,15 @@ class JsonObject { template void visit(Visitor& visitor) const { if (_data) - visitor.acceptObject(*this); + visitor.acceptObject(*_data); else - return visitor.acceptNull(); + visitor.acceptNull(); } private: template bool containsKey_impl(TStringRef key) const { - return findKey(key) != end(); + return findKey(key) != _data->end(); } template @@ -251,30 +245,32 @@ class JsonObject { // Returns the list node that matches the specified key. template - 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 - const_iterator findKey(TStringRef key) const { + internal_iterator findKey(TStringRef key) const { return const_cast(this)->findKey(key); } template typename Internals::JsonVariantAs::type get_impl( TStringRef key) const { - const_iterator it = findKey(key); - return it != end() ? it->value.as() - : Internals::JsonVariantDefault::get(); + internal_iterator it = findKey(key); + return it != _data->end() ? JsonVariant(_buffer, &it->value).as() + : TValue(); } template bool is_impl(TStringRef key) const { - const_iterator it = findKey(key); - return it != end() ? it->value.is() : false; + internal_iterator it = findKey(key); + return it != _data->end() ? JsonVariant(_buffer, &it->value).is() + : false; } template @@ -291,21 +287,33 @@ class JsonObject { if (Internals::makeString(key).is_null()) return false; // search a matching key - iterator it = findKey(key); - if (it == end()) { + internal_iterator it = findKey(key); + if (it == _data->end()) { // add the key - it = _data->add(); - if (it == end()) return false; - bool key_ok = - Internals::ValueSaver::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::save(_data->_buffer, it->value, - value); + return JsonVariant(_buffer, &it->value).set(value); } - Internals::JsonObjectData* _data; + bool set_key(internal_iterator& it, const char* key) { + it->key = key; + return true; + } + + template + 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 diff --git a/src/ArduinoJson/JsonObjectData.hpp b/src/ArduinoJson/JsonObjectData.hpp index 05d66504..5c2945b3 100644 --- a/src/ArduinoJson/JsonObjectData.hpp +++ b/src/ArduinoJson/JsonObjectData.hpp @@ -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, JsonBufferAllocated { - explicit JsonObjectData(JsonBuffer* buf) throw() : List(buf) {} +struct JsonObjectData : List, 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 diff --git a/src/ArduinoJson/JsonObjectImpl.hpp b/src/ArduinoJson/JsonObjectImpl.hpp index ebc64173..f30c0dda 100644 --- a/src/ArduinoJson/JsonObjectImpl.hpp +++ b/src/ArduinoJson/JsonObjectImpl.hpp @@ -22,7 +22,7 @@ inline JsonArray JsonObject::createNestedArray(TString* key) { template 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 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; } diff --git a/src/ArduinoJson/JsonObjectIterator.hpp b/src/ArduinoJson/JsonObjectIterator.hpp new file mode 100644 index 00000000..cdbc97b5 --- /dev/null +++ b/src/ArduinoJson/JsonObjectIterator.hpp @@ -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 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 diff --git a/src/ArduinoJson/JsonPair.hpp b/src/ArduinoJson/JsonPair.hpp index 1748f877..40eeaf0a 100644 --- a/src/ArduinoJson/JsonPair.hpp +++ b/src/ArduinoJson/JsonPair.hpp @@ -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 diff --git a/src/ArduinoJson/JsonVariant.hpp b/src/ArduinoJson/JsonVariant.hpp index 2ad63b1d..6bed8d84 100644 --- a/src/ArduinoJson/JsonVariant.hpp +++ b/src/ArduinoJson/JsonVariant.hpp @@ -7,10 +7,10 @@ #include #include // 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,135 @@ class JsonObject; // - a reference to a JsonArray or JsonObject class JsonVariant : public Internals::JsonVariantBase { public: + // Intenal use only + explicit JsonVariant(Internals::JsonBuffer *buffer, + Internals::JsonVariantData *data) + : _buffer(buffer), _data(data) {} + // Creates an uninitialized JsonVariant - JsonVariant() : _type(Internals::JSON_UNDEFINED) {} + 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(value); + // set(bool value) + 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 - JsonVariant(T value, - typename Internals::enable_if< - Internals::is_floating_point::value>::type * = 0) { - using namespace Internals; - _type = JSON_FLOAT; - _content.asFloat = static_cast(value); + bool set(T value, typename Internals::enable_if< + Internals::is_floating_point::value>::type * = 0) { + if (!_data) return false; + _data->setFloat(static_cast(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 - JsonVariant( - T value, - typename Internals::enable_if::value && - Internals::is_signed::value>::type * = - 0) { - using namespace Internals; - if (value >= 0) { - _type = JSON_POSITIVE_INTEGER; - _content.asInteger = static_cast(value); + bool set(T value, + typename Internals::enable_if::value && + Internals::is_signed::value>::type + * = 0) { + if (!_data) return false; + if (value >= 0) + _data->setPostiveInteger(static_cast(value)); + else + _data->setNegativeInteger(~static_cast(value) + 1); + return true; + } + + // set(unsigned short) + // set(unsigned int) + // set(unsigned long) + template + bool set(T value, + typename Internals::enable_if::value && + Internals::is_unsigned::value>::type + * = 0) { + if (!_data) return false; + _data->setPostiveInteger(static_cast(value)); + return true; + } + + // set(SerializedValue) + bool set(Internals::SerializedValue value) { + if (!_data) return false; + _data->setRaw(value.data(), value.size()); + return true; + } + + // set(SerializedValue) + // set(SerializedValue) + // set(SerializedValue) + template + bool set(Internals::SerializedValue value, + typename Internals::enable_if< + !Internals::is_same::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; + } + + // set(const std::string&) + // set(const String&) + template + bool set(const T &value, + typename Internals::enable_if::value>::type + * = 0) { + if (!_data) return false; + const char *dup = Internals::makeString(value).save(_buffer); + if (dup) { + _data->setString(dup); + return true; } else { - _type = JSON_NEGATIVE_INTEGER; - _content.asInteger = ~static_cast(value) + 1; + _data->setNull(); + return false; } } - // JsonVariant(unsigned short) - // JsonVariant(unsigned int) - // JsonVariant(unsigned long) - template - JsonVariant( - T value, - typename Internals::enable_if::value && - Internals::is_unsigned::value>::type * = - 0) { - using namespace Internals; - _type = JSON_POSITIVE_INTEGER; - _content.asInteger = static_cast(value); + + // set(const char*); + // set(const char[n]); // VLA + bool set(const char *value) { + if (!_data) return false; + _data->setString(value); + return true; + } + // set(const unsigned char*); + // set(const unsigned char[n]); // VLA + bool set(const unsigned char *value) { + return set(reinterpret_cast(value)); + } + // set(const signed char*); + // set(const signed char[n]); // VLA + bool set(const signed char *value) { + return set(reinterpret_cast(value)); } - // Create a JsonVariant containing a string. - // JsonVariant(const char*); - // JsonVariant(const signed char*); - // JsonVariant(const unsigned char*); - template - JsonVariant(const TChar *value, - typename Internals::enable_if::type * = 0) { - _type = Internals::JSON_STRING; - _content.asString = reinterpret_cast(value); + bool set(const JsonVariant &value) { + if (!_data) return false; + if (value._data) + *_data = *value._data; + else + _data->setNull(); + return true; } - // Create a JsonVariant containing an unparsed string - JsonVariant(Internals::SerializedValue value) { - _type = Internals::JSON_UNPARSED; - _content.asRaw.data = value.data(); - _content.asRaw.size = value.size(); - } - - JsonVariant(JsonArray array); - JsonVariant(JsonObject object); + bool set(const JsonArray &array); + bool set(const Internals::JsonArraySubscript &); + bool set(const JsonObject &object); + template + bool set(const Internals::JsonObjectSubscript &); // Get the variant as the specified type. // @@ -123,14 +174,14 @@ class JsonVariant : public Internals::JsonVariantBase { template const typename Internals::enable_if::value, T>::type as() const { - return variantAsInteger(); + return _data ? _data->asInteger() : T(); } // bool as() const template const typename Internals::enable_if::value, T>::type as() const { - return variantAsInteger() != 0; + return _data && _data->asInteger() != 0; } // // double as() const; @@ -139,7 +190,7 @@ class JsonVariant : public Internals::JsonVariantBase { const typename Internals::enable_if::value, T>::type as() const { - return variantAsFloat(); + return _data ? _data->asFloat() : 0; } // // const char* as() const; @@ -149,7 +200,7 @@ class JsonVariant : public Internals::JsonVariantBase { Internals::is_same::value, const char *>::type as() const { - return variantAsString(); + return _data ? _data->asString() : 0; } // // std::string as() const; @@ -157,7 +208,7 @@ class JsonVariant : public Internals::JsonVariantBase { template typename Internals::enable_if::value, T>::type as() const { - const char *cstr = variantAsString(); + const char *cstr = _data ? _data->asString() : 0; if (cstr) return T(cstr); T s; serializeJson(*this, s); @@ -205,7 +256,7 @@ class JsonVariant : public Internals::JsonVariantBase { template typename Internals::enable_if::value, bool>::type is() const { - return variantIsInteger(); + return _data && _data->isInteger(); } // // bool is() const; @@ -214,14 +265,14 @@ class JsonVariant : public Internals::JsonVariantBase { typename Internals::enable_if::value, bool>::type is() const { - return variantIsFloat(); + return _data && _data->isFloat(); } // // bool is() const template typename Internals::enable_if::value, bool>::type is() const { - return variantIsBoolean(); + return _data && _data->isBoolean(); } // // bool is() const; @@ -231,7 +282,7 @@ class JsonVariant : public Internals::JsonVariantBase { Internals::is_same::value, bool>::type is() const { - return variantIsString(); + return _data && _data->isString(); } // // bool is const; @@ -242,7 +293,7 @@ class JsonVariant : public Internals::JsonVariantBase { JsonArray>::value, bool>::type is() const { - return variantIsArray(); + return _data && _data->isArray(); } // // bool is const; @@ -253,72 +304,24 @@ class JsonVariant : public Internals::JsonVariantBase { 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; + return _data == 0 || _data->isNull(); } template 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(); - } + if (_data) + _data->visit(visitor); + else + visitor.acceptNull(); } private: - JsonArray variantAsArray() const; - JsonObject variantAsObject() const; - const char *variantAsString() const; - template - T variantAsFloat() const; - template - 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 diff --git a/src/ArduinoJson/JsonVariantComparisons.hpp b/src/ArduinoJson/JsonVariantComparisons.hpp index f9f55cc3..c9c6c5e8 100644 --- a/src/ArduinoJson/JsonVariantComparisons.hpp +++ b/src/ArduinoJson/JsonVariantComparisons.hpp @@ -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" diff --git a/src/ArduinoJson/JsonVariantImpl.hpp b/src/ArduinoJson/JsonVariantImpl.hpp index cc752939..626aa337 100644 --- a/src/ArduinoJson/JsonVariantImpl.hpp +++ b/src/ArduinoJson/JsonVariantImpl.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()); +} + +inline bool JsonVariant::set(const JsonObject& object) { + if (!_data) return false; + if (object._data) + _data->setObject(*object._data); + else + _data->setNull(); + return true; +} + +template +inline bool JsonVariant::set( + const Internals::JsonObjectSubscript& value) { + return set(value.template as()); } template @@ -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 @@ -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 -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(_content.asString); - default: - return T(_content.asFloat); - } -} - -inline const char *JsonVariant::variantAsString() const { - using namespace Internals; - return _type == JSON_STRING ? _content.asString : NULL; -} - -template -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(_content.asInteger); - case JSON_NEGATIVE_INTEGER: - return -static_cast(_content.asInteger); - case JSON_STRING: - return parseFloat(_content.asString); - default: - return static_cast(_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 diff --git a/src/ArduinoJson/Memory/JsonBufferAllocated.hpp b/src/ArduinoJson/Memory/JsonBufferAllocated.hpp index 4712ccb1..da8ab09a 100644 --- a/src/ArduinoJson/Memory/JsonBufferAllocated.hpp +++ b/src/ArduinoJson/Memory/JsonBufferAllocated.hpp @@ -16,7 +16,7 @@ class JsonBufferAllocated { return jsonBuffer->alloc(n); } - void operator delete(void *, JsonBuffer *)throw(); + void operator delete(void *, JsonBuffer *)throw() {} }; } // namespace Internals } // namespace ArduinoJson diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index c87c0bb1..132de6cb 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -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(code); + variant.setInteger(static_cast(code)); return DeserializationError::Ok; } @@ -48,15 +48,15 @@ class MsgPackDeserializer { switch (code) { case 0xc0: - variant = static_cast(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 - 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 enable_if::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 enable_if::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 enable_if::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(&value); if (!readBytes(i, 8)) return DeserializationError::IncompleteInput; doubleToFloat(i, o); fixEndianess(value); - variant = value; + variant.setFloat(value); return DeserializationError::Ok; } template - 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::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 - 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 - 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(); - 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; diff --git a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index fe1e6163..7162599a 100644 --- a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -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); diff --git a/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp b/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp index e97a09cc..abd86050 100644 --- a/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp +++ b/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp @@ -4,6 +4,7 @@ #pragma once +#include "../../Configuration.hpp" #include "is_same.hpp" namespace ArduinoJson { diff --git a/src/ArduinoJson/StaticJsonDocument.hpp b/src/ArduinoJson/StaticJsonDocument.hpp index cb080169..bdf3a5d4 100644 --- a/src/ArduinoJson/StaticJsonDocument.hpp +++ b/src/ArduinoJson/StaticJsonDocument.hpp @@ -9,11 +9,8 @@ namespace ArduinoJson { -template +template class StaticJsonDocument { - Internals::StaticJsonBuffer _buffer; - JsonVariant _root; - public: uint8_t nestingLimit; @@ -25,12 +22,12 @@ class StaticJsonDocument { template bool is() const { - return _root.is(); + return getVariant().template is(); } template typename Internals::JsonVariantAs::type as() const { - return _root.as(); + return getVariant().template as(); } // JsonObject to() @@ -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() template typename Internals::enable_if::value, - T&>::type + JsonVariant>::type to() { clear(); - return _root; + return getVariant(); + } + + // JsonVariantData& to() + template + typename Internals::enable_if< + Internals::is_same::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 void visit(Visitor& visitor) const { - return _root.visit(visitor); + return getVariant().visit(visitor); } + + private: + JsonVariant getVariant() const { + return JsonVariant(&_buffer, &_rootData); + } + + mutable Internals::StaticJsonBuffer _buffer; + mutable Internals::JsonVariantData _rootData; }; } // namespace ArduinoJson diff --git a/src/ArduinoJson/Strings/FixedSizeRamString.hpp b/src/ArduinoJson/Strings/FixedSizeRamString.hpp index 937086df..48ce4ad3 100644 --- a/src/ArduinoJson/Strings/FixedSizeRamString.hpp +++ b/src/ArduinoJson/Strings/FixedSizeRamString.hpp @@ -4,6 +4,8 @@ #pragma once +#include // strcmp + namespace ArduinoJson { namespace Internals { diff --git a/src/ArduinoJson/Strings/StlString.hpp b/src/ArduinoJson/Strings/StlString.hpp index 7e90b29e..9d47f7e8 100644 --- a/src/ArduinoJson/Strings/StlString.hpp +++ b/src/ArduinoJson/Strings/StlString.hpp @@ -26,6 +26,7 @@ class StlString { } bool equals(const char* expected) const { + if (!expected) return false; return *_str == expected; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 724c5181..82e90a31 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -68,6 +68,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) diff --git a/test/JsonArray/iterator.cpp b/test/JsonArray/iterator.cpp index db884ee4..95f9dd80 100644 --- a/test/JsonArray/iterator.cpp +++ b/test/JsonArray/iterator.cpp @@ -30,8 +30,4 @@ TEST_CASE("JsonArray::begin()/end()") { SECTION("Mutable") { run_iterator_test(); } - - SECTION("Const") { - run_iterator_test(); - } } diff --git a/test/JsonDocument/CMakeLists.txt b/test/JsonDocument/CMakeLists.txt new file mode 100644 index 00000000..4ce5e97f --- /dev/null +++ b/test/JsonDocument/CMakeLists.txt @@ -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) diff --git a/test/JsonDocument/DynamicJsonDocument.cpp b/test/JsonDocument/DynamicJsonDocument.cpp new file mode 100644 index 00000000..7256b6a2 --- /dev/null +++ b/test/JsonDocument/DynamicJsonDocument.cpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("DynamicJsonDocument") { + DynamicJsonDocument doc; + + SECTION("serializeJson()") { + JsonObject obj = doc.to(); + obj["hello"] = "world"; + + std::string json; + serializeJson(doc, json); + + REQUIRE(json == "{\"hello\":\"world\"}"); + } +} diff --git a/test/JsonDocument/StaticJsonDocument.cpp b/test/JsonDocument/StaticJsonDocument.cpp new file mode 100644 index 00000000..ee416d9a --- /dev/null +++ b/test/JsonDocument/StaticJsonDocument.cpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("StaticJsonDocument") { + StaticJsonDocument<200> doc; + + SECTION("serializeJson()") { + JsonObject obj = doc.to(); + obj["hello"] = "world"; + + std::string json; + serializeJson(doc, json); + + REQUIRE(json == "{\"hello\":\"world\"}"); + } +} diff --git a/test/JsonObject/iterator.cpp b/test/JsonObject/iterator.cpp index 0ccf1b54..fe7b6fd8 100644 --- a/test/JsonObject/iterator.cpp +++ b/test/JsonObject/iterator.cpp @@ -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); + // } } diff --git a/test/JsonObject/remove.cpp b/test/JsonObject/remove.cpp index 0277385f..fc815651 100644 --- a/test/JsonObject/remove.cpp +++ b/test/JsonObject/remove.cpp @@ -32,7 +32,7 @@ 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; diff --git a/test/JsonSerializer/JsonVariant.cpp b/test/JsonSerializer/JsonVariant.cpp index 517eb38c..691a0fa2 100644 --- a/test/JsonSerializer/JsonVariant.cpp +++ b/test/JsonSerializer/JsonVariant.cpp @@ -6,9 +6,12 @@ #include #include -void check(JsonVariant variant, const std::string &expected) { +template +void check(T value, const std::string &expected) { + DynamicJsonDocument doc; + doc.to().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(0), "null"); } - SECTION("String") { + SECTION("const char*") { check("hello", "\"hello\""); } + SECTION("string") { + check(std::string("hello"), "\"hello\""); + } + + SECTION("SerializedValue") { + check(serialized("[1,2]"), "[1,2]"); + } + + SECTION("SerializedValue") { + check(serialized(std::string("[1,2]")), "[1,2]"); + } + SECTION("Double") { check(3.1415927, "3.1415927"); } diff --git a/test/JsonSerializer/std_stream.cpp b/test/JsonSerializer/std_stream.cpp index 0357fba9..db36c23b 100644 --- a/test/JsonSerializer/std_stream.cpp +++ b/test/JsonSerializer/std_stream.cpp @@ -11,16 +11,18 @@ TEST_CASE("operator<<(std::ostream)") { std::ostringstream os; SECTION("JsonVariant containing false") { - JsonVariant variant = false; + JsonVariant variant = doc.to(); + variant.set(false); os << variant; REQUIRE("false" == os.str()); } SECTION("JsonVariant containing string") { - JsonVariant variant = "coucou"; + JsonVariant variant = doc.to(); + variant.set("coucou"); os << variant; REQUIRE("\"coucou\"" == os.str()); diff --git a/test/JsonVariant/CMakeLists.txt b/test/JsonVariant/CMakeLists.txt index 9004b3be..15c8eca9 100644 --- a/test/JsonVariant/CMakeLists.txt +++ b/test/JsonVariant/CMakeLists.txt @@ -5,7 +5,6 @@ add_executable(JsonVariantTests as.cpp compare.cpp - copy.cpp is.cpp isnull.cpp or.cpp diff --git a/test/JsonVariant/as.cpp b/test/JsonVariant/as.cpp index b324161e..cfd79dd3 100644 --- a/test/JsonVariant/as.cpp +++ b/test/JsonVariant/as.cpp @@ -9,222 +9,225 @@ static const char* null = 0; TEST_CASE("JsonVariant::as()") { + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + SECTION("DoubleAsBool") { - JsonVariant variant = 4.2; + variant.set(4.2); REQUIRE(variant.as()); } SECTION("DoubleAsCstr") { - JsonVariant variant = 4.2; + variant.set(4.2); REQUIRE_FALSE(variant.as()); } SECTION("DoubleAsString") { - JsonVariant variant = 4.2; + variant.set(4.2); REQUIRE(std::string("4.2") == variant.as()); } SECTION("DoubleAsLong") { - JsonVariant variant = 4.2; + variant.set(4.2); REQUIRE(4L == variant.as()); } SECTION("DoubleAsUnsigned") { - JsonVariant variant = 4.2; + variant.set(4.2); REQUIRE(4U == variant.as()); } SECTION("DoubleZeroAsBool") { - JsonVariant variant = 0.0; + variant.set(0.0); REQUIRE_FALSE(variant.as()); } SECTION("DoubleZeroAsLong") { - JsonVariant variant = 0.0; + variant.set(0.0); REQUIRE(0L == variant.as()); } SECTION("FalseAsBool") { - JsonVariant variant = false; + variant.set(false); REQUIRE_FALSE(variant.as()); } SECTION("FalseAsDouble") { - JsonVariant variant = false; + variant.set(false); REQUIRE(0.0 == variant.as()); } SECTION("FalseAsLong") { - JsonVariant variant = false; + variant.set(false); REQUIRE(0L == variant.as()); } SECTION("FalseAsString") { - JsonVariant variant = false; + variant.set(false); REQUIRE(std::string("false") == variant.as()); } SECTION("TrueAsBool") { - JsonVariant variant = true; + variant.set(true); REQUIRE(variant.as()); } SECTION("TrueAsDouble") { - JsonVariant variant = true; + variant.set(true); REQUIRE(1.0 == variant.as()); } SECTION("TrueAsLong") { - JsonVariant variant = true; + variant.set(true); REQUIRE(1L == variant.as()); } SECTION("TrueAsString") { - JsonVariant variant = true; + variant.set(true); REQUIRE(std::string("true") == variant.as()); } SECTION("LongAsBool") { - JsonVariant variant = 42L; + variant.set(42L); REQUIRE(variant.as()); } SECTION("LongZeroAsBool") { - JsonVariant variant = 0L; + variant.set(0L); REQUIRE_FALSE(variant.as()); } SECTION("PositiveLongAsDouble") { - JsonVariant variant = 42L; + variant.set(42L); REQUIRE(42.0 == variant.as()); } SECTION("NegativeLongAsDouble") { - JsonVariant variant = -42L; + variant.set(-42L); REQUIRE(-42.0 == variant.as()); } SECTION("LongAsString") { - JsonVariant variant = 42L; + variant.set(42L); REQUIRE(std::string("42") == variant.as()); } SECTION("LongZeroAsDouble") { - JsonVariant variant = 0L; + variant.set(0L); REQUIRE(0.0 == variant.as()); } SECTION("NullAsBool") { - JsonVariant variant = null; + variant.set(null); REQUIRE_FALSE(variant.as()); } SECTION("NullAsDouble") { - JsonVariant variant = null; + variant.set(null); REQUIRE(0.0 == variant.as()); } SECTION("NullAsLong") { - JsonVariant variant = null; + variant.set(null); REQUIRE(0L == variant.as()); } SECTION("NullAsString") { - JsonVariant variant = null; + variant.set(null); REQUIRE(std::string("null") == variant.as()); } SECTION("NumberStringAsBool") { - JsonVariant variant = "42"; + variant.set("42"); REQUIRE(variant.as()); } SECTION("NumberStringAsLong") { - JsonVariant variant = "42"; + variant.set("42"); REQUIRE(42L == variant.as()); } #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 SECTION("NumberStringAsInt64Negative") { - JsonVariant variant = "-9223372036854775808"; + variant.set("-9223372036854775808"); REQUIRE(-9223372036854775807 - 1 == variant.as()); } SECTION("NumberStringAsInt64Positive") { - JsonVariant variant = "9223372036854775807"; + variant.set("9223372036854775807"); REQUIRE(9223372036854775807 == variant.as()); } #endif SECTION("RandomStringAsBool") { - JsonVariant variant = "hello"; + variant.set("hello"); REQUIRE_FALSE(variant.as()); } SECTION("RandomStringAsLong") { - JsonVariant variant = "hello"; + variant.set("hello"); REQUIRE(0L == variant.as()); } SECTION("RandomStringAsConstCharPtr") { - JsonVariant variant = "hello"; + variant.set("hello"); REQUIRE(std::string("hello") == variant.as()); } SECTION("RandomStringAsCharPtr") { - JsonVariant variant = "hello"; + variant.set("hello"); REQUIRE(std::string("hello") == variant.as()); } SECTION("RandomStringAsString") { - JsonVariant variant = "hello"; + variant.set("hello"); REQUIRE(std::string("hello") == variant.as()); } SECTION("TrueStringAsBool") { - JsonVariant variant = "true"; + variant.set("true"); REQUIRE(variant.as()); } SECTION("TrueStringAsLong") { - JsonVariant variant = "true"; + variant.set("true"); REQUIRE(1L == variant.as()); } SECTION("ObjectAsString") { - DynamicJsonDocument doc; - JsonObject obj = doc.to(); + DynamicJsonDocument doc2; + JsonObject obj = doc2.to(); obj["key"] = "value"; - JsonVariant variant = obj; + variant.set(obj); REQUIRE(std::string("{\"key\":\"value\"}") == variant.as()); } SECTION("ArrayAsString") { - DynamicJsonDocument doc; - JsonArray arr = doc.to(); + DynamicJsonDocument doc2; + JsonArray arr = doc2.to(); arr.add(4); arr.add(2); - JsonVariant variant = arr; + variant.set(arr); REQUIRE(std::string("[4,2]") == variant.as()); } SECTION("ArrayAsJsonArray") { - DynamicJsonDocument doc; - JsonArray arr = doc.to(); + DynamicJsonDocument doc2; + JsonArray arr = doc2.to(); - JsonVariant variant = arr; + variant.set(arr); REQUIRE(arr == variant.as()); REQUIRE(arr == variant.as()); // <- shorthand } SECTION("ObjectAsJsonObject") { - DynamicJsonDocument doc; - JsonObject obj = doc.to(); + DynamicJsonDocument doc2; + JsonObject obj = doc2.to(); - JsonVariant variant = obj; + variant.set(obj); REQUIRE(obj == variant.as()); REQUIRE(obj == variant.as()); // <- shorthand } diff --git a/test/JsonVariant/compare.cpp b/test/JsonVariant/compare.cpp index c7681f08..a14087af 100644 --- a/test/JsonVariant/compare.cpp +++ b/test/JsonVariant/compare.cpp @@ -8,46 +8,58 @@ static const char* null = 0; template -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(); + 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 -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(); + 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 -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(); + 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 @@ -99,7 +111,9 @@ TEST_CASE("JsonVariant comparisons") { } SECTION("null") { - JsonVariant variant = null; + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + 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(); + variant.set("hello"); REQUIRE(variant == variant); REQUIRE_FALSE(variant != variant); @@ -163,10 +179,15 @@ TEST_CASE("JsonVariant comparisons") { REQUIRE_FALSE(null == variant); } + DynamicJsonDocument doc1, doc2, doc3; + JsonVariant variant1 = doc1.to(); + JsonVariant variant2 = doc2.to(); + JsonVariant variant3 = doc3.to(); + 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 +197,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 +209,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 +221,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 +233,13 @@ TEST_CASE("JsonVariant comparisons") { } SECTION("ArrayInVariant") { - DynamicJsonDocument doc1; - JsonArray array1 = doc1.to(); - DynamicJsonDocument doc2; - JsonArray array2 = doc2.to(); + DynamicJsonDocument docArr1, docArr2; + JsonArray array1 = docArr1.to(); + JsonArray array2 = docArr2.to(); - 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 +249,13 @@ TEST_CASE("JsonVariant comparisons") { } SECTION("ObjectInVariant") { - DynamicJsonDocument doc1; - JsonObject obj1 = doc1.to(); - DynamicJsonDocument doc2; - JsonObject obj2 = doc2.to(); + DynamicJsonDocument docObj1, docObj2; + JsonObject obj1 = docObj1.to(); + JsonObject obj2 = docObj2.to(); - 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 +264,22 @@ TEST_CASE("JsonVariant comparisons") { REQUIRE_FALSE(variant1 == variant3); } - SECTION("VariantsOfDifferentTypes") { - DynamicJsonDocument doc1; - JsonObject obj = doc1.to(); + // SECTION("VariantsOfDifferentTypes") { + // DynamicJsonDocument doc1; + // JsonObject obj = doc1.to(); - DynamicJsonDocument doc2; - JsonArray arr = doc2.to(); - JsonVariant variants[] = { - true, 42, 666.667, "hello", arr, obj, - }; - size_t n = sizeof(variants) / sizeof(variants[0]); + // DynamicJsonDocument doc2; + // JsonArray arr = doc2.to(); + // 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]); + // } + // } + // } } diff --git a/test/JsonVariant/copy.cpp b/test/JsonVariant/copy.cpp deleted file mode 100644 index 890db3a8..00000000 --- a/test/JsonVariant/copy.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -TEST_CASE("JsonVariant copy") { - JsonVariant _variant1; - JsonVariant _variant2; - - SECTION("IntegersAreCopiedByValue") { - _variant1 = 123; - _variant2 = _variant1; - _variant1 = 456; - - REQUIRE(123 == _variant2.as()); - } - - SECTION("DoublesAreCopiedByValue") { - _variant1 = 123.45; - _variant2 = _variant1; - _variant1 = 456.78; - - REQUIRE(123.45 == _variant2.as()); - } - - SECTION("BooleansAreCopiedByValue") { - _variant1 = true; - _variant2 = _variant1; - _variant1 = false; - - REQUIRE(_variant2.as()); - } - - SECTION("StringsAreCopiedByValue") { - _variant1 = "hello"; - _variant2 = _variant1; - _variant1 = "world"; - - REQUIRE(std::string("hello") == _variant2.as()); - } - - SECTION("ObjectsAreCopiedByReference") { - DynamicJsonDocument doc; - JsonObject object = doc.to(); - - _variant1 = object; - - object["hello"] = "world"; - - REQUIRE(1 == _variant1.as().size()); - } - - SECTION("ArraysAreCopiedByReference") { - DynamicJsonDocument doc; - JsonArray array = doc.to(); - - _variant1 = array; - - array.add("world"); - - REQUIRE(1 == _variant1.as().size()); - } -} diff --git a/test/JsonVariant/is.cpp b/test/JsonVariant/is.cpp index 3594d8f7..2f8e6c2b 100644 --- a/test/JsonVariant/is.cpp +++ b/test/JsonVariant/is.cpp @@ -5,7 +5,11 @@ #include #include -void checkIsArray(JsonVariant var) { +void checkIsArray(JsonArray value) { + DynamicJsonDocument doc; + JsonVariant var = doc.to(); + var.set(value); + REQUIRE(var.is()); REQUIRE(var.is()); REQUIRE(var.is()); @@ -16,48 +20,65 @@ void checkIsArray(JsonVariant var) { REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); - REQUIRE_FALSE(var.is()); + REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); } -void checkIsBool(JsonVariant var) { +void checkIsBool(bool value) { + DynamicJsonDocument doc; + JsonVariant var = doc.to(); + var.set(value); + REQUIRE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); - REQUIRE_FALSE(var.is()); + REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); } -void checkIsFloat(JsonVariant var) { +void checkIsFloat(double value) { + DynamicJsonDocument doc; + JsonVariant var = doc.to(); + var.set(value); + REQUIRE(var.is()); REQUIRE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); - REQUIRE_FALSE(var.is()); + REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); } -void checkIsInteger(JsonVariant var) { +template +void checkIsInteger(T value) { + DynamicJsonDocument doc; + JsonVariant var = doc.to(); + var.set(value); + REQUIRE(var.is()); REQUIRE(var.is()); REQUIRE(var.is()); REQUIRE(var.is()); REQUIRE_FALSE(var.is()); - REQUIRE_FALSE(var.is()); + REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); } -void checkIsString(JsonVariant var) { - REQUIRE(var.is()); +void checkIsString(const char *value) { + DynamicJsonDocument doc; + JsonVariant var = doc.to(); + var.set(value); + + REQUIRE(var.is()); REQUIRE_FALSE(var.is()); REQUIRE_FALSE(var.is()); diff --git a/test/JsonVariant/isnull.cpp b/test/JsonVariant/isnull.cpp index e4072c1a..b429048c 100644 --- a/test/JsonVariant/isnull.cpp +++ b/test/JsonVariant/isnull.cpp @@ -6,39 +6,42 @@ #include TEST_CASE("JsonVariant::isNull()") { - SECTION("ReturnsFalse_WhenUndefined") { - JsonVariant variant; + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + + 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(); + SECTION("return false when EmptyArray") { + DynamicJsonDocument doc2; + JsonArray array = doc2.to(); - JsonVariant variant = array; + variant.set(array); REQUIRE(variant.isNull() == false); } - SECTION("ReturnsTrue_WhenEmptyObject") { - DynamicJsonDocument doc; - JsonObject obj = doc.to(); + SECTION("return false when EmptyObject") { + DynamicJsonDocument doc2; + JsonObject obj = doc2.to(); - 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); } } diff --git a/test/JsonVariant/or.cpp b/test/JsonVariant/or.cpp index 84349463..4d46e84a 100644 --- a/test/JsonVariant/or.cpp +++ b/test/JsonVariant/or.cpp @@ -5,78 +5,84 @@ #include #include -static const JsonVariant undefined; -static const JsonVariant null = static_cast(0); - TEST_CASE("JsonVariant::operator|()") { - SECTION("undefined | const char*") { - std::string result = undefined | "default"; - REQUIRE(result == "default"); + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + + 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(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); } diff --git a/test/JsonVariant/set_get.cpp b/test/JsonVariant/set_get.cpp index 772df2a6..883c0e91 100644 --- a/test/JsonVariant/set_get.cpp +++ b/test/JsonVariant/set_get.cpp @@ -9,7 +9,10 @@ template void checkValue(T expected) { - JsonVariant variant = expected; + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + + variant.set(expected); REQUIRE(expected == variant.as()); } @@ -21,11 +24,15 @@ void checkReference(T &expected) { template void checkNumericType() { + DynamicJsonDocument docMin, docMax; + JsonVariant variantMin = docMin.to(); + JsonVariant variantMax = docMax.to(); + T min = std::numeric_limits::min(); T max = std::numeric_limits::max(); - JsonVariant variantMin(min); - JsonVariant variantMax(max); + variantMin.set(min); + variantMax.set(max); REQUIRE(min == variantMin.as()); REQUIRE(max == variantMax.as()); @@ -41,9 +48,12 @@ TEST_CASE("JsonVariant set()/get()") { SECTION("Null") { checkValue(NULL); } - SECTION("String") { + SECTION("const char*") { checkValue("hello"); } + SECTION("std::string") { + checkValue("hello"); + } SECTION("False") { checkValue(false); diff --git a/test/JsonVariant/subscript.cpp b/test/JsonVariant/subscript.cpp index 24227252..9a94d1cf 100644 --- a/test/JsonVariant/subscript.cpp +++ b/test/JsonVariant/subscript.cpp @@ -6,24 +6,26 @@ #include TEST_CASE("JsonVariant::operator[]") { + DynamicJsonDocument doc; + JsonVariant var = doc.to(); + 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(); - JsonVariant var = array; + DynamicJsonDocument doc2; + JsonArray array = doc2.to(); + 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(); - JsonVariant var = object; + DynamicJsonDocument doc2; + JsonObject object = doc2.to(); + var.set(object); SECTION("get value") { object["a"] = "element at key \"a\""; diff --git a/test/Misc/unsigned_char.cpp b/test/Misc/unsigned_char.cpp index b8a9ed24..c65611cd 100644 --- a/test/Misc/unsigned_char.cpp +++ b/test/Misc/unsigned_char.cpp @@ -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()); - } - - SECTION("operator=") { - unsigned char value[] = "42"; - - JsonVariant variant(666); - variant = value; + JsonVariant variant = doc.to(); + variant.set(value); REQUIRE(42 == variant.as()); } @@ -50,7 +44,6 @@ TEST_CASE("unsigned char[]") { SECTION("operator[]") { unsigned char key[] = "hello"; - DynamicJsonDocument doc; deserializeJson(doc, "{\"hello\":\"world\"}"); JsonVariant variant = doc.as(); @@ -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(); @@ -73,8 +65,8 @@ TEST_CASE("unsigned char[]") { SECTION("operator==") { unsigned char comparand[] = "hello"; - JsonVariant variant; - variant = "hello"; + JsonVariant variant = doc.to(); + 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(); + variant.set("world"); REQUIRE(comparand != variant); REQUIRE(variant != comparand); diff --git a/test/Misc/vla.cpp b/test/Misc/vla.cpp index e5ac70bb..4ed5e306 100644 --- a/test/Misc/vla.cpp +++ b/test/Misc/vla.cpp @@ -40,23 +40,15 @@ TEST_CASE("Variable Length Array") { } SECTION("JsonVariant") { - SECTION("constructor") { + DynamicJsonDocument doc; + + SECTION("set()") { int i = 16; char vla[i]; strcpy(vla, "42"); - JsonVariant variant(vla); - - REQUIRE(42 == variant.as()); - } - - SECTION("operator=") { - int i = 16; - char vla[i]; - strcpy(vla, "42"); - - JsonVariant variant(666); - variant = vla; + JsonVariant variant = doc.to(); + variant.set(vla); REQUIRE(42 == variant.as()); } @@ -67,7 +59,6 @@ TEST_CASE("Variable Length Array") { char vla[i]; strcpy(vla, "hello"); - DynamicJsonDocument doc; deserializeJson(doc, "{\"hello\":\"world\"}"); JsonVariant variant = doc.as(); @@ -81,7 +72,6 @@ TEST_CASE("Variable Length Array") { char vla[i]; strcpy(vla, "hello"); - DynamicJsonDocument doc; deserializeJson(doc, "{\"hello\":\"world\"}"); const JsonVariant variant = doc.as(); @@ -94,8 +84,8 @@ TEST_CASE("Variable Length Array") { char vla[i]; strcpy(vla, "hello"); - JsonVariant variant; - variant = "hello"; + JsonVariant variant = doc.to(); + variant.set("hello"); REQUIRE((vla == variant)); REQUIRE((variant == vla)); @@ -109,7 +99,7 @@ TEST_CASE("Variable Length Array") { strcpy(vla, "hello"); JsonVariant variant; - variant = "world"; + variant.set("world"); REQUIRE((vla != variant)); REQUIRE((variant != vla)); diff --git a/test/MsgPackDeserializer/deserializeVariant.cpp b/test/MsgPackDeserializer/deserializeVariant.cpp index dd13887c..f63f964e 100644 --- a/test/MsgPackDeserializer/deserializeVariant.cpp +++ b/test/MsgPackDeserializer/deserializeVariant.cpp @@ -16,10 +16,18 @@ static void check(const char* input, U expected) { REQUIRE(variant.as() == expected); } +static void checkIsNull(const char* input) { + DynamicJsonDocument variant; + + DeserializationError error = deserializeMsgPack(variant, input); + + REQUIRE(error == DeserializationError::Ok); + REQUIRE(variant.as().isNull()); +} + TEST_CASE("deserialize MsgPack value") { SECTION("nil") { - const char* nil = 0; // ArduinoJson uses a string for null - check("\xc0", nil); + checkIsNull("\xc0"); } SECTION("bool") { diff --git a/test/MsgPackSerializer/serializeVariant.cpp b/test/MsgPackSerializer/serializeVariant.cpp index 29c78d6e..952daa53 100644 --- a/test/MsgPackSerializer/serializeVariant.cpp +++ b/test/MsgPackSerializer/serializeVariant.cpp @@ -5,8 +5,11 @@ #include #include -void check(JsonVariant variant, const char* expected_data, - size_t expected_len) { +template +void check(T value, const char* expected_data, size_t expected_len) { + DynamicJsonDocument doc; + JsonVariant variant = doc.to(); + 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 -void check(JsonVariant variant, const char (&expected_data)[N]) { +template +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 +void check(T value, const std::string& expected) { + check(value, expected.data(), expected.length()); } TEST_CASE("serialize MsgPack value") {