Implicitly duplicate String in the JsonBuffer (issue #84, #87)

This commit is contained in:
Benoit Blanchon
2015-07-25 15:38:12 +02:00
parent 92e687303d
commit c161f698fc
20 changed files with 762 additions and 253 deletions

View File

@ -4,9 +4,11 @@ ArduinoJson: change log
v5.0 (currently in beta) 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) * 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) * Switched to new the library layout (requires Arduino 1.0.6 or above)
**BREAKING CHANGES**: **BREAKING CHANGES**:

View File

@ -23,11 +23,6 @@ inline char const* JsonVariantContent::as<char const*>() const {
return asString; return asString;
} }
template <>
inline String JsonVariantContent::as<String>() const {
return asString;
}
template <> template <>
inline double JsonVariantContent::as<double>() const { inline double JsonVariantContent::as<double>() const {
return asDouble; return asDouble;

View File

@ -42,16 +42,46 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
: Internals::List<JsonVariant>(buffer) {} : Internals::List<JsonVariant>(buffer) {}
// Gets the value at the specified index // 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 // Gets or sets the value at specified index
FORCE_INLINE JsonArraySubscript operator[](size_t index); FORCE_INLINE JsonArraySubscript operator[](size_t index);
// Adds the specified value at the end of the array. // 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. // 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. // Gets the value at the specified index.
FORCE_INLINE JsonVariant get(size_t index) const; FORCE_INLINE JsonVariant get(size_t index) const;
@ -86,6 +116,15 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
private: private:
node_type *getNodeAt(size_t index) const; node_type *getNodeAt(size_t index) const;
template <typename TValue>
void setNodeAt(size_t index, TValue value);
template <typename TValue>
bool addNode(TValue);
template <typename T>
FORCE_INLINE void setNodeValue(node_type *, T value);
// The instance returned by JsonArray::invalid() // The instance returned by JsonArray::invalid()
static JsonArray _invalid; static JsonArray _invalid;
}; };

View File

@ -15,14 +15,159 @@ inline JsonArraySubscript JsonArray::operator[](size_t index) {
return JsonArraySubscript(*this, index); return JsonArraySubscript(*this, index);
} }
inline const JsonArraySubscript JsonArray::operator[](size_t index) const { inline JsonVariant JsonArray::operator[](size_t index) const {
return JsonArraySubscript(*const_cast<JsonArray *>(this), index); return get(index);
} }
inline bool JsonArray::add(const JsonVariant value) { inline bool JsonArray::add(bool value) { return addNode<bool>(value); }
inline bool JsonArray::add(float value, uint8_t decimals) {
return addNode<const JsonVariant &>(JsonVariant(value, decimals));
}
inline bool JsonArray::add(double value, uint8_t decimals) {
return addNode<const JsonVariant &>(JsonVariant(value, decimals));
}
inline bool JsonArray::add(signed char value) {
return addNode<signed char>(value);
}
inline bool JsonArray::add(signed long value) {
return addNode<signed long>(value);
}
inline bool JsonArray::add(signed int value) {
return addNode<signed int>(value);
}
inline bool JsonArray::add(signed short value) {
return addNode<signed short>(value);
}
inline bool JsonArray::add(unsigned char value) {
return addNode<unsigned char>(value);
}
inline bool JsonArray::add(unsigned long value) {
return addNode<unsigned long>(value);
}
inline bool JsonArray::add(unsigned int value) {
return addNode<unsigned int>(value);
}
inline bool JsonArray::add(unsigned short value) {
return addNode<unsigned short>(value);
}
inline bool JsonArray::add(const char *value) {
return addNode<const char *>(value);
}
inline bool JsonArray::add(const String &value) {
return addNode<const String &>(value);
}
inline bool JsonArray::add(JsonArray &array) {
return addNode<JsonArray &>(array);
}
inline bool JsonArray::add(JsonObject &object) {
return addNode<JsonObject &>(object);
}
inline bool JsonArray::add(const JsonVariant &object) {
return addNode<const JsonVariant &>(object);
}
template <typename TValue>
inline bool JsonArray::addNode(TValue value) {
node_type *node = addNewNode(); node_type *node = addNewNode();
if (node) node->content = value; if (node == NULL) return false;
return node != NULL; setNodeValue<TValue>(node, value);
return true;
}
inline void JsonArray::set(size_t index, bool value) {
return setNodeAt<bool>(index, value);
}
inline void JsonArray::set(size_t index, float value, uint8_t decimals) {
return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals));
}
inline void JsonArray::set(size_t index, double value, uint8_t decimals) {
return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals));
}
inline void JsonArray::set(size_t index, signed char value) {
return setNodeAt<signed char>(index, value);
}
inline void JsonArray::set(size_t index, signed long value) {
return setNodeAt<signed long>(index, value);
}
inline void JsonArray::set(size_t index, signed int value) {
return setNodeAt<signed int>(index, value);
}
inline void JsonArray::set(size_t index, signed short value) {
return setNodeAt<signed short>(index, value);
}
inline void JsonArray::set(size_t index, unsigned char value) {
return setNodeAt<unsigned char>(index, value);
}
inline void JsonArray::set(size_t index, unsigned long value) {
return setNodeAt<unsigned long>(index, value);
}
inline void JsonArray::set(size_t index, unsigned int value) {
return setNodeAt<unsigned int>(index, value);
}
inline void JsonArray::set(size_t index, unsigned short value) {
return setNodeAt<unsigned short>(index, value);
}
inline void JsonArray::set(size_t index, const char *value) {
return setNodeAt<const char *>(index, value);
}
inline void JsonArray::set(size_t index, const String &value) {
return setNodeAt<const String &>(index, value);
}
inline void JsonArray::set(size_t index, JsonArray &array) {
return setNodeAt<JsonArray &>(index, array);
}
inline void JsonArray::set(size_t index, JsonObject &object) {
return setNodeAt<JsonObject &>(index, object);
}
inline void JsonArray::set(size_t index, const JsonVariant &object) {
return setNodeAt<const JsonVariant &>(index, object);
}
template <typename TValue>
inline void JsonArray::setNodeAt(size_t index, TValue value) {
node_type *node = getNodeAt(index);
if (node == NULL) return;
setNodeValue<TValue>(node, value);
}
template <typename TValue>
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 { 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<T>() : false; return node ? node->content.is<T>() : false;
} }
inline void JsonArray::set(size_t index, const JsonVariant value) {
node_type *node = getNodeAt(index);
if (node) node->content = value;
}
template <typename TImplem> template <typename TImplem>
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[]( inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
int index) const { int index) const {

View File

@ -6,18 +6,15 @@
#pragma once #pragma once
#include "JsonVariantBase.hpp" #include "JsonSubscriptBase.hpp"
namespace ArduinoJson { namespace ArduinoJson {
class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { class JsonArraySubscript : public JsonSubscriptBase<JsonArraySubscript> {
public: public:
FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
: _array(array), _index(index) {} : _array(array), _index(index) {}
FORCE_INLINE JsonArraySubscript& operator=(const JsonVariant& value) { using JsonSubscriptBase::operator=;
_array.set(_index, value);
return *this;
}
FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& other) { FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& other) {
// to prevent Visual Studio warning C4512: assignment operator could not be // to prevent Visual Studio warning C4512: assignment operator could not be
@ -40,17 +37,23 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
return _array.is<T>(_index); return _array.is<T>(_index);
} }
void writeTo(Internals::JsonWriter &writer) const { void writeTo(Internals::JsonWriter& writer) const {
_array.get(_index).writeTo(writer); _array.get(_index).writeTo(writer);
} }
template <typename TValue>
void set(TValue value) {
_array.set(_index, value);
}
private: private:
JsonArray& _array; JsonArray& _array;
const size_t _index; const size_t _index;
}; };
#ifdef ARDUINOJSON_ENABLE_STD_STREAM #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); return source.printTo(os);
} }
#endif #endif

