From c161f698fca9808879e30ee3a543af8e8b4487ad Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sat, 25 Jul 2015 15:38:12 +0200 Subject: [PATCH] Implicitly duplicate String in the JsonBuffer (issue #84, #87) --- CHANGELOG.md | 6 +- .../Internals/JsonVariantContent.ipp | 5 - include/ArduinoJson/JsonArray.hpp | 45 ++++- include/ArduinoJson/JsonArray.ipp | 160 +++++++++++++++-- include/ArduinoJson/JsonArraySubscript.hpp | 21 ++- include/ArduinoJson/JsonBuffer.hpp | 14 +- include/ArduinoJson/JsonObject.hpp | 60 ++++++- include/ArduinoJson/JsonObject.ipp | 168 ++++++++++++++++-- include/ArduinoJson/JsonObjectSubscript.hpp | 52 +++--- include/ArduinoJson/JsonSubscriptBase.hpp | 82 +++++++++ include/ArduinoJson/JsonVariant.hpp | 2 - include/ArduinoJson/JsonVariant.ipp | 14 +- include/ArduinoJson/JsonVariantBase.hpp | 7 +- src/DynamicJsonBuffer.cpp | 2 +- src/JsonBuffer.cpp | 7 + src/JsonObject.cpp | 18 +- test/ArduinoString_Tests.cpp | 157 ++++++++++------ test/JsonObject_Container_Tests.cpp | 36 ++-- test/JsonObject_PrintTo_Tests.cpp | 126 ++++++------- test/StaticJsonBuffer_CreateObject_Tests.cpp | 33 ++-- 20 files changed, 762 insertions(+), 253 deletions(-) create mode 100644 include/ArduinoJson/JsonSubscriptBase.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index e30858a6..dd996c71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,11 @@ ArduinoJson: change log v5.0 (currently in beta) ---- -* Added support of `String` class (issue #55, #56, #70, #77) +* Added support of `String` class (issues #55, #56, #70, #77) +* Added `JsonBuffer::strdup()` to make a copy of a string (issues #10, #57) +* Implicitly call `strdup()` for `String` but not for `char*` (issues #84, #87) * Added support of non standard JSON input (issue #44) -* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators +* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66) * Switched to new the library layout (requires Arduino 1.0.6 or above) **BREAKING CHANGES**: diff --git a/include/ArduinoJson/Internals/JsonVariantContent.ipp b/include/ArduinoJson/Internals/JsonVariantContent.ipp index c5fb36c0..2c5a9ae6 100644 --- a/include/ArduinoJson/Internals/JsonVariantContent.ipp +++ b/include/ArduinoJson/Internals/JsonVariantContent.ipp @@ -23,11 +23,6 @@ inline char const* JsonVariantContent::as() const { return asString; } -template <> -inline String JsonVariantContent::as() const { - return asString; -} - template <> inline double JsonVariantContent::as() const { return asDouble; diff --git a/include/ArduinoJson/JsonArray.hpp b/include/ArduinoJson/JsonArray.hpp index 3c8c3a7e..4573ded3 100644 --- a/include/ArduinoJson/JsonArray.hpp +++ b/include/ArduinoJson/JsonArray.hpp @@ -42,16 +42,46 @@ class JsonArray : public Internals::JsonPrintable, : Internals::List(buffer) {} // Gets the value at the specified index - FORCE_INLINE const JsonArraySubscript operator[](size_t index) const; + FORCE_INLINE JsonVariant operator[](size_t index) const; // Gets or sets the value at specified index FORCE_INLINE JsonArraySubscript operator[](size_t index); // Adds the specified value at the end of the array. - FORCE_INLINE bool add(const JsonVariant value); + FORCE_INLINE bool add(bool value); + FORCE_INLINE bool add(float value, uint8_t decimals = 2); + FORCE_INLINE bool add(double value, uint8_t decimals = 2); + FORCE_INLINE bool add(signed char value); + FORCE_INLINE bool add(signed long value); + FORCE_INLINE bool add(signed int value); + FORCE_INLINE bool add(signed short value); + FORCE_INLINE bool add(unsigned char value); + FORCE_INLINE bool add(unsigned long value); + FORCE_INLINE bool add(unsigned int value); + FORCE_INLINE bool add(unsigned short value); + FORCE_INLINE bool add(const char *value); + FORCE_INLINE bool add(const String &value); + FORCE_INLINE bool add(JsonArray &array); + FORCE_INLINE bool add(JsonObject &object); + FORCE_INLINE bool add(const JsonVariant &object); // Sets the value at specified index. - FORCE_INLINE void set(size_t index, const JsonVariant value); + FORCE_INLINE void set(size_t index, bool value); + FORCE_INLINE void set(size_t index, float value, uint8_t decimals = 2); + FORCE_INLINE void set(size_t index, double value, uint8_t decimals = 2); + FORCE_INLINE void set(size_t index, signed char value); + FORCE_INLINE void set(size_t index, signed long value); + FORCE_INLINE void set(size_t index, signed int value); + FORCE_INLINE void set(size_t index, signed short value); + FORCE_INLINE void set(size_t index, unsigned char value); + FORCE_INLINE void set(size_t index, unsigned long value); + FORCE_INLINE void set(size_t index, unsigned int value); + FORCE_INLINE void set(size_t index, unsigned short value); + FORCE_INLINE void set(size_t index, const char *value); + FORCE_INLINE void set(size_t index, const String &value); + FORCE_INLINE void set(size_t index, JsonArray &array); + FORCE_INLINE void set(size_t index, JsonObject &object); + FORCE_INLINE void set(size_t index, const JsonVariant &object); // Gets the value at the specified index. FORCE_INLINE JsonVariant get(size_t index) const; @@ -86,6 +116,15 @@ class JsonArray : public Internals::JsonPrintable, private: node_type *getNodeAt(size_t index) const; + template + void setNodeAt(size_t index, TValue value); + + template + bool addNode(TValue); + + template + FORCE_INLINE void setNodeValue(node_type *, T value); + // The instance returned by JsonArray::invalid() static JsonArray _invalid; }; diff --git a/include/ArduinoJson/JsonArray.ipp b/include/ArduinoJson/JsonArray.ipp index e21da630..424a8391 100644 --- a/include/ArduinoJson/JsonArray.ipp +++ b/include/ArduinoJson/JsonArray.ipp @@ -15,14 +15,159 @@ inline JsonArraySubscript JsonArray::operator[](size_t index) { return JsonArraySubscript(*this, index); } -inline const JsonArraySubscript JsonArray::operator[](size_t index) const { - return JsonArraySubscript(*const_cast(this), index); +inline JsonVariant JsonArray::operator[](size_t index) const { + return get(index); } -inline bool JsonArray::add(const JsonVariant value) { +inline bool JsonArray::add(bool value) { return addNode(value); } + +inline bool JsonArray::add(float value, uint8_t decimals) { + return addNode(JsonVariant(value, decimals)); +} + +inline bool JsonArray::add(double value, uint8_t decimals) { + return addNode(JsonVariant(value, decimals)); +} + +inline bool JsonArray::add(signed char value) { + return addNode(value); +} + +inline bool JsonArray::add(signed long value) { + return addNode(value); +} + +inline bool JsonArray::add(signed int value) { + return addNode(value); +} + +inline bool JsonArray::add(signed short value) { + return addNode(value); +} + +inline bool JsonArray::add(unsigned char value) { + return addNode(value); +} + +inline bool JsonArray::add(unsigned long value) { + return addNode(value); +} + +inline bool JsonArray::add(unsigned int value) { + return addNode(value); +} + +inline bool JsonArray::add(unsigned short value) { + return addNode(value); +} + +inline bool JsonArray::add(const char *value) { + return addNode(value); +} + +inline bool JsonArray::add(const String &value) { + return addNode(value); +} + +inline bool JsonArray::add(JsonArray &array) { + return addNode(array); +} + +inline bool JsonArray::add(JsonObject &object) { + return addNode(object); +} + +inline bool JsonArray::add(const JsonVariant &object) { + return addNode(object); +} + +template +inline bool JsonArray::addNode(TValue value) { node_type *node = addNewNode(); - if (node) node->content = value; - return node != NULL; + if (node == NULL) return false; + setNodeValue(node, value); + return true; +} + +inline void JsonArray::set(size_t index, bool value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, float value, uint8_t decimals) { + return setNodeAt(index, JsonVariant(value, decimals)); +} + +inline void JsonArray::set(size_t index, double value, uint8_t decimals) { + return setNodeAt(index, JsonVariant(value, decimals)); +} + +inline void JsonArray::set(size_t index, signed char value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, signed long value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, signed int value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, signed short value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, unsigned char value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, unsigned long value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, unsigned int value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, unsigned short value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, const char *value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, const String &value) { + return setNodeAt(index, value); +} + +inline void JsonArray::set(size_t index, JsonArray &array) { + return setNodeAt(index, array); +} + +inline void JsonArray::set(size_t index, JsonObject &object) { + return setNodeAt(index, object); +} + +inline void JsonArray::set(size_t index, const JsonVariant &object) { + return setNodeAt(index, object); +} + +template +inline void JsonArray::setNodeAt(size_t index, TValue value) { + node_type *node = getNodeAt(index); + if (node == NULL) return; + setNodeValue(node, value); +} + +template +inline void JsonArray::setNodeValue(node_type *node, TValue value) { + node->content = value; +} + +template <> +inline void JsonArray::setNodeValue(node_type *node, const String &value) { + node->content = _buffer->strdup(value); } inline JsonVariant JsonArray::get(size_t index) const { @@ -42,11 +187,6 @@ inline T JsonArray::is(size_t index) const { return node ? node->content.is() : false; } -inline void JsonArray::set(size_t index, const JsonVariant value) { - node_type *node = getNodeAt(index); - if (node) node->content = value; -} - template inline const JsonArraySubscript JsonVariantBase::operator[]( int index) const { diff --git a/include/ArduinoJson/JsonArraySubscript.hpp b/include/ArduinoJson/JsonArraySubscript.hpp index 17783549..37f91ea6 100644 --- a/include/ArduinoJson/JsonArraySubscript.hpp +++ b/include/ArduinoJson/JsonArraySubscript.hpp @@ -6,18 +6,15 @@ #pragma once -#include "JsonVariantBase.hpp" +#include "JsonSubscriptBase.hpp" namespace ArduinoJson { -class JsonArraySubscript : public JsonVariantBase { +class JsonArraySubscript : public JsonSubscriptBase { public: FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) : _array(array), _index(index) {} - FORCE_INLINE JsonArraySubscript& operator=(const JsonVariant& value) { - _array.set(_index, value); - return *this; - } + using JsonSubscriptBase::operator=; FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& other) { // to prevent Visual Studio warning C4512: assignment operator could not be @@ -40,19 +37,25 @@ class JsonArraySubscript : public JsonVariantBase { return _array.is(_index); } - void writeTo(Internals::JsonWriter &writer) const { + void writeTo(Internals::JsonWriter& writer) const { _array.get(_index).writeTo(writer); } + template + void set(TValue value) { + _array.set(_index, value); + } + private: JsonArray& _array; const size_t _index; }; #ifdef ARDUINOJSON_ENABLE_STD_STREAM -inline std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& source) { +inline std::ostream& operator<<(std::ostream& os, + const JsonArraySubscript& source) { return source.printTo(os); } #endif -} // namespace ArduinoJson +} // namespace ArduinoJson diff --git a/include/ArduinoJson/JsonBuffer.hpp b/include/ArduinoJson/JsonBuffer.hpp index e1ef3b81..73c87374 100644 --- a/include/ArduinoJson/JsonBuffer.hpp +++ b/include/ArduinoJson/JsonBuffer.hpp @@ -8,8 +8,10 @@ #include // for size_t #include // for uint8_t +#include #include "Arduino/String.hpp" +#include "JsonVariant.hpp" #if defined(__clang__) #pragma clang diagnostic ignored "-Wnon-virtual-dtor" @@ -59,7 +61,7 @@ class JsonBuffer { // Same as above with a String class JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) { - return parseArray(const_cast(json.c_str()), nesting); + return parseArray(strdup(json), nesting); } // Allocates and populate a JsonObject from a JSON string. @@ -75,11 +77,15 @@ class JsonBuffer { JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); // Same as above with a String class - JsonObject &parseObject(const String &json, - uint8_t nestingLimit = DEFAULT_LIMIT) { - return parseObject(const_cast(json.c_str()), nestingLimit); + JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) { + return parseObject(strdup(json), nesting); } + // Duplicate a string + char *strdup(const char *src) { return strdup(src, strlen(src)); } + char *strdup(const String &src) { return strdup(src.c_str(), src.length()); } + char *strdup(const char *, size_t); + // Allocates n bytes in the JsonBuffer. // Return a pointer to the allocated memory or NULL if allocation fails. virtual void *alloc(size_t size) = 0; diff --git a/include/ArduinoJson/JsonObject.hpp b/include/ArduinoJson/JsonObject.hpp index d5da8e9e..f8cfac21 100644 --- a/include/ArduinoJson/JsonObject.hpp +++ b/include/ArduinoJson/JsonObject.hpp @@ -23,7 +23,6 @@ namespace ArduinoJson { // Forward declarations class JsonArray; class JsonBuffer; -class JsonObjectSubscript; // A dictionary of JsonVariant indexed by string (char*) // @@ -43,13 +42,45 @@ class JsonObject : public Internals::JsonPrintable, : Internals::List(buffer) {} // Gets or sets the value associated with the specified key. - FORCE_INLINE JsonObjectSubscript operator[](JsonObjectKey key); + FORCE_INLINE JsonObjectSubscript operator[](const char* key); + FORCE_INLINE JsonObjectSubscript operator[](const String& key); // Gets the value associated with the specified key. - FORCE_INLINE const JsonObjectSubscript operator[](JsonObjectKey key) const; + FORCE_INLINE JsonVariant operator[](JsonObjectKey key) const; // Sets the specified key with the specified value. - FORCE_INLINE bool set(JsonObjectKey key, JsonVariant value); + FORCE_INLINE bool set(const char* key, bool value); + FORCE_INLINE bool set(const char* key, float value, uint8_t decimals = 2); + FORCE_INLINE bool set(const char* key, double value, uint8_t decimals = 2); + FORCE_INLINE bool set(const char* key, signed char value); + FORCE_INLINE bool set(const char* key, signed long value); + FORCE_INLINE bool set(const char* key, signed int value); + FORCE_INLINE bool set(const char* key, signed short value); + FORCE_INLINE bool set(const char* key, unsigned char value); + FORCE_INLINE bool set(const char* key, unsigned long value); + FORCE_INLINE bool set(const char* key, unsigned int value); + FORCE_INLINE bool set(const char* key, unsigned short value); + FORCE_INLINE bool set(const char* key, const char* value); + FORCE_INLINE bool set(const char* key, const String& value); + FORCE_INLINE bool set(const char* key, JsonArray& array); + FORCE_INLINE bool set(const char* key, JsonObject& object); + FORCE_INLINE bool set(const char* key, const JsonVariant& value); + FORCE_INLINE bool set(const String& key, bool value); + FORCE_INLINE bool set(const String& key, float value, uint8_t decimals = 2); + FORCE_INLINE bool set(const String& key, double value, uint8_t decimals = 2); + FORCE_INLINE bool set(const String& key, signed char value); + FORCE_INLINE bool set(const String& key, signed long value); + FORCE_INLINE bool set(const String& key, signed int value); + FORCE_INLINE bool set(const String& key, signed short value); + FORCE_INLINE bool set(const String& key, unsigned char value); + FORCE_INLINE bool set(const String& key, unsigned long value); + FORCE_INLINE bool set(const String& key, unsigned int value); + FORCE_INLINE bool set(const String& key, unsigned short value); + FORCE_INLINE bool set(const String& key, const char* value); + FORCE_INLINE bool set(const String& key, const String& value); + FORCE_INLINE bool set(const String& key, JsonArray& array); + FORCE_INLINE bool set(const String& key, JsonObject& object); + FORCE_INLINE bool set(const String& key, const JsonVariant& value); // Gets the value associated with the specified key. FORCE_INLINE JsonVariant get(JsonObjectKey) const; @@ -64,11 +95,13 @@ class JsonObject : public Internals::JsonPrintable, // Creates and adds a JsonArray. // This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). - JsonArray& createNestedArray(JsonObjectKey key); + FORCE_INLINE JsonArray& createNestedArray(const char* key); + FORCE_INLINE JsonArray& createNestedArray(const String& key); // Creates and adds a JsonObject. // This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). - JsonObject& createNestedObject(JsonObjectKey key); + FORCE_INLINE JsonObject& createNestedObject(const char* key); + FORCE_INLINE JsonObject& createNestedObject(const String& key); // Tells weither the specified key is present and associated with a value. FORCE_INLINE bool containsKey(JsonObjectKey key) const; @@ -90,6 +123,21 @@ class JsonObject : public Internals::JsonPrintable, node_type* getOrCreateNodeAt(JsonObjectKey key); + template + FORCE_INLINE bool setNodeAt(TKey key, TValue value); + + template + JsonArray& createArrayAt(TKey key); + + template + JsonObject& createObjectAt(TKey key); + + template + FORCE_INLINE void setNodeKey(node_type*, T key); + + template + FORCE_INLINE void setNodeValue(node_type*, T value); + // The instance returned by JsonObject::invalid() static JsonObject _invalid; }; diff --git a/include/ArduinoJson/JsonObject.ipp b/include/ArduinoJson/JsonObject.ipp index ab57dc51..4db04d2e 100644 --- a/include/ArduinoJson/JsonObject.ipp +++ b/include/ArduinoJson/JsonObject.ipp @@ -28,41 +28,183 @@ inline bool JsonObject::is(JsonObjectKey key) const { return node ? node->content.value.is() : false; } -inline JsonObjectSubscript JsonObject::operator[](JsonObjectKey key) { - return JsonObjectSubscript(*this, key); +inline JsonObjectSubscript JsonObject::operator[]( + const char *key) { + return JsonObjectSubscript(*this, key); } -inline const JsonObjectSubscript JsonObject::operator[]( - JsonObjectKey key) const { - return JsonObjectSubscript(*const_cast(this), key); +inline JsonObjectSubscript JsonObject::operator[]( + const String &key) { + return JsonObjectSubscript(*this, key); +} + +inline JsonVariant JsonObject::operator[](JsonObjectKey key) const { + return get(key); } inline bool JsonObject::containsKey(JsonObjectKey key) const { return getNodeAt(key) != NULL; } +inline JsonArray &JsonObject::createNestedArray(const char *key) { + return createArrayAt(key); +} + +inline JsonArray &JsonObject::createNestedArray(const String &key) { + return createArrayAt(key); +} + +inline JsonObject &JsonObject::createNestedObject(const char *key) { + return createObjectAt(key); +} + +inline JsonObject &JsonObject::createNestedObject(const String &key) { + return createObjectAt(key); +} + inline void JsonObject::remove(JsonObjectKey key) { removeNode(getNodeAt(key)); } -inline bool JsonObject::set(JsonObjectKey key, const JsonVariant value) { +inline bool JsonObject::set(const char *key, bool value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, float value, uint8_t decimals) { + return setNodeAt( + key, JsonVariant(value, decimals)); +} +inline bool JsonObject::set(const char *key, double value, uint8_t decimals) { + return setNodeAt( + key, JsonVariant(value, decimals)); +} +inline bool JsonObject::set(const char *key, signed char value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, signed long value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, signed int value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, signed short value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, unsigned char value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, unsigned long value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, unsigned int value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, unsigned short value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, const char *value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, const String &value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const char *key, JsonArray &array) { + return setNodeAt(key, array); +} +inline bool JsonObject::set(const char *key, JsonObject &object) { + return setNodeAt(key, object); +} +inline bool JsonObject::set(const char *key, const JsonVariant &value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, bool value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, float value, uint8_t decimals) { + return setNodeAt( + key, JsonVariant(value, decimals)); +} +inline bool JsonObject::set(const String &key, double value, uint8_t decimals) { + return setNodeAt( + key, JsonVariant(value, decimals)); +} +inline bool JsonObject::set(const String &key, signed char value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, signed long value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, signed int value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, signed short value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, unsigned char value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, unsigned long value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, unsigned int value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, unsigned short value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, const char *value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, const String &value) { + return setNodeAt(key, value); +} +inline bool JsonObject::set(const String &key, JsonArray &array) { + return setNodeAt(key, array); +} +inline bool JsonObject::set(const String &key, JsonObject &object) { + return setNodeAt(key, object); +} +inline bool JsonObject::set(const String &key, const JsonVariant &value) { + return setNodeAt(key, value); +} + +template +inline bool JsonObject::setNodeAt(TKey key, TValue value) { node_type *node = getOrCreateNodeAt(key); if (!node) return false; - - node->content.key = key; - node->content.value = value; + setNodeKey(node, key); + setNodeValue(node, value); return true; } +template <> +inline void JsonObject::setNodeKey(node_type *node, const char *key) { + node->content.key = key; +} + +template <> +inline void JsonObject::setNodeKey(node_type *node, const String &key) { + node->content.key = _buffer->strdup(key); +} + +template +inline void JsonObject::setNodeValue(node_type *node, TValue value) { + node->content.value = value; +} + +template <> +inline void JsonObject::setNodeValue(node_type *node, const String &value) { + node->content.value = _buffer->strdup(value); +} + template -inline const JsonObjectSubscript JsonVariantBase::operator[]( - const char *key) const { +inline const JsonObjectSubscript JsonVariantBase:: +operator[](const char *key) const { return asObject()[key]; } template -inline const JsonObjectSubscript JsonVariantBase::operator[]( - const String &key) const { +inline const JsonObjectSubscript JsonVariantBase:: +operator[](const String &key) const { return asObject()[key]; } diff --git a/include/ArduinoJson/JsonObjectSubscript.hpp b/include/ArduinoJson/JsonObjectSubscript.hpp index 697e2b0e..aaf1e035 100644 --- a/include/ArduinoJson/JsonObjectSubscript.hpp +++ b/include/ArduinoJson/JsonObjectSubscript.hpp @@ -6,52 +6,64 @@ #pragma once -#include "JsonVariantBase.hpp" +#include "JsonSubscriptBase.hpp" namespace ArduinoJson { -class JsonObjectSubscript : public JsonVariantBase { + +template +class JsonObjectSubscript + : public JsonSubscriptBase > { public: - FORCE_INLINE JsonObjectSubscript(JsonObject& object, JsonObjectKey key) + FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key) : _object(object), _key(key) {} - FORCE_INLINE JsonObjectSubscript& operator=(const JsonVariant& value) { - _object.set(_key, value); - return *this; - } + using JsonSubscriptBase >::operator=; - FORCE_INLINE JsonObjectSubscript& operator=( - const JsonObjectSubscript& other) { + FORCE_INLINE JsonObjectSubscript& operator=( + const JsonObjectSubscript& other) { // to prevent Visual Studio warning C4512: assignment operator could not be // generated - _object.set(_key, other._object.get(other._key)); - return *this; + return set(other.get()); } FORCE_INLINE bool success() const { return _object.containsKey(_key); } FORCE_INLINE operator JsonVariant() const { return _object.get(_key); } - template - FORCE_INLINE T as() const { - return _object.get(_key); + template + FORCE_INLINE TValue as() const { + return _object.get(_key); } - template - FORCE_INLINE T is() const { - return _object.is(_key); + template + FORCE_INLINE TValue is() const { + return _object.is(_key); } - void writeTo(Internals::JsonWriter &writer) const { + template + FORCE_INLINE bool set(TValue value) { + return _object.set(_key, value); + } + + FORCE_INLINE JsonVariant get() { return _object.get(_key); } + + void writeTo(Internals::JsonWriter& writer) const { _object.get(_key).writeTo(writer); } private: JsonObject& _object; - JsonObjectKey _key; + TKey _key; }; #ifdef ARDUINOJSON_ENABLE_STD_STREAM -inline std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& source) { +inline std::ostream& operator<<( + std::ostream& os, const JsonObjectSubscript& source) { + return source.printTo(os); +} + +inline std::ostream& operator<<( + std::ostream& os, const JsonObjectSubscript& source) { return source.printTo(os); } #endif diff --git a/include/ArduinoJson/JsonSubscriptBase.hpp b/include/ArduinoJson/JsonSubscriptBase.hpp new file mode 100644 index 00000000..12406156 --- /dev/null +++ b/include/ArduinoJson/JsonSubscriptBase.hpp @@ -0,0 +1,82 @@ +// Copyright Benoit Blanchon 2014-2015 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson + +#pragma once + +#include "JsonVariantBase.hpp" + +namespace ArduinoJson { + +template +class JsonSubscriptBase : public JsonVariantBase { + public: + FORCE_INLINE TImpl& operator=(bool value) { return assign(value); } + + FORCE_INLINE TImpl& operator=(float value) { return assign(value); } + + FORCE_INLINE TImpl& operator=(double value) { return assign(value); } + + FORCE_INLINE TImpl& operator=(signed char value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(signed long value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(signed int value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(signed short value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(unsigned char value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(unsigned long value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(unsigned int value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(unsigned short value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(const char* value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(const String& value) { + return assign(value); + } + + FORCE_INLINE TImpl& operator=(JsonArray& array) { + return assign(array); + } + + FORCE_INLINE TImpl& operator=(JsonObject& object) { + return assign(object); + } + + FORCE_INLINE TImpl& operator=(JsonVariant value) { + return assign(value); + } + + private: + template + FORCE_INLINE TImpl& assign(TValue value) { + TImpl* impl = static_cast(this); + impl->template set(value); + return *impl; + } +}; +} diff --git a/include/ArduinoJson/JsonVariant.hpp b/include/ArduinoJson/JsonVariant.hpp index 1ee1acc5..9258abcd 100644 --- a/include/ArduinoJson/JsonVariant.hpp +++ b/include/ArduinoJson/JsonVariant.hpp @@ -9,7 +9,6 @@ #include #include // for uint8_t -#include "Arduino/String.hpp" #include "Internals/JsonPrintable.hpp" #include "Internals/JsonVariantContent.hpp" #include "Internals/JsonVariantType.hpp" @@ -55,7 +54,6 @@ class JsonVariant : public JsonVariantBase { // Create a JsonVariant containing a string. FORCE_INLINE JsonVariant(const char *value); - FORCE_INLINE JsonVariant(const String &value); // Create a JsonVariant containing a reference to an array. FORCE_INLINE JsonVariant(JsonArray &array); diff --git a/include/ArduinoJson/JsonVariant.ipp b/include/ArduinoJson/JsonVariant.ipp index 818fea69..ec347ba3 100644 --- a/include/ArduinoJson/JsonVariant.ipp +++ b/include/ArduinoJson/JsonVariant.ipp @@ -20,11 +20,6 @@ inline JsonVariant::JsonVariant(const char *value) { _content.asString = value; } -inline JsonVariant::JsonVariant(const String &value) { - _type = Internals::JSON_STRING; - _content.asString = value.c_str(); -} - inline JsonVariant::JsonVariant(double value, uint8_t decimals) { _type = static_cast( Internals::JSON_DOUBLE_0_DECIMALS + decimals); @@ -112,11 +107,6 @@ inline bool JsonVariant::is() const { return _type == Internals::JSON_STRING; } -template <> -inline bool JsonVariant::is() const { - return _type == Internals::JSON_STRING; -} - template <> inline bool JsonVariant::is() const { return _type >= Internals::JSON_DOUBLE_0_DECIMALS; @@ -188,9 +178,9 @@ inline bool JsonVariant::is() const { } #ifdef ARDUINOJSON_ENABLE_STD_STREAM -inline std::ostream& operator<<(std::ostream& os, const JsonVariant& source) { +inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) { return source.printTo(os); } #endif -} // namespace ArduinoJson +} // namespace ArduinoJson diff --git a/include/ArduinoJson/JsonVariantBase.hpp b/include/ArduinoJson/JsonVariantBase.hpp index fba044b0..87cd081d 100644 --- a/include/ArduinoJson/JsonVariantBase.hpp +++ b/include/ArduinoJson/JsonVariantBase.hpp @@ -13,6 +13,7 @@ namespace ArduinoJson { // Forward declarations. class JsonArraySubscript; +template class JsonObjectSubscript; template @@ -76,8 +77,10 @@ class JsonVariantBase : public Internals::JsonPrintable { // Returns the value associated with the specified key if the variant is // an object. // Return JsonVariant::invalid() if the variant is not an object. - FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const; - FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const; + FORCE_INLINE const JsonObjectSubscript operator[]( + const char *key) const; + FORCE_INLINE const JsonObjectSubscript operator[]( + const String &key) const; // Serialize the variant to a JsonWriter void writeTo(Internals::JsonWriter &writer) const; diff --git a/src/DynamicJsonBuffer.cpp b/src/DynamicJsonBuffer.cpp index f0fb9393..3494dfbb 100644 --- a/src/DynamicJsonBuffer.cpp +++ b/src/DynamicJsonBuffer.cpp @@ -49,7 +49,7 @@ size_t DynamicJsonBuffer::size() const { } void* DynamicJsonBuffer::alloc(size_t bytes) { - if (!canAllocInHead(bytes)) addNewBlock(); + while (!canAllocInHead(bytes)) addNewBlock(); return allocInHead(bytes); } diff --git a/src/JsonBuffer.cpp b/src/JsonBuffer.cpp index d47fac85..755705e5 100644 --- a/src/JsonBuffer.cpp +++ b/src/JsonBuffer.cpp @@ -32,3 +32,10 @@ JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) { JsonParser parser(this, json, nestingLimit); return parser.parseObject(); } + +char *JsonBuffer::strdup(const char *source, size_t length) { + size_t size = length + 1; + char *dest = static_cast(alloc(size)); + if (dest != NULL) memcpy(dest, source, size); + return dest; +} diff --git a/src/JsonObject.cpp b/src/JsonObject.cpp index 77aae413..81f74563 100644 --- a/src/JsonObject.cpp +++ b/src/JsonObject.cpp @@ -25,19 +25,25 @@ JsonObject::node_type *JsonObject::getOrCreateNodeAt(JsonObjectKey key) { return newNode; } -JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { +template +JsonArray &JsonObject::createArrayAt(TKey key) { if (!_buffer) return JsonArray::invalid(); JsonArray &array = _buffer->createArray(); - set(key, array); + setNodeAt(key, array); return array; } +template JsonArray &JsonObject::createArrayAt(const char *); +template JsonArray &JsonObject::createArrayAt(const String &); -JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { +template +JsonObject &JsonObject::createObjectAt(TKey key) { if (!_buffer) return JsonObject::invalid(); - JsonObject &object = _buffer->createObject(); - set(key, object); - return object; + JsonObject &array = _buffer->createObject(); + setNodeAt(key, array); + return array; } +template JsonObject &JsonObject::createObjectAt(const char *); +template JsonObject &JsonObject::createObjectAt(const String &); JsonObject::node_type *JsonObject::getNodeAt(JsonObjectKey key) const { for (node_type *node = _firstNode; node; node = node->next) { diff --git a/test/ArduinoString_Tests.cpp b/test/ArduinoString_Tests.cpp index 2aa6c540..ed0899c6 100644 --- a/test/ArduinoString_Tests.cpp +++ b/test/ArduinoString_Tests.cpp @@ -7,103 +7,160 @@ #include #include -TEST(ArduinoStringTests, JsonBuffer_ParseArray) { - DynamicJsonBuffer jsonBuffer; - String json("[1,2]"); - JsonArray &array = jsonBuffer.parseArray(json); +class ArduinoStringTests : public ::testing::Test { + protected: + static void eraseString(String &str) { + char *p = const_cast(str.c_str()); + while (*p) *p++ = '*'; + } + + DynamicJsonBuffer _jsonBuffer; +}; + +TEST_F(ArduinoStringTests, JsonBuffer_ParseArray) { + String json("[\"hello\"]"); + JsonArray &array = _jsonBuffer.parseArray(json); + eraseString(json); ASSERT_TRUE(array.success()); + ASSERT_STREQ("hello", array[0]); } -TEST(ArduinoStringTests, JsonBuffer_ParseObject) { - DynamicJsonBuffer jsonBuffer; - String json("{\"a\":1,\"b\":2}"); - JsonObject &object = jsonBuffer.parseObject(json); +TEST_F(ArduinoStringTests, JsonBuffer_ParseObject) { + String json("{\"hello\":\"world\"}"); + JsonObject &object = _jsonBuffer.parseObject(json); + eraseString(json); ASSERT_TRUE(object.success()); + ASSERT_STREQ("world", object["hello"]); } -TEST(ArduinoStringTests, JsonVariant) { - String input = "Hello world!"; - JsonVariant variant(input); - ASSERT_TRUE(variant.is()); - String output = variant.as(); - ASSERT_EQ(input, output); -} - -TEST(ArduinoStringTests, JsonObject_Subscript) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_Subscript) { char json[] = "{\"key\":\"value\"}"; - JsonObject &object = jsonBuffer.parseObject(json); + JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_STREQ("value", object[String("key")]); } -TEST(ArduinoStringTests, JsonObject_ConstSubscript) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_ConstSubscript) { char json[] = "{\"key\":\"value\"}"; - const JsonObject &object = jsonBuffer.parseObject(json); + const JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_STREQ("value", object[String("key")]); } -TEST(ArduinoStringTests, JsonObject_Set) { - DynamicJsonBuffer jsonBuffer; - JsonObject &object = jsonBuffer.createObject(); - String key = "key"; - object.set(key, "value"); - ASSERT_STREQ("value", object["key"]); +TEST_F(ArduinoStringTests, JsonObject_SetKey) { + JsonObject &object = _jsonBuffer.createObject(); + String key("hello"); + object.set(key, "world"); + eraseString(key); + ASSERT_STREQ("world", object["hello"]); } -TEST(ArduinoStringTests, JsonObject_Get) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_SetValue) { + JsonObject &object = _jsonBuffer.createObject(); + String value("world"); + object.set("hello", value); + eraseString(value); + ASSERT_STREQ("world", object["hello"]); +} + +TEST_F(ArduinoStringTests, JsonObject_SetKeyValue) { + JsonObject &object = _jsonBuffer.createObject(); + String key("hello"); + String value("world"); + object.set(key, value); + eraseString(key); + eraseString(value); + ASSERT_STREQ("world", object["hello"]); +} + +TEST_F(ArduinoStringTests, JsonObject_Get) { char json[] = "{\"key\":\"value\"}"; - const JsonObject &object = jsonBuffer.parseObject(json); + const JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_STREQ("value", object.get(String("key"))); } -TEST(ArduinoStringTests, JsonObject_GetT) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_GetT) { char json[] = "{\"key\":\"value\"}"; - const JsonObject &object = jsonBuffer.parseObject(json); + const JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_STREQ("value", object.get(String("key"))); } -TEST(ArduinoStringTests, JsonObject_IsT) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_IsT) { char json[] = "{\"key\":\"value\"}"; - const JsonObject &object = jsonBuffer.parseObject(json); + const JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_TRUE(object.is(String("key"))); } -TEST(ArduinoStringTests, JsonObject_CreateNestedObject) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) { String key = "key"; char json[64]; - JsonObject &object = jsonBuffer.createObject(); + JsonObject &object = _jsonBuffer.createObject(); object.createNestedObject(key); + eraseString(key); object.printTo(json, sizeof(json)); ASSERT_STREQ("{\"key\":{}}", json); } -TEST(ArduinoStringTests, JsonObject_CreateNestedArray) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) { String key = "key"; char json[64]; - JsonObject &object = jsonBuffer.createObject(); + JsonObject &object = _jsonBuffer.createObject(); object.createNestedArray(key); + eraseString(key); object.printTo(json, sizeof(json)); ASSERT_STREQ("{\"key\":[]}", json); } -TEST(ArduinoStringTests, JsonObject_ContainsKey) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_ContainsKey) { char json[] = "{\"key\":\"value\"}"; - const JsonObject &object = jsonBuffer.parseObject(json); + const JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_TRUE(object.containsKey(String("key"))); } -TEST(ArduinoStringTests, JsonObject_Remove) { - DynamicJsonBuffer jsonBuffer; +TEST_F(ArduinoStringTests, JsonObject_Remove) { char json[] = "{\"key\":\"value\"}"; - JsonObject &object = jsonBuffer.parseObject(json); + JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_EQ(1, object.size()); object.remove(String("key")); ASSERT_EQ(0, object.size()); -} \ No newline at end of file +} + +TEST_F(ArduinoStringTests, JsonObjectSubscript_SetKey) { + JsonObject &object = _jsonBuffer.createObject(); + String key("hello"); + object[key] = "world"; + eraseString(key); + ASSERT_STREQ("world", object["hello"]); +} + +TEST_F(ArduinoStringTests, JsonObjectSubscript_SetValue) { + JsonObject &object = _jsonBuffer.createObject(); + String value("world"); + object["hello"] = value; + eraseString(value); + ASSERT_STREQ("world", object["hello"]); +} + +TEST_F(ArduinoStringTests, JsonArray_Add) { + JsonArray &array = _jsonBuffer.createArray(); + String value("hello"); + array.add(value); + eraseString(value); + ASSERT_STREQ("hello", array[0]); +} + +TEST_F(ArduinoStringTests, JsonArray_Set) { + JsonArray &array = _jsonBuffer.createArray(); + String value("world"); + array.add("hello"); + array.set(0, value); + eraseString(value); + ASSERT_STREQ("world", array[0]); +} + +TEST_F(ArduinoStringTests, JsonArraySubscript) { + JsonArray &array = _jsonBuffer.createArray(); + String value("world"); + array.add("hello"); + array[0] = value; + eraseString(value); + ASSERT_STREQ("world", array[0]); +} diff --git a/test/JsonObject_Container_Tests.cpp b/test/JsonObject_Container_Tests.cpp index e1ee775a..dc183749 100644 --- a/test/JsonObject_Container_Tests.cpp +++ b/test/JsonObject_Container_Tests.cpp @@ -59,7 +59,7 @@ TEST_F(JsonObject_Container_Tests, TEST_F(JsonObject_Container_Tests, CanStoreIntegers) { _object["hello"] = 123; - _object["world"] = 456; + _object.set("world", 456); EXPECT_EQ(123, _object["hello"].as()); EXPECT_EQ(456, _object["world"].as()); @@ -67,7 +67,7 @@ TEST_F(JsonObject_Container_Tests, CanStoreIntegers) { TEST_F(JsonObject_Container_Tests, CanStoreDoubles) { _object["hello"] = 123.45; - _object["world"] = 456.78; + _object.set("world", 456.78); EXPECT_EQ(123.45, _object["hello"].as()); EXPECT_EQ(456.78, _object["world"].as()); @@ -75,7 +75,7 @@ TEST_F(JsonObject_Container_Tests, CanStoreDoubles) { TEST_F(JsonObject_Container_Tests, CanStoreBooleans) { _object["hello"] = true; - _object["world"] = false; + _object.set("world", false); EXPECT_TRUE(_object["hello"].as()); EXPECT_FALSE(_object["world"].as()); @@ -83,32 +83,32 @@ TEST_F(JsonObject_Container_Tests, CanStoreBooleans) { TEST_F(JsonObject_Container_Tests, CanStoreStrings) { _object["hello"] = "h3110"; - _object["world"] = "w0r1d"; + _object.set("world", "w0r1d"); EXPECT_STREQ("h3110", _object["hello"].as()); EXPECT_STREQ("w0r1d", _object["world"].as()); } -TEST_F(JsonObject_Container_Tests, CanStoreInnerArrays) { - JsonArray& innerarray1 = _jsonBuffer.createArray(); - JsonArray& innerarray2 = _jsonBuffer.createArray(); +TEST_F(JsonObject_Container_Tests, CanStoreArrays) { + JsonArray& array1 = _jsonBuffer.createArray(); + JsonArray& array2 = _jsonBuffer.createArray(); - _object["hello"] = innerarray1; - _object["world"] = innerarray2; + _object["hello"] = array1; + _object.set("world", array2); - EXPECT_EQ(&innerarray1, &_object["hello"].asArray()); - EXPECT_EQ(&innerarray2, &_object["world"].asArray()); + EXPECT_EQ(&array1, &_object["hello"].asArray()); + EXPECT_EQ(&array2, &_object["world"].asArray()); } -TEST_F(JsonObject_Container_Tests, CanStoreInnerObjects) { - JsonObject& innerObject1 = _jsonBuffer.createObject(); - JsonObject& innerObject2 = _jsonBuffer.createObject(); +TEST_F(JsonObject_Container_Tests, CanStoreObjects) { + JsonObject& object1 = _jsonBuffer.createObject(); + JsonObject& object2 = _jsonBuffer.createObject(); - _object["hello"] = innerObject1; - _object["world"] = innerObject2; + _object["hello"] = object1; + _object.set("world", object2); - EXPECT_EQ(&innerObject1, &_object["hello"].asObject()); - EXPECT_EQ(&innerObject2, &_object["world"].asObject()); + EXPECT_EQ(&object1, &_object["hello"].asObject()); + EXPECT_EQ(&object2, &_object["world"].asObject()); } TEST_F(JsonObject_Container_Tests, ContainsKeyReturnsFalseForNonExistingKey) { diff --git a/test/JsonObject_PrintTo_Tests.cpp b/test/JsonObject_PrintTo_Tests.cpp index f9057d4b..60f7ce2e 100644 --- a/test/JsonObject_PrintTo_Tests.cpp +++ b/test/JsonObject_PrintTo_Tests.cpp @@ -11,131 +11,105 @@ using namespace ArduinoJson::Internals; class JsonObject_PrintTo_Tests : public testing::Test { public: - JsonObject_PrintTo_Tests() : object(json.createObject()) {} + JsonObject_PrintTo_Tests() : _object(_jsonBuffer.createObject()) {} protected: void outputMustBe(const char *expected) { char actual[256]; - size_t actualLen = object.printTo(actual, sizeof(actual)); - size_t measuredLen = object.measureLength(); + size_t actualLen = _object.printTo(actual, sizeof(actual)); + size_t measuredLen = _object.measureLength(); EXPECT_STREQ(expected, actual); EXPECT_EQ(strlen(expected), actualLen); EXPECT_EQ(strlen(expected), measuredLen); } - StaticJsonBuffer json; - JsonObject &object; + DynamicJsonBuffer _jsonBuffer; + JsonObject &_object; }; TEST_F(JsonObject_PrintTo_Tests, EmptyObject) { outputMustBe("{}"); } -TEST_F(JsonObject_PrintTo_Tests, OneString) { - object["key"] = "value"; - - outputMustBe("{\"key\":\"value\"}"); -} - TEST_F(JsonObject_PrintTo_Tests, TwoStrings) { - object["key1"] = "value1"; - object["key2"] = "value2"; + _object["key1"] = "value1"; + _object.set("key2", "value2"); outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}"); } TEST_F(JsonObject_PrintTo_Tests, RemoveFirst) { - object["key1"] = "value1"; - object["key2"] = "value2"; - object.remove("key1"); + _object["key1"] = "value1"; + _object["key2"] = "value2"; + _object.remove("key1"); outputMustBe("{\"key2\":\"value2\"}"); } TEST_F(JsonObject_PrintTo_Tests, RemoveLast) { - object["key1"] = "value1"; - object["key2"] = "value2"; - object.remove("key2"); + _object["key1"] = "value1"; + _object["key2"] = "value2"; + _object.remove("key2"); outputMustBe("{\"key1\":\"value1\"}"); } TEST_F(JsonObject_PrintTo_Tests, RemoveUnexistingKey) { - object["key1"] = "value1"; - object["key2"] = "value2"; - object.remove("key3"); + _object["key1"] = "value1"; + _object["key2"] = "value2"; + _object.remove("key3"); outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}"); } TEST_F(JsonObject_PrintTo_Tests, ReplaceExistingKey) { - object["key"] = "value1"; - object["key"] = "value2"; + _object["key"] = "value1"; + _object["key"] = "value2"; outputMustBe("{\"key\":\"value2\"}"); } -TEST_F(JsonObject_PrintTo_Tests, OneStringOverCapacity) { - object["key1"] = "value1"; - object["key2"] = "value2"; - object["key3"] = "value3"; - - outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}"); +TEST_F(JsonObject_PrintTo_Tests, TwoIntegers) { + _object["a"] = 1; + _object.set("b", 2); + outputMustBe("{\"a\":1,\"b\":2}"); } -TEST_F(JsonObject_PrintTo_Tests, OneInteger) { - object["key"] = 1; - outputMustBe("{\"key\":1}"); +TEST_F(JsonObject_PrintTo_Tests, TwoDoublesFourDigits) { + _object["a"] = double_with_n_digits(3.14159265358979323846, 4); + _object.set("b", 2.71828182845904523536, 4); + outputMustBe("{\"a\":3.1416,\"b\":2.7183}"); } -TEST_F(JsonObject_PrintTo_Tests, OneDoubleFourDigits) { - object["key"] = double_with_n_digits(3.14159265358979323846, 4); - outputMustBe("{\"key\":3.1416}"); +TEST_F(JsonObject_PrintTo_Tests, TwoDoubleDefaultDigits) { + _object["a"] = 3.14159265358979323846; + _object.set("b", 2.71828182845904523536); + outputMustBe("{\"a\":3.14,\"b\":2.72}"); } -TEST_F(JsonObject_PrintTo_Tests, OneDoubleDefaultDigits) { - object["key"] = 3.14159265358979323846; - outputMustBe("{\"key\":3.14}"); +TEST_F(JsonObject_PrintTo_Tests, TwoNull) { + _object["a"] = static_cast(0); + _object.set("b", static_cast(0)); + outputMustBe("{\"a\":null,\"b\":null}"); } -TEST_F(JsonObject_PrintTo_Tests, OneNull) { - object["key"] = static_cast(0); - outputMustBe("{\"key\":null}"); +TEST_F(JsonObject_PrintTo_Tests, TwoBooleans) { + _object["a"] = true; + _object.set("b", false); + outputMustBe("{\"a\":true,\"b\":false}"); } -TEST_F(JsonObject_PrintTo_Tests, OneTrue) { - object["key"] = true; - outputMustBe("{\"key\":true}"); +TEST_F(JsonObject_PrintTo_Tests, ThreeNestedArrays) { + _object.createNestedArray("a"); + _object["b"] = _jsonBuffer.createArray(); + _object.set("c", _jsonBuffer.createArray()); + + outputMustBe("{\"a\":[],\"b\":[],\"c\":[]}"); } -TEST_F(JsonObject_PrintTo_Tests, OneFalse) { - object["key"] = false; - outputMustBe("{\"key\":false}"); -} - -TEST_F(JsonObject_PrintTo_Tests, OneEmptyNestedArrayViaProxy) { - JsonArray &nestedArray = json.createArray(); - - object["key"] = nestedArray; - - outputMustBe("{\"key\":[]}"); -} - -TEST_F(JsonObject_PrintTo_Tests, OneEmptyNestedObjectViaProxy) { - JsonObject &nestedArray = json.createObject(); - - object["key"] = nestedArray; - - outputMustBe("{\"key\":{}}"); -} - -TEST_F(JsonObject_PrintTo_Tests, OneEmptyNestedObject) { - object.createNestedObject("key"); - - outputMustBe("{\"key\":{}}"); -} - -TEST_F(JsonObject_PrintTo_Tests, OneEmptyNestedArray) { - object.createNestedArray("key"); - - outputMustBe("{\"key\":[]}"); +TEST_F(JsonObject_PrintTo_Tests, ThreeNestedObjects) { + _object.createNestedObject("a"); + _object["b"] = _jsonBuffer.createObject(); + _object.set("c", _jsonBuffer.createObject()); + + outputMustBe("{\"a\":{},\"b\":{},\"c\":{}}"); } diff --git a/test/StaticJsonBuffer_CreateObject_Tests.cpp b/test/StaticJsonBuffer_CreateObject_Tests.cpp index 3ddd0274..fc46dba9 100644 --- a/test/StaticJsonBuffer_CreateObject_Tests.cpp +++ b/test/StaticJsonBuffer_CreateObject_Tests.cpp @@ -8,44 +8,49 @@ #include TEST(StaticJsonBuffer_CreateObject_Tests, GrowsWithObject) { - StaticJsonBuffer json; + StaticJsonBuffer buffer; - JsonObject &obj = json.createObject(); - ASSERT_EQ(JSON_OBJECT_SIZE(0), json.size()); + JsonObject &obj = buffer.createObject(); + ASSERT_EQ(JSON_OBJECT_SIZE(0), buffer.size()); obj["hello"]; - ASSERT_EQ(JSON_OBJECT_SIZE(0), json.size()); + ASSERT_EQ(JSON_OBJECT_SIZE(0), buffer.size()); obj["hello"] = 1; - ASSERT_EQ(JSON_OBJECT_SIZE(1), json.size()); + ASSERT_EQ(JSON_OBJECT_SIZE(1), buffer.size()); obj["world"] = 2; - ASSERT_EQ(JSON_OBJECT_SIZE(2), json.size()); + ASSERT_EQ(JSON_OBJECT_SIZE(2), buffer.size()); obj["world"] = 3; // <- same key, should not grow - ASSERT_EQ(JSON_OBJECT_SIZE(2), json.size()); + ASSERT_EQ(JSON_OBJECT_SIZE(2), buffer.size()); } TEST(StaticJsonBuffer_CreateObject_Tests, SucceedWhenBigEnough) { - StaticJsonBuffer json; + StaticJsonBuffer buffer; - JsonObject &object = json.createObject(); + JsonObject &object = buffer.createObject(); ASSERT_TRUE(object.success()); } TEST(StaticJsonBuffer_CreateObject_Tests, FailsWhenTooSmall) { - StaticJsonBuffer json; + StaticJsonBuffer buffer; - JsonObject &object = json.createObject(); + JsonObject &object = buffer.createObject(); ASSERT_FALSE(object.success()); } TEST(StaticJsonBuffer_CreateObject_Tests, ObjectDoesntGrowWhenFull) { - StaticJsonBuffer json; + StaticJsonBuffer buffer; - JsonObject &obj = json.createObject(); + JsonObject &obj = buffer.createObject(); obj["hello"] = 1; obj["world"] = 2; - ASSERT_EQ(JSON_OBJECT_SIZE(1), json.size()); + ASSERT_EQ(JSON_OBJECT_SIZE(1), buffer.size()); + ASSERT_EQ(1, obj.size()); + + char json[64]; + obj.printTo(json, sizeof(json)); + ASSERT_STREQ("{\"hello\":1}", json); }