View File

@ -8,8 +8,10 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <stdint.h> // for uint8_t #include <stdint.h> // for uint8_t
#include <string.h>
#include "Arduino/String.hpp" #include "Arduino/String.hpp"
#include "JsonVariant.hpp"
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic ignored "-Wnon-virtual-dtor" #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
@ -59,7 +61,7 @@ class JsonBuffer {
// Same as above with a String class // Same as above with a String class
JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) { JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
return parseArray(const_cast<char *>(json.c_str()), nesting); return parseArray(strdup(json), nesting);
} }
// Allocates and populate a JsonObject from a JSON string. // Allocates and populate a JsonObject from a JSON string.
@ -75,11 +77,15 @@ class JsonBuffer {
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
// Same as above with a String class // Same as above with a String class
JsonObject &parseObject(const String &json, JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
uint8_t nestingLimit = DEFAULT_LIMIT) { return parseObject(strdup(json), nesting);
return parseObject(const_cast<char *>(json.c_str()), nestingLimit);
} }
// 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. // Allocates n bytes in the JsonBuffer.
// Return a pointer to the allocated memory or NULL if allocation fails. // Return a pointer to the allocated memory or NULL if allocation fails.
virtual void *alloc(size_t size) = 0; virtual void *alloc(size_t size) = 0;

View File

@ -23,7 +23,6 @@ namespace ArduinoJson {
// Forward declarations // Forward declarations
class JsonArray; class JsonArray;
class JsonBuffer; class JsonBuffer;
class JsonObjectSubscript;
// A dictionary of JsonVariant indexed by string (char*) // A dictionary of JsonVariant indexed by string (char*)
// //
@ -43,13 +42,45 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
: Internals::List<JsonPair>(buffer) {} : Internals::List<JsonPair>(buffer) {}
// Gets or sets the value associated with the specified key. // Gets or sets the value associated with the specified key.
FORCE_INLINE JsonObjectSubscript operator[](JsonObjectKey key); FORCE_INLINE JsonObjectSubscript<const char*> operator[](const char* key);
FORCE_INLINE JsonObjectSubscript<const String&> operator[](const String& key);
// Gets the value associated with the specified 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. // 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. // Gets the value associated with the specified key.
FORCE_INLINE JsonVariant get(JsonObjectKey) const; FORCE_INLINE JsonVariant get(JsonObjectKey) const;
@ -64,11 +95,13 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// Creates and adds a JsonArray. // Creates and adds a JsonArray.
// This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). // 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. // Creates and adds a JsonObject.
// This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). // 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. // Tells weither the specified key is present and associated with a value.
FORCE_INLINE bool containsKey(JsonObjectKey key) const; FORCE_INLINE bool containsKey(JsonObjectKey key) const;
@ -90,6 +123,21 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
node_type* getOrCreateNodeAt(JsonObjectKey key); node_type* getOrCreateNodeAt(JsonObjectKey key);
template <typename TKey, typename TValue>
FORCE_INLINE bool setNodeAt(TKey key, TValue value);
template <typename TKey>
JsonArray& createArrayAt(TKey key);
template <typename TKey>
JsonObject& createObjectAt(TKey key);
template <typename T>
FORCE_INLINE void setNodeKey(node_type*, T key);
template <typename T>
FORCE_INLINE void setNodeValue(node_type*, T value);
// The instance returned by JsonObject::invalid() // The instance returned by JsonObject::invalid()
static JsonObject _invalid; static JsonObject _invalid;
}; };

View File

@ -28,41 +28,183 @@ inline bool JsonObject::is(JsonObjectKey key) const {
return node ? node->content.value.is<T>() : false; return node ? node->content.value.is<T>() : false;
} }
inline JsonObjectSubscript JsonObject::operator[](JsonObjectKey key) { inline JsonObjectSubscript<const char *> JsonObject::operator[](
return JsonObjectSubscript(*this, key); const char *key) {
return JsonObjectSubscript<const char *>(*this, key);
} }
inline const JsonObjectSubscript JsonObject::operator[]( inline JsonObjectSubscript<const String &> JsonObject::operator[](
JsonObjectKey key) const { const String &key) {
return JsonObjectSubscript(*const_cast<JsonObject *>(this), key); return JsonObjectSubscript<const String &>(*this, key);
}
inline JsonVariant JsonObject::operator[](JsonObjectKey key) const {
return get(key);
} }
inline bool JsonObject::containsKey(JsonObjectKey key) const { inline bool JsonObject::containsKey(JsonObjectKey key) const {
return getNodeAt(key) != NULL; return getNodeAt(key) != NULL;
} }
inline JsonArray &JsonObject::createNestedArray(const char *key) {
return createArrayAt<const char *>(key);
}
inline JsonArray &JsonObject::createNestedArray(const String &key) {
return createArrayAt<const String &>(key);
}
inline JsonObject &JsonObject::createNestedObject(const char *key) {
return createObjectAt<const char *>(key);
}
inline JsonObject &JsonObject::createNestedObject(const String &key) {
return createObjectAt<const String &>(key);
}
inline void JsonObject::remove(JsonObjectKey key) { inline void JsonObject::remove(JsonObjectKey key) {
removeNode(getNodeAt(key)); removeNode(getNodeAt(key));
} }
inline bool JsonObject::set(JsonObjectKey key, const JsonVariant value) { inline bool JsonObject::set(const char *key, bool value) {
return setNodeAt<const char *, bool>(key, value);
}
inline bool JsonObject::set(const char *key, float value, uint8_t decimals) {
return setNodeAt<const char *, const JsonVariant &>(
key, JsonVariant(value, decimals));
}
inline bool JsonObject::set(const char *key, double value, uint8_t decimals) {
return setNodeAt<const char *, const JsonVariant &>(
key, JsonVariant(value, decimals));
}
inline bool JsonObject::set(const char *key, signed char value) {
return setNodeAt<const char *, signed char>(key, value);
}
inline bool JsonObject::set(const char *key, signed long value) {
return setNodeAt<const char *, signed long>(key, value);
}
inline bool JsonObject::set(const char *key, signed int value) {
return setNodeAt<const char *, signed int>(key, value);
}
inline bool JsonObject::set(const char *key, signed short value) {
return setNodeAt<const char *, signed short>(key, value);
}
inline bool JsonObject::set(const char *key, unsigned char value) {
return setNodeAt<const char *, unsigned char>(key, value);
}
inline bool JsonObject::set(const char *key, unsigned long value) {
return setNodeAt<const char *, unsigned long>(key, value);
}
inline bool JsonObject::set(const char *key, unsigned int value) {
return setNodeAt<const char *, unsigned int>(key, value);
}
inline bool JsonObject::set(const char *key, unsigned short value) {
return setNodeAt<const char *, unsigned short>(key, value);
}
inline bool JsonObject::set(const char *key, const char *value) {
return setNodeAt<const char *, const char *>(key, value);
}
inline bool JsonObject::set(const char *key, const String &value) {
return setNodeAt<const char *, const String &>(key, value);
}
inline bool JsonObject::set(const char *key, JsonArray &array) {
return setNodeAt<const char *, JsonArray &>(key, array);
}
inline bool JsonObject::set(const char *key, JsonObject &object) {
return setNodeAt<const char *, JsonObject &>(key, object);
}
inline bool JsonObject::set(const char *key, const JsonVariant &value) {
return setNodeAt<const char *, const JsonVariant &>(key, value);
}
inline bool JsonObject::set(const String &key, bool value) {
return setNodeAt<const String &, bool>(key, value);
}
inline bool JsonObject::set(const String &key, float value, uint8_t decimals) {
return setNodeAt<const String &, const JsonVariant &>(
key, JsonVariant(value, decimals));
}
inline bool JsonObject::set(const String &key, double value, uint8_t decimals) {
return setNodeAt<const String &, const JsonVariant &>(
key, JsonVariant(value, decimals));
}
inline bool JsonObject::set(const String &key, signed char value) {
return setNodeAt<const String &, signed char>(key, value);
}
inline bool JsonObject::set(const String &key, signed long value) {
return setNodeAt<const String &, signed long>(key, value);
}
inline bool JsonObject::set(const String &key, signed int value) {
return setNodeAt<const String &, signed int>(key, value);
}
inline bool JsonObject::set(const String &key, signed short value) {
return setNodeAt<const String &, signed short>(key, value);
}
inline bool JsonObject::set(const String &key, unsigned char value) {
return setNodeAt<const String &, unsigned char>(key, value);
}
inline bool JsonObject::set(const String &key, unsigned long value) {
return setNodeAt<const String &, unsigned long>(key, value);
}
inline bool JsonObject::set(const String &key, unsigned int value) {
return setNodeAt<const String &, unsigned int>(key, value);
}
inline bool JsonObject::set(const String &key, unsigned short value) {
return setNodeAt<const String &, unsigned short>(key, value);
}
inline bool JsonObject::set(const String &key, const char *value) {
return setNodeAt<const String &, const char *>(key, value);
}
inline bool JsonObject::set(const String &key, const String &value) {
return setNodeAt<const String &, const String &>(key, value);
}
inline bool JsonObject::set(const String &key, JsonArray &array) {
return setNodeAt<const String &, JsonArray &>(key, array);
}
inline bool JsonObject::set(const String &key, JsonObject &object) {
return setNodeAt<const String &, JsonObject &>(key, object);
}
inline bool JsonObject::set(const String &key, const JsonVariant &value) {
return setNodeAt<const String &, const JsonVariant &>(key, value);
}
template <typename TKey, typename TValue>
inline bool JsonObject::setNodeAt(TKey key, TValue value) {
node_type *node = getOrCreateNodeAt(key); node_type *node = getOrCreateNodeAt(key);
if (!node) return false; if (!node) return false;
setNodeKey<TKey>(node, key);
node->content.key = key; setNodeValue<TValue>(node, value);
node->content.value = value;
return true; 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 <typename TValue>
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 <typename TImplem> template <typename TImplem>
inline const JsonObjectSubscript JsonVariantBase<TImplem>::operator[]( inline const JsonObjectSubscript<const char *> JsonVariantBase<TImplem>::
const char *key) const { operator[](const char *key) const {
return asObject()[key]; return asObject()[key];
} }
template <typename TImplem> template <typename TImplem>
inline const JsonObjectSubscript JsonVariantBase<TImplem>::operator[]( inline const JsonObjectSubscript<const String &> JsonVariantBase<TImplem>::
const String &key) const { operator[](const String &key) const {
return asObject()[key]; return asObject()[key];
} }

View File

@ -6,52 +6,64 @@
#pragma once #pragma once
#include "JsonVariantBase.hpp" #include "JsonSubscriptBase.hpp"
namespace ArduinoJson { namespace ArduinoJson {
class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript> {
template <typename TKey>
class JsonObjectSubscript
: public JsonSubscriptBase<JsonObjectSubscript<TKey> > {
public: public:
FORCE_INLINE JsonObjectSubscript(JsonObject& object, JsonObjectKey key) FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key)
: _object(object), _key(key) {} : _object(object), _key(key) {}
FORCE_INLINE JsonObjectSubscript& operator=(const JsonVariant& value) { using JsonSubscriptBase<JsonObjectSubscript<TKey> >::operator=;
_object.set(_key, value);
return *this;
}
FORCE_INLINE JsonObjectSubscript& operator=( FORCE_INLINE JsonObjectSubscript<TKey>& operator=(
const JsonObjectSubscript& other) { const JsonObjectSubscript<TKey>& other) {
// to prevent Visual Studio warning C4512: assignment operator could not be // to prevent Visual Studio warning C4512: assignment operator could not be
// generated // generated
_object.set(_key, other._object.get(other._key)); return set(other.get());
return *this;
} }
FORCE_INLINE bool success() const { return _object.containsKey(_key); } FORCE_INLINE bool success() const { return _object.containsKey(_key); }
FORCE_INLINE operator JsonVariant() const { return _object.get(_key); } FORCE_INLINE operator JsonVariant() const { return _object.get(_key); }
template <typename T> template <typename TValue>
FORCE_INLINE T as() const { FORCE_INLINE TValue as() const {
return _object.get<T>(_key); return _object.get<TValue>(_key);
} }
template <typename T> template <typename TValue>
FORCE_INLINE T is() const { FORCE_INLINE TValue is() const {
return _object.is<T>(_key); return _object.is<TValue>(_key);
} }
void writeTo(Internals::JsonWriter &writer) const { template <typename TValue>
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); _object.get(_key).writeTo(writer);
} }
private: private:
JsonObject& _object; JsonObject& _object;
JsonObjectKey _key; TKey _key;
}; };
#ifdef ARDUINOJSON_ENABLE_STD_STREAM #ifdef ARDUINOJSON_ENABLE_STD_STREAM
inline std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& source) { inline std::ostream& operator<<(
std::ostream& os, const JsonObjectSubscript<const String&>& source) {
return source.printTo(os);
}
inline std::ostream& operator<<(
std::ostream& os, const JsonObjectSubscript<const char*>& source) {
return source.printTo(os); return source.printTo(os);
} }
#endif #endif

View File

@ -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 <typename TImpl>
class JsonSubscriptBase : public JsonVariantBase<TImpl> {
public:
FORCE_INLINE TImpl& operator=(bool value) { return assign<bool>(value); }
FORCE_INLINE TImpl& operator=(float value) { return assign<float>(value); }
FORCE_INLINE TImpl& operator=(double value) { return assign<double>(value); }
FORCE_INLINE TImpl& operator=(signed char value) {
return assign<signed char>(value);
}
FORCE_INLINE TImpl& operator=(signed long value) {
return assign<signed long>(value);
}
FORCE_INLINE TImpl& operator=(signed int value) {
return assign<signed int>(value);
}
FORCE_INLINE TImpl& operator=(signed short value) {
return assign<signed short>(value);
}
FORCE_INLINE TImpl& operator=(unsigned char value) {
return assign<unsigned char>(value);
}
FORCE_INLINE TImpl& operator=(unsigned long value) {
return assign<unsigned long>(value);
}
FORCE_INLINE TImpl& operator=(unsigned int value) {
return assign<unsigned int>(value);
}
FORCE_INLINE TImpl& operator=(unsigned short value) {
return assign<unsigned short>(value);
}
FORCE_INLINE TImpl& operator=(const char* value) {
return assign<const char*>(value);
}
FORCE_INLINE TImpl& operator=(const String& value) {
return assign<const String&>(value);
}
FORCE_INLINE TImpl& operator=(JsonArray& array) {
return assign<JsonArray&>(array);
}
FORCE_INLINE TImpl& operator=(JsonObject& object) {
return assign<JsonObject&>(object);
}
FORCE_INLINE TImpl& operator=(JsonVariant value) {
return assign<JsonVariant>(value);
}
private:
template <typename TValue>
FORCE_INLINE TImpl& assign(TValue value) {
TImpl* impl = static_cast<TImpl*>(this);
impl->template set<TValue>(value);
return *impl;
}
};
}

View File

@ -9,7 +9,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> // for uint8_t #include <stdint.h> // for uint8_t
#include "Arduino/String.hpp"
#include "Internals/JsonPrintable.hpp" #include "Internals/JsonPrintable.hpp"
#include "Internals/JsonVariantContent.hpp" #include "Internals/JsonVariantContent.hpp"
#include "Internals/JsonVariantType.hpp" #include "Internals/JsonVariantType.hpp"
@ -55,7 +54,6 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// Create a JsonVariant containing a string. // Create a JsonVariant containing a string.
FORCE_INLINE JsonVariant(const char *value); FORCE_INLINE JsonVariant(const char *value);
FORCE_INLINE JsonVariant(const String &value);
// Create a JsonVariant containing a reference to an array. // Create a JsonVariant containing a reference to an array.
FORCE_INLINE JsonVariant(JsonArray &array); FORCE_INLINE JsonVariant(JsonArray &array);

View File

@ -20,11 +20,6 @@ inline JsonVariant::JsonVariant(const char *value) {
_content.asString = 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) { inline JsonVariant::JsonVariant(double value, uint8_t decimals) {
_type = static_cast<Internals::JsonVariantType>( _type = static_cast<Internals::JsonVariantType>(
Internals::JSON_DOUBLE_0_DECIMALS + decimals); Internals::JSON_DOUBLE_0_DECIMALS + decimals);
@ -112,11 +107,6 @@ inline bool JsonVariant::is<char const *>() const {
return _type == Internals::JSON_STRING; return _type == Internals::JSON_STRING;
} }
template <>
inline bool JsonVariant::is<String>() const {
return _type == Internals::JSON_STRING;
}
template <> template <>
inline bool JsonVariant::is<double>() const { inline bool JsonVariant::is<double>() const {
return _type >= Internals::JSON_DOUBLE_0_DECIMALS; return _type >= Internals::JSON_DOUBLE_0_DECIMALS;
@ -188,7 +178,7 @@ inline bool JsonVariant::is<unsigned short>() const {
} }
#ifdef ARDUINOJSON_ENABLE_STD_STREAM #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); return source.printTo(os);
} }
#endif #endif

View File

@ -13,6 +13,7 @@ namespace ArduinoJson {
// Forward declarations. // Forward declarations.
class JsonArraySubscript; class JsonArraySubscript;
template <typename TKey>
class JsonObjectSubscript; class JsonObjectSubscript;
template <typename TImpl> template <typename TImpl>
@ -76,8 +77,10 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
// Returns the value associated with the specified key if the variant is // Returns the value associated with the specified key if the variant is
// an object. // an object.
// Return JsonVariant::invalid() if the variant is not 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<const char *> operator[](
FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const; const char *key) const;
FORCE_INLINE const JsonObjectSubscript<const String &> operator[](
const String &key) const;
// Serialize the variant to a JsonWriter // Serialize the variant to a JsonWriter
void writeTo(Internals::JsonWriter &writer) const; void writeTo(Internals::JsonWriter &writer) const;

View File

@ -49,7 +49,7 @@ size_t DynamicJsonBuffer::size() const {
} }
void* DynamicJsonBuffer::alloc(size_t bytes) { void* DynamicJsonBuffer::alloc(size_t bytes) {
if (!canAllocInHead(bytes)) addNewBlock(); while (!canAllocInHead(bytes)) addNewBlock();
return allocInHead(bytes); return allocInHead(bytes);
} }

View File

@ -32,3 +32,10 @@ JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) {
JsonParser parser(this, json, nestingLimit); JsonParser parser(this, json, nestingLimit);
return parser.parseObject(); return parser.parseObject();
} }
char *JsonBuffer::strdup(const char *source, size_t length) {
size_t size = length + 1;
char *dest = static_cast<char *>(alloc(size));
if (dest != NULL) memcpy(dest, source, size);
return dest;
}

View File

@ -25,19 +25,25 @@ JsonObject::node_type *JsonObject::getOrCreateNodeAt(JsonObjectKey key) {
return newNode; return newNode;
} }
JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { template <typename TKey>
JsonArray &JsonObject::createArrayAt(TKey key) {
if (!_buffer) return JsonArray::invalid(); if (!_buffer) return JsonArray::invalid();
JsonArray &array = _buffer->createArray(); JsonArray &array = _buffer->createArray();
set(key, array); setNodeAt<TKey, const JsonVariant &>(key, array);
return array; return array;
} }
template JsonArray &JsonObject::createArrayAt<const char *>(const char *);
template JsonArray &JsonObject::createArrayAt<const String &>(const String &);
JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { template <typename TKey>
JsonObject &JsonObject::createObjectAt(TKey key) {
if (!_buffer) return JsonObject::invalid(); if (!_buffer) return JsonObject::invalid();
JsonObject &object = _buffer->createObject(); JsonObject &array = _buffer->createObject();
set(key, object); setNodeAt<TKey, const JsonVariant &>(key, array);
return object; return array;
} }
template JsonObject &JsonObject::createObjectAt<const char *>(const char *);
template JsonObject &JsonObject::createObjectAt<const String &>(const String &);
JsonObject::node_type *JsonObject::getNodeAt(JsonObjectKey key) const { JsonObject::node_type *JsonObject::getNodeAt(JsonObjectKey key) const {
for (node_type *node = _firstNode; node; node = node->next) { for (node_type *node = _firstNode; node; node = node->next) {

View File

@ -7,103 +7,160 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
TEST(ArduinoStringTests, JsonBuffer_ParseArray) { class ArduinoStringTests : public ::testing::Test {
DynamicJsonBuffer jsonBuffer; protected:
String json("[1,2]"); static void eraseString(String &str) {
JsonArray &array = jsonBuffer.parseArray(json); char *p = const_cast<char *>(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_TRUE(array.success());
ASSERT_STREQ("hello", array[0]);
} }
TEST(ArduinoStringTests, JsonBuffer_ParseObject) { TEST_F(ArduinoStringTests, JsonBuffer_ParseObject) {
DynamicJsonBuffer jsonBuffer; String json("{\"hello\":\"world\"}");
String json("{\"a\":1,\"b\":2}"); JsonObject &object = _jsonBuffer.parseObject(json);
JsonObject &object = jsonBuffer.parseObject(json); eraseString(json);
ASSERT_TRUE(object.success()); ASSERT_TRUE(object.success());
ASSERT_STREQ("world", object["hello"]);
} }
TEST(ArduinoStringTests, JsonVariant) { TEST_F(ArduinoStringTests, JsonObject_Subscript) {
String input = "Hello world!";
JsonVariant variant(input);
ASSERT_TRUE(variant.is<String>());
String output = variant.as<String>();
ASSERT_EQ(input, output);
}
TEST(ArduinoStringTests, JsonObject_Subscript) {
DynamicJsonBuffer jsonBuffer;
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
JsonObject &object = jsonBuffer.parseObject(json); JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object[String("key")]); ASSERT_STREQ("value", object[String("key")]);
} }
TEST(ArduinoStringTests, JsonObject_ConstSubscript) { TEST_F(ArduinoStringTests, JsonObject_ConstSubscript) {
DynamicJsonBuffer jsonBuffer;
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object[String("key")]); ASSERT_STREQ("value", object[String("key")]);
} }
TEST(ArduinoStringTests, JsonObject_Set) { TEST_F(ArduinoStringTests, JsonObject_SetKey) {
DynamicJsonBuffer jsonBuffer; JsonObject &object = _jsonBuffer.createObject();
JsonObject &object = jsonBuffer.createObject(); String key("hello");
String key = "key"; object.set(key, "world");
object.set(key, "value"); eraseString(key);
ASSERT_STREQ("value", object["key"]); ASSERT_STREQ("world", object["hello"]);
} }
TEST(ArduinoStringTests, JsonObject_Get) { TEST_F(ArduinoStringTests, JsonObject_SetValue) {
DynamicJsonBuffer jsonBuffer; 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\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object.get(String("key"))); ASSERT_STREQ("value", object.get(String("key")));
} }
TEST(ArduinoStringTests, JsonObject_GetT) { TEST_F(ArduinoStringTests, JsonObject_GetT) {
DynamicJsonBuffer jsonBuffer;
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object.get<const char *>(String("key"))); ASSERT_STREQ("value", object.get<const char *>(String("key")));
} }
TEST(ArduinoStringTests, JsonObject_IsT) { TEST_F(ArduinoStringTests, JsonObject_IsT) {
DynamicJsonBuffer jsonBuffer;
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_TRUE(object.is<const char *>(String("key"))); ASSERT_TRUE(object.is<const char *>(String("key")));
} }
TEST(ArduinoStringTests, JsonObject_CreateNestedObject) { TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) {
DynamicJsonBuffer jsonBuffer;
String key = "key"; String key = "key";
char json[64]; char json[64];
JsonObject &object = jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object.createNestedObject(key); object.createNestedObject(key);
eraseString(key);
object.printTo(json, sizeof(json)); object.printTo(json, sizeof(json));
ASSERT_STREQ("{\"key\":{}}", json); ASSERT_STREQ("{\"key\":{}}", json);
} }
TEST(ArduinoStringTests, JsonObject_CreateNestedArray) { TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) {
DynamicJsonBuffer jsonBuffer;
String key = "key"; String key = "key";
char json[64]; char json[64];
JsonObject &object = jsonBuffer.createObject(); JsonObject &object = _jsonBuffer.createObject();
object.createNestedArray(key); object.createNestedArray(key);
eraseString(key);
object.printTo(json, sizeof(json)); object.printTo(json, sizeof(json));
ASSERT_STREQ("{\"key\":[]}", json); ASSERT_STREQ("{\"key\":[]}", json);
} }
TEST(ArduinoStringTests, JsonObject_ContainsKey) { TEST_F(ArduinoStringTests, JsonObject_ContainsKey) {
DynamicJsonBuffer jsonBuffer;
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
const JsonObject &object = jsonBuffer.parseObject(json); const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_TRUE(object.containsKey(String("key"))); ASSERT_TRUE(object.containsKey(String("key")));
} }
TEST(ArduinoStringTests, JsonObject_Remove) { TEST_F(ArduinoStringTests, JsonObject_Remove) {
DynamicJsonBuffer jsonBuffer;
char json[] = "{\"key\":\"value\"}"; char json[] = "{\"key\":\"value\"}";
JsonObject &object = jsonBuffer.parseObject(json); JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_EQ(1, object.size()); ASSERT_EQ(1, object.size());
object.remove(String("key")); object.remove(String("key"));
ASSERT_EQ(0, object.size()); ASSERT_EQ(0, object.size());
} }
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]);
}

View File

@ -59,7 +59,7 @@ TEST_F(JsonObject_Container_Tests,
TEST_F(JsonObject_Container_Tests, CanStoreIntegers) { TEST_F(JsonObject_Container_Tests, CanStoreIntegers) {
_object["hello"] = 123; _object["hello"] = 123;
_object["world"] = 456; _object.set("world", 456);
EXPECT_EQ(123, _object["hello"].as<int>()); EXPECT_EQ(123, _object["hello"].as<int>());
EXPECT_EQ(456, _object["world"].as<int>()); EXPECT_EQ(456, _object["world"].as<int>());
@ -67,7 +67,7 @@ TEST_F(JsonObject_Container_Tests, CanStoreIntegers) {
TEST_F(JsonObject_Container_Tests, CanStoreDoubles) { TEST_F(JsonObject_Container_Tests, CanStoreDoubles) {
_object["hello"] = 123.45; _object["hello"] = 123.45;
_object["world"] = 456.78; _object.set("world", 456.78);
EXPECT_EQ(123.45, _object["hello"].as<double>()); EXPECT_EQ(123.45, _object["hello"].as<double>());
EXPECT_EQ(456.78, _object["world"].as<double>()); EXPECT_EQ(456.78, _object["world"].as<double>());
@ -75,7 +75,7 @@ TEST_F(JsonObject_Container_Tests, CanStoreDoubles) {
TEST_F(JsonObject_Container_Tests, CanStoreBooleans) { TEST_F(JsonObject_Container_Tests, CanStoreBooleans) {
_object["hello"] = true; _object["hello"] = true;
_object["world"] = false; _object.set("world", false);
EXPECT_TRUE(_object["hello"].as<bool>()); EXPECT_TRUE(_object["hello"].as<bool>());
EXPECT_FALSE(_object["world"].as<bool>()); EXPECT_FALSE(_object["world"].as<bool>());
@ -83,32 +83,32 @@ TEST_F(JsonObject_Container_Tests, CanStoreBooleans) {
TEST_F(JsonObject_Container_Tests, CanStoreStrings) { TEST_F(JsonObject_Container_Tests, CanStoreStrings) {
_object["hello"] = "h3110"; _object["hello"] = "h3110";
_object["world"] = "w0r1d"; _object.set("world", "w0r1d");
EXPECT_STREQ("h3110", _object["hello"].as<const char*>()); EXPECT_STREQ("h3110", _object["hello"].as<const char*>());
EXPECT_STREQ("w0r1d", _object["world"].as<const char*>()); EXPECT_STREQ("w0r1d", _object["world"].as<const char*>());
} }
TEST_F(JsonObject_Container_Tests, CanStoreInnerArrays) { TEST_F(JsonObject_Container_Tests, CanStoreArrays) {
JsonArray& innerarray1 = _jsonBuffer.createArray(); JsonArray& array1 = _jsonBuffer.createArray();
JsonArray& innerarray2 = _jsonBuffer.createArray(); JsonArray& array2 = _jsonBuffer.createArray();
_object["hello"] = innerarray1; _object["hello"] = array1;
_object["world"] = innerarray2; _object.set("world", array2);
EXPECT_EQ(&innerarray1, &_object["hello"].asArray()); EXPECT_EQ(&array1, &_object["hello"].asArray());
EXPECT_EQ(&innerarray2, &_object["world"].asArray()); EXPECT_EQ(&array2, &_object["world"].asArray());
} }
TEST_F(JsonObject_Container_Tests, CanStoreInnerObjects) { TEST_F(JsonObject_Container_Tests, CanStoreObjects) {
JsonObject& innerObject1 = _jsonBuffer.createObject(); JsonObject& object1 = _jsonBuffer.createObject();
JsonObject& innerObject2 = _jsonBuffer.createObject(); JsonObject& object2 = _jsonBuffer.createObject();
_object["hello"] = innerObject1; _object["hello"] = object1;
_object["world"] = innerObject2; _object.set("world", object2);
EXPECT_EQ(&innerObject1, &_object["hello"].asObject()); EXPECT_EQ(&object1, &_object["hello"].asObject());
EXPECT_EQ(&innerObject2, &_object["world"].asObject()); EXPECT_EQ(&object2, &_object["world"].asObject());
} }
TEST_F(JsonObject_Container_Tests, ContainsKeyReturnsFalseForNonExistingKey) { TEST_F(JsonObject_Container_Tests, ContainsKeyReturnsFalseForNonExistingKey) {

View File

@ -11,131 +11,105 @@ using namespace ArduinoJson::Internals;
class JsonObject_PrintTo_Tests : public testing::Test { class JsonObject_PrintTo_Tests : public testing::Test {
public: public:
JsonObject_PrintTo_Tests() : object(json.createObject()) {} JsonObject_PrintTo_Tests() : _object(_jsonBuffer.createObject()) {}
protected: protected:
void outputMustBe(const char *expected) { void outputMustBe(const char *expected) {
char actual[256]; char actual[256];
size_t actualLen = object.printTo(actual, sizeof(actual)); size_t actualLen = _object.printTo(actual, sizeof(actual));
size_t measuredLen = object.measureLength(); size_t measuredLen = _object.measureLength();
EXPECT_STREQ(expected, actual); EXPECT_STREQ(expected, actual);
EXPECT_EQ(strlen(expected), actualLen); EXPECT_EQ(strlen(expected), actualLen);
EXPECT_EQ(strlen(expected), measuredLen); EXPECT_EQ(strlen(expected), measuredLen);
} }
StaticJsonBuffer<JSON_OBJECT_SIZE(2)> json; DynamicJsonBuffer _jsonBuffer;
JsonObject &object; JsonObject &_object;
}; };
TEST_F(JsonObject_PrintTo_Tests, EmptyObject) { outputMustBe("{}"); } 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) { TEST_F(JsonObject_PrintTo_Tests, TwoStrings) {
object["key1"] = "value1"; _object["key1"] = "value1";
object["key2"] = "value2"; _object.set("key2", "value2");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}"); outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
} }
TEST_F(JsonObject_PrintTo_Tests, RemoveFirst) { TEST_F(JsonObject_PrintTo_Tests, RemoveFirst) {
object["key1"] = "value1"; _object["key1"] = "value1";
object["key2"] = "value2"; _object["key2"] = "value2";
object.remove("key1"); _object.remove("key1");
outputMustBe("{\"key2\":\"value2\"}"); outputMustBe("{\"key2\":\"value2\"}");
} }
TEST_F(JsonObject_PrintTo_Tests, RemoveLast) { TEST_F(JsonObject_PrintTo_Tests, RemoveLast) {
object["key1"] = "value1"; _object["key1"] = "value1";
object["key2"] = "value2"; _object["key2"] = "value2";
object.remove("key2"); _object.remove("key2");
outputMustBe("{\"key1\":\"value1\"}"); outputMustBe("{\"key1\":\"value1\"}");
} }
TEST_F(JsonObject_PrintTo_Tests, RemoveUnexistingKey) { TEST_F(JsonObject_PrintTo_Tests, RemoveUnexistingKey) {
object["key1"] = "value1"; _object["key1"] = "value1";
object["key2"] = "value2"; _object["key2"] = "value2";
object.remove("key3"); _object.remove("key3");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}"); outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
} }
TEST_F(JsonObject_PrintTo_Tests, ReplaceExistingKey) { TEST_F(JsonObject_PrintTo_Tests, ReplaceExistingKey) {
object["key"] = "value1"; _object["key"] = "value1";
object["key"] = "value2"; _object["key"] = "value2";
outputMustBe("{\"key\":\"value2\"}"); outputMustBe("{\"key\":\"value2\"}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneStringOverCapacity) { TEST_F(JsonObject_PrintTo_Tests, TwoIntegers) {
object["key1"] = "value1"; _object["a"] = 1;
object["key2"] = "value2"; _object.set("b", 2);
object["key3"] = "value3"; outputMustBe("{\"a\":1,\"b\":2}");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneInteger) { TEST_F(JsonObject_PrintTo_Tests, TwoDoublesFourDigits) {
object["key"] = 1; _object["a"] = double_with_n_digits(3.14159265358979323846, 4);
outputMustBe("{\"key\":1}"); _object.set("b", 2.71828182845904523536, 4);
outputMustBe("{\"a\":3.1416,\"b\":2.7183}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneDoubleFourDigits) { TEST_F(JsonObject_PrintTo_Tests, TwoDoubleDefaultDigits) {
object["key"] = double_with_n_digits(3.14159265358979323846, 4); _object["a"] = 3.14159265358979323846;
outputMustBe("{\"key\":3.1416}"); _object.set("b", 2.71828182845904523536);
outputMustBe("{\"a\":3.14,\"b\":2.72}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneDoubleDefaultDigits) { TEST_F(JsonObject_PrintTo_Tests, TwoNull) {
object["key"] = 3.14159265358979323846; _object["a"] = static_cast<char *>(0);
outputMustBe("{\"key\":3.14}"); _object.set("b", static_cast<char *>(0));
outputMustBe("{\"a\":null,\"b\":null}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneNull) { TEST_F(JsonObject_PrintTo_Tests, TwoBooleans) {
object["key"] = static_cast<char *>(0); _object["a"] = true;
outputMustBe("{\"key\":null}"); _object.set("b", false);
outputMustBe("{\"a\":true,\"b\":false}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneTrue) { TEST_F(JsonObject_PrintTo_Tests, ThreeNestedArrays) {
object["key"] = true; _object.createNestedArray("a");
outputMustBe("{\"key\":true}"); _object["b"] = _jsonBuffer.createArray();
_object.set("c", _jsonBuffer.createArray());
outputMustBe("{\"a\":[],\"b\":[],\"c\":[]}");
} }
TEST_F(JsonObject_PrintTo_Tests, OneFalse) { TEST_F(JsonObject_PrintTo_Tests, ThreeNestedObjects) {
object["key"] = false; _object.createNestedObject("a");
outputMustBe("{\"key\":false}"); _object["b"] = _jsonBuffer.createObject();
} _object.set("c", _jsonBuffer.createObject());
TEST_F(JsonObject_PrintTo_Tests, OneEmptyNestedArrayViaProxy) { outputMustBe("{\"a\":{},\"b\":{},\"c\":{}}");
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\":[]}");
} }

View File

@ -8,44 +8,49 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
TEST(StaticJsonBuffer_CreateObject_Tests, GrowsWithObject) { TEST(StaticJsonBuffer_CreateObject_Tests, GrowsWithObject) {
StaticJsonBuffer<JSON_OBJECT_SIZE(3)> json; StaticJsonBuffer<JSON_OBJECT_SIZE(3)> buffer;
JsonObject &obj = json.createObject(); JsonObject &obj = buffer.createObject();
ASSERT_EQ(JSON_OBJECT_SIZE(0), json.size()); ASSERT_EQ(JSON_OBJECT_SIZE(0), buffer.size());
obj["hello"]; obj["hello"];
ASSERT_EQ(JSON_OBJECT_SIZE(0), json.size()); ASSERT_EQ(JSON_OBJECT_SIZE(0), buffer.size());
obj["hello"] = 1; obj["hello"] = 1;
ASSERT_EQ(JSON_OBJECT_SIZE(1), json.size()); ASSERT_EQ(JSON_OBJECT_SIZE(1), buffer.size());
obj["world"] = 2; 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 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) { TEST(StaticJsonBuffer_CreateObject_Tests, SucceedWhenBigEnough) {
StaticJsonBuffer<JSON_OBJECT_SIZE(0)> json; StaticJsonBuffer<JSON_OBJECT_SIZE(0)> buffer;
JsonObject &object = json.createObject(); JsonObject &object = buffer.createObject();
ASSERT_TRUE(object.success()); ASSERT_TRUE(object.success());
} }
TEST(StaticJsonBuffer_CreateObject_Tests, FailsWhenTooSmall) { TEST(StaticJsonBuffer_CreateObject_Tests, FailsWhenTooSmall) {
StaticJsonBuffer<JSON_OBJECT_SIZE(0) - 1> json; StaticJsonBuffer<JSON_OBJECT_SIZE(0) - 1> buffer;
JsonObject &object = json.createObject(); JsonObject &object = buffer.createObject();
ASSERT_FALSE(object.success()); ASSERT_FALSE(object.success());
} }
TEST(StaticJsonBuffer_CreateObject_Tests, ObjectDoesntGrowWhenFull) { TEST(StaticJsonBuffer_CreateObject_Tests, ObjectDoesntGrowWhenFull) {
StaticJsonBuffer<JSON_OBJECT_SIZE(1)> json; StaticJsonBuffer<JSON_OBJECT_SIZE(1)> buffer;
JsonObject &obj = json.createObject(); JsonObject &obj = buffer.createObject();
obj["hello"] = 1; obj["hello"] = 1;
obj["world"] = 2; 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);
} }