Compare commits

...

3 Commits

44 changed files with 1164 additions and 647 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
/build
/bin
/lib
/sftp-config.json

View File

@ -4,9 +4,7 @@ compiler:
- clang
before_install:
- sudo pip install cpp-coveralls
before_script:
- cmake -DCOVERAGE=true .
script:
- make && make test
- cmake -DCOVERAGE=true . && make && make test
after_success:
- coveralls --exclude test --exclude third-party --gcov-options '\-lp'
- if [ "$CC" = "gcc" ]; then coveralls --exclude third-party --gcov-options '\-lp'; fi

View File

@ -1,12 +1,15 @@
ArduinoJson: change log
=======================
v5.0 (currently under development)
v5.0 (currently in beta)
----
* Added support of `String` class (issue #55, #56, #70, #77)
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators
* Switched to new library layout (requires Arduino 1.0.6 or above)
* 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 (issue #66)
* Switched to new the library layout (requires Arduino 1.0.6 or above)
**BREAKING CHANGES**:
- `JsonObject::add()` was renamed to `set()`
@ -17,9 +20,18 @@ v5.0 (currently under development)
Support of the `String` class has been added to the library because many people use it in their programs.
However, you should not see this as an invitation to use the `String` class.
The `String` class is **bad** because it uses dynamic memory allocation.
Compared to static allocation, it compiles to a bigger, slower program, and is less predicate.
Compared to static allocation, it compiles to a bigger, slower program, and is less predictable.
You certainly don't want that in an embedded environment!
v4.5
----
* Fixed buffer overflow when input contains a backslash followed by a terminator (issue #81)
**Upgrading is recommended** since previous versions contain a potential security risk.
Special thanks to [Giancarlo Canales Barreto](https://github.com/gcanalesb) for finding this nasty bug.
v4.4
----

View File

@ -12,9 +12,8 @@ if(MSVC)
endif()
if(${COVERAGE})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage")
set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
endif()
add_subdirectory(src)
add_subdirectory(test)
add_subdirectory(test)

View File

@ -0,0 +1,39 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../Arduino/Print.hpp"
namespace ArduinoJson {
namespace Internals {
class Encoding {
public:
// Optimized for code size on a 8-bit AVR
static char escapeChar(char c) {
const char *p = _escapeTable;
while (p[0] && p[1] != c) {
p += 2;
}
return p[0];
}
// Optimized for code size on a 8-bit AVR
static char unescapeChar(char c) {
const char *p = _escapeTable + 4;
for (;;) {
if (p[0] == '\0') return c;
if (p[0] == c) return p[1];
p += 2;
}
}
private:
static const char _escapeTable[];
};
}
}

View File

@ -18,7 +18,10 @@ namespace Internals {
class JsonParser {
public:
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
: _buffer(buffer), _ptr(json), _nestingLimit(nestingLimit) {}
: _buffer(buffer),
_readPtr(json),
_writePtr(json),
_nestingLimit(nestingLimit) {}
JsonArray &parseArray();
JsonObject &parseObject();
@ -26,12 +29,10 @@ class JsonParser {
private:
bool skip(char charToSkip);
bool skip(const char *wordToSkip);
void skipSpaces();
bool parseAnythingTo(JsonVariant *destination);
FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination);
const char *parseString();
bool parseAnythingTo(JsonVariant *destination);
FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination);
inline bool parseArrayTo(JsonVariant *destination);
inline bool parseBooleanTo(JsonVariant *destination);
@ -41,7 +42,8 @@ class JsonParser {
inline bool parseStringTo(JsonVariant *destination);
JsonBuffer *_buffer;
char *_ptr;
const char *_readPtr;
char *_writePtr;
uint8_t _nestingLimit;
};
}

View File

@ -12,6 +12,10 @@
#include "Prettyfier.hpp"
#include "StringBuilder.hpp"
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
#include "StreamPrintAdapter.hpp"
#endif
namespace ArduinoJson {
namespace Internals {
@ -28,6 +32,14 @@ class JsonPrintable {
return writer.bytesWritten();
}
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
std::ostream& printTo(std::ostream &os) const {
StreamPrintAdapter adapter(os);
printTo(adapter);
return os;
}
#endif
size_t printTo(char *buffer, size_t bufferSize) const {
StringBuilder sb(buffer, bufferSize);
return printTo(sb);
@ -61,5 +73,13 @@ class JsonPrintable {
private:
const T &downcast() const { return *static_cast<const T *>(this); }
};
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
template<typename T>
inline std::ostream& operator<<(std::ostream& os, const JsonPrintable<T>& v) {
return v.printTo(os);
}
#endif
}
}

View File

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

View File

@ -7,7 +7,7 @@
#pragma once
#include "../Arduino/Print.hpp"
#include "QuotedString.hpp"
#include "Encoding.hpp"
namespace ArduinoJson {
namespace Internals {
@ -26,7 +26,7 @@ class JsonWriter {
// Returns the number of bytes sent to the Print implementation.
// This is very handy for implementations of printTo() that must return the
// number of bytes written.
size_t bytesWritten() { return _length; }
size_t bytesWritten() const { return _length; }
void beginArray() { write('['); }
void endArray() { write(']'); }
@ -37,15 +37,32 @@ class JsonWriter {
void writeColon() { write(':'); }
void writeComma() { write(','); }
void writeBoolean(bool value) {
write(value ? "true" : "false");
}
void writeString(const char *value) {
_length += QuotedString::printTo(value, _sink);
if (!value) {
write("null");
} else {
write('\"');
while (*value) writeChar(*value++);
write('\"');
}
}
void writeChar(char c) {
char specialChar = Encoding::escapeChar(c);
if (specialChar) {
write('\\');
write(specialChar);
} else {
write(c);
}
}
void writeLong(long value) { _length += _sink.print(value); }
void writeBoolean(bool value) {
_length += _sink.print(value ? "true" : "false");
}
void writeDouble(double value, uint8_t decimals) {
_length += _sink.print(value, decimals);
}

View File

@ -1,29 +0,0 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../Arduino/Print.hpp"
namespace ArduinoJson {
namespace Internals {
// An helper class to print and extract doubly-quoted strings
class QuotedString {
public:
// Writes a doubly-quote string to a Print implementation.
// It adds the double quotes (") at the beginning and the end of the string.
// It escapes the special characters as required by the JSON specifications.
static size_t printTo(const char *, Print &);
// Reads a doubly-quoted string from a buffer.
// It removes the double quotes (").
// It unescapes the special character as required by the JSON specification,
// with the exception of the Unicode characters (\u0000).
static char *extractFrom(char *input, char **end);
};
}
}

View File

@ -0,0 +1,34 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
#include "../Arduino/Print.hpp"
namespace ArduinoJson {
namespace Internals {
class StreamPrintAdapter : public Print {
public:
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
virtual size_t write(uint8_t c) {
_os << static_cast<char>(c);
return 1;
}
private:
// cannot be assigned
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
std::ostream& _os;
};
}
}
#endif // ARDUINOJSON_ENABLE_STD_STREAM

View File

@ -42,16 +42,46 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
: Internals::List<JsonVariant>(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<JsonArray>,
private:
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()
static JsonArray _invalid;
};

View File

@ -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<JsonArray *>(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<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();
if (node) node->content = value;
return node != NULL;
if (node == NULL) return false;
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 {
@ -42,11 +187,6 @@ inline T JsonArray::is(size_t index) const {
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>
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
int index) const {

View File

@ -6,18 +6,15 @@
#pragma once
#include "JsonVariantBase.hpp"
#include "JsonSubscriptBase.hpp"
namespace ArduinoJson {
class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
class JsonArraySubscript : public JsonSubscriptBase<JsonArraySubscript> {
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,8 +37,25 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
return _array.is<T>(_index);
}
void writeTo(Internals::JsonWriter& writer) const {
_array.get(_index).writeTo(writer);
}
template <typename TValue>
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) {
return source.printTo(os);
}
#endif
} // namespace ArduinoJson

View File

@ -8,8 +8,10 @@
#include <stddef.h> // for size_t
#include <stdint.h> // for uint8_t
#include <string.h>
#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<char *>(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<char *>(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;

View File

@ -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<JsonObject>,
: Internals::List<JsonPair>(buffer) {}
// 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.
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<JsonObject>,
// 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<JsonObject>,
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()
static JsonObject _invalid;
};

View File

@ -28,41 +28,183 @@ inline bool JsonObject::is(JsonObjectKey key) const {
return node ? node->content.value.is<T>() : false;
}
inline JsonObjectSubscript JsonObject::operator[](JsonObjectKey key) {
return JsonObjectSubscript(*this, key);
inline JsonObjectSubscript<const char *> JsonObject::operator[](
const char *key) {
return JsonObjectSubscript<const char *>(*this, key);
}
inline const JsonObjectSubscript JsonObject::operator[](
JsonObjectKey key) const {
return JsonObjectSubscript(*const_cast<JsonObject *>(this), key);
inline JsonObjectSubscript<const String &> JsonObject::operator[](
const String &key) {
return JsonObjectSubscript<const String &>(*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<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) {
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);
if (!node) return false;
node->content.key = key;
node->content.value = value;
setNodeKey<TKey>(node, key);
setNodeValue<TValue>(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 <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>
inline const JsonObjectSubscript JsonVariantBase<TImplem>::operator[](
const char *key) const {
inline const JsonObjectSubscript<const char *> JsonVariantBase<TImplem>::
operator[](const char *key) const {
return asObject()[key];
}
template <typename TImplem>
inline const JsonObjectSubscript JsonVariantBase<TImplem>::operator[](
const String &key) const {
inline const JsonObjectSubscript<const String &> JsonVariantBase<TImplem>::
operator[](const String &key) const {
return asObject()[key];
}

View File

@ -6,43 +6,65 @@
#pragma once
#include "JsonVariantBase.hpp"
#include "JsonSubscriptBase.hpp"
namespace ArduinoJson {
class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript> {
template <typename TKey>
class JsonObjectSubscript
: public JsonSubscriptBase<JsonObjectSubscript<TKey> > {
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<JsonObjectSubscript<TKey> >::operator=;
FORCE_INLINE JsonObjectSubscript& operator=(
const JsonObjectSubscript& other) {
FORCE_INLINE JsonObjectSubscript<TKey>& operator=(
const JsonObjectSubscript<TKey>& 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 <typename T>
FORCE_INLINE T as() const {
return _object.get<T>(_key);
template <typename TValue>
FORCE_INLINE TValue as() const {
return _object.get<TValue>(_key);
}
template <typename T>
FORCE_INLINE T is() const {
return _object.is<T>(_key);
template <typename TValue>
FORCE_INLINE TValue is() const {
return _object.is<TValue>(_key);
}
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);
}
private:
JsonObject& _object;
JsonObjectKey _key;
TKey _key;
};
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
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);
}
#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 <stdint.h> // for uint8_t
#include "Arduino/String.hpp"
#include "Internals/JsonPrintable.hpp"
#include "Internals/JsonVariantContent.hpp"
#include "Internals/JsonVariantType.hpp"
@ -28,8 +27,7 @@ class JsonObject;
// - a char, short, int or a long (signed or unsigned)
// - a string (const char*)
// - a reference to a JsonArray or JsonObject
class JsonVariant : public Internals::JsonPrintable<JsonVariant>,
public JsonVariantBase<JsonVariant> {
class JsonVariant : public JsonVariantBase<JsonVariant> {
public:
// Creates an uninitialized JsonVariant
FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
@ -56,7 +54,6 @@ class JsonVariant : public Internals::JsonPrintable<JsonVariant>,
// 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);

View File

@ -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::JsonVariantType>(
Internals::JSON_DOUBLE_0_DECIMALS + decimals);
@ -112,11 +107,6 @@ inline bool JsonVariant::is<char const *>() const {
return _type == Internals::JSON_STRING;
}
template <>
inline bool JsonVariant::is<String>() const {
return _type == Internals::JSON_STRING;
}
template <>
inline bool JsonVariant::is<double>() const {
return _type >= Internals::JSON_DOUBLE_0_DECIMALS;
@ -186,4 +176,11 @@ template <>
inline bool JsonVariant::is<unsigned short>() const {
return _type == Internals::JSON_LONG;
}
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
return source.printTo(os);
}
#endif
} // namespace ArduinoJson

View File

@ -13,10 +13,11 @@ namespace ArduinoJson {
// Forward declarations.
class JsonArraySubscript;
template <typename TKey>
class JsonObjectSubscript;
template <typename TImpl>
class JsonVariantBase {
class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
public:
// Gets the variant as a boolean value.
// Returns false if the variant is not a boolean value.
@ -76,8 +77,13 @@ class JsonVariantBase {
// 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<const char *> operator[](
const char *key) const;
FORCE_INLINE const JsonObjectSubscript<const String &> operator[](
const String &key) const;
// Serialize the variant to a JsonWriter
void writeTo(Internals::JsonWriter &writer) const;
private:
const TImpl *impl() const { return static_cast<const TImpl *>(this); }

View File

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

View File

@ -0,0 +1,12 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
// How to escape special chars:
// _escapeTable[2*i+1] => the special char
// _escapeTable[2*i] => the char to use instead
const char ArduinoJson::Internals::Encoding::_escapeTable[] = "\"\"\\\\b\bf\fn\nr\rt\t";

View File

@ -9,7 +9,7 @@
#include <stdlib.h> // for strtol, strtod
#include <ctype.h>
#include "../../include/ArduinoJson/Internals/QuotedString.hpp"
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
#include "../../include/ArduinoJson/JsonArray.hpp"
#include "../../include/ArduinoJson/JsonBuffer.hpp"
#include "../../include/ArduinoJson/JsonObject.hpp"
@ -17,25 +17,28 @@
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
void JsonParser::skipSpaces() {
while (isspace(*_ptr)) _ptr++;
static const char *skipSpaces(const char *ptr) {
while (isspace(*ptr)) ptr++;
return ptr;
}
bool JsonParser::skip(char charToSkip) {
skipSpaces();
if (*_ptr != charToSkip) return false;
_ptr++;
skipSpaces();
register const char *ptr = skipSpaces(_readPtr);
if (*ptr != charToSkip) return false;
ptr++;
_readPtr = skipSpaces(ptr);
return true;
}
bool JsonParser::skip(const char *wordToSkip) {
const char *charToSkip = wordToSkip;
while (*charToSkip && *_ptr == *charToSkip) {
charToSkip++;
_ptr++;
register const char *ptr = _readPtr;
while (*wordToSkip && *ptr == *wordToSkip) {
wordToSkip++;
ptr++;
}
return *charToSkip == '\0';
if (*wordToSkip != '\0') return false;
_readPtr = ptr;
return true;
}
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
@ -47,9 +50,9 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) {
}
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
skipSpaces();
_readPtr = skipSpaces(_readPtr);
switch (*_ptr) {
switch (*_readPtr) {
case '[':
return parseArrayTo(destination);
@ -181,7 +184,7 @@ bool JsonParser::parseBooleanTo(JsonVariant *destination) {
bool JsonParser::parseNumberTo(JsonVariant *destination) {
char *endOfLong;
long longValue = strtol(_ptr, &endOfLong, 10);
long longValue = strtol(_readPtr, &endOfLong, 10);
char stopChar = *endOfLong;
// Could it be a floating point value?
@ -189,14 +192,14 @@ bool JsonParser::parseNumberTo(JsonVariant *destination) {
if (couldBeFloat) {
// Yes => parse it as a double
double doubleValue = strtod(_ptr, &_ptr);
double doubleValue = strtod(_readPtr, const_cast<char **>(&_readPtr));
// Count the decimal digits
uint8_t decimals = static_cast<uint8_t>(_ptr - endOfLong - 1);
uint8_t decimals = static_cast<uint8_t>(_readPtr - endOfLong - 1);
// Set the variant as a double
*destination = JsonVariant(doubleValue, decimals);
} else {
// No => set the variant as a long
_ptr = endOfLong;
_readPtr = endOfLong;
*destination = longValue;
}
return true;
@ -209,8 +212,53 @@ bool JsonParser::parseNullTo(JsonVariant *destination) {
return true;
}
static bool isStopChar(char c) {
return c == '\0' || c == ':' || c == '}' || c == ']' || c == ',';
}
const char *JsonParser::parseString() {
return QuotedString::extractFrom(_ptr, &_ptr);
const char *readPtr = _readPtr;
char *writePtr = _writePtr;
char c = *readPtr;
if (c == '\'' || c == '\"') {
char stopChar = c;
for (;;) {
c = *++readPtr;
if (c == '\0') break;
if (c == stopChar) {
readPtr++;
break;
}
if (c == '\\') {
// replace char
c = Encoding::unescapeChar(*++readPtr);
if (c == '\0') break;
}
*writePtr++ = c;
}
} else {
for (;;) {
if (isStopChar(c)) break;
*writePtr++ = c;
c = *++readPtr;
}
}
// end the string here
*writePtr++ = '\0';
const char *startPtr = _writePtr;
// update end ptr
_readPtr = readPtr;
_writePtr = writePtr;
// return pointer to unquoted string
return startPtr;
}
bool JsonParser::parseStringTo(JsonVariant *destination) {

View File

@ -1,103 +0,0 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../../include/ArduinoJson/Internals/QuotedString.hpp"
using namespace ArduinoJson::Internals;
// How to escape special chars:
// specialChars[2*i+1] => the special char
// specialChars[2*i] => the char to use instead
static const char specialChars[] = "\"\"\\\\b\bf\fn\nr\rt\t";
static inline char getSpecialChar(char c) {
// Optimized for code size on a 8-bit AVR
const char *p = specialChars;
while (p[0] && p[1] != c) {
p += 2;
}
return p[0];
}
static inline size_t printCharTo(char c, Print &p) {
char specialChar = getSpecialChar(c);
return specialChar ? p.write('\\') + p.write(specialChar) : p.write(c);
}
size_t QuotedString::printTo(const char *s, Print &p) {
if (!s) return p.print("null");
size_t n = p.write('\"');
while (*s) {
n += printCharTo(*s++, p);
}
return n + p.write('\"');
}
static char unescapeChar(char c) {
// Optimized for code size on a 8-bit AVR
const char *p = specialChars + 4;
for (;;) {
if (p[0] == '\0') return c;
if (p[0] == c) return p[1];
p += 2;
}
}
static inline bool isQuote(char c) { return c == '\"' || c == '\''; }
char *QuotedString::extractFrom(char *input, char **endPtr) {
char firstChar = *input;
if (!isQuote(firstChar)) {
// must start with a quote
return NULL;
}
char stopChar = firstChar; // closing quote is the same as opening quote
char *startPtr = input + 1; // skip the quote
char *readPtr = startPtr;
char *writePtr = startPtr;
char c;
for (;;) {
c = *readPtr++;
if (c == '\0') {
// premature ending
return NULL;
}
if (c == stopChar) {
// closing quote
break;
}
if (c == '\\') {
// replace char
c = unescapeChar(*readPtr++);
}
*writePtr++ = c;
}
// end the string here
*writePtr = '\0';
// update end ptr
*endPtr = readPtr;
return startPtr;
}

View File

@ -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<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;
}
JsonArray &JsonObject::createNestedArray(JsonObjectKey key) {
template <typename TKey>
JsonArray &JsonObject::createArrayAt(TKey key) {
if (!_buffer) return JsonArray::invalid();
JsonArray &array = _buffer->createArray();
set(key, array);
setNodeAt<TKey, const JsonVariant &>(key, 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();
JsonObject &object = _buffer->createObject();
set(key, object);
return object;
JsonObject &array = _buffer->createObject();
setNodeAt<TKey, const JsonVariant &>(key, array);
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 {
for (node_type *node = _firstNode; node; node = node->next) {

View File

@ -7,103 +7,160 @@
#include <gtest/gtest.h>
#include <ArduinoJson.h>
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<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_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>());
String output = variant.as<String>();
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<const char *>(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<const char *>(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());
}
}
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

@ -18,4 +18,4 @@ add_executable(ArduinoJsonTests
target_link_libraries(ArduinoJsonTests ArduinoJson)
add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests)
add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests)

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson.h>
#include "Printers.hpp"
class GbathreeBug : public testing::Test {
public:

View File

@ -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<int>());
EXPECT_EQ(456, _object["world"].as<int>());
@ -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<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) {
_object["hello"] = true;
_object["world"] = false;
_object.set("world", false);
EXPECT_TRUE(_object["hello"].as<bool>());
EXPECT_FALSE(_object["world"].as<bool>());
@ -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<const char*>());
EXPECT_STREQ("w0r1d", _object["world"].as<const char*>());
}
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) {

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson.h>
#include "Printers.hpp"
class JsonObject_Iterator_Test : public testing::Test {
public:

View File

@ -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_OBJECT_SIZE(2)> 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<char *>(0);
_object.set("b", static_cast<char *>(0));
outputMustBe("{\"a\":null,\"b\":null}");
}
TEST_F(JsonObject_PrintTo_Tests, OneNull) {
object["key"] = static_cast<char *>(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\":{}}");
}

View File

@ -9,14 +9,19 @@
class JsonParser_Array_Tests : public testing::Test {
protected:
void whenInputIs(const char *json) {
strcpy(_jsonString, json);
_array = &_jsonBuffer.parseArray(_jsonString);
void whenInputIs(const char *json) { strcpy(_jsonString, json); }
void whenInputIs(const char *json, size_t len) {
memcpy(_jsonString, json, len);
}
void parseMustSucceed() { EXPECT_TRUE(_array->success()); }
void parseMustSucceed() {
_array = &_jsonBuffer.parseArray(_jsonString);
EXPECT_TRUE(_array->success());
}
void parseMustFail() {
_array = &_jsonBuffer.parseArray(_jsonString);
EXPECT_FALSE(_array->success());
EXPECT_EQ(0, _array->size());
}
@ -154,6 +159,11 @@ TEST_F(JsonParser_Array_Tests, IncompleteFalse) {
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, MixedTrueFalse) {
whenInputIs("[trufalse]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, TwoStrings) {
whenInputIs("[\"hello\",\"world\"]");
@ -162,3 +172,55 @@ TEST_F(JsonParser_Array_Tests, TwoStrings) {
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, EmptyStringsDoubleQuotes) {
whenInputIs("[\"\",\"\"]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("");
secondElementMustBe("");
}
TEST_F(JsonParser_Array_Tests, EmptyStringSingleQuotes) {
whenInputIs("[\'\',\'\']");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("");
secondElementMustBe("");
}
TEST_F(JsonParser_Array_Tests, EmptyStringNoQuotes) {
whenInputIs("[,]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("");
secondElementMustBe("");
}
TEST_F(JsonParser_Array_Tests, ClosingDoubleQuoteMissing) {
whenInputIs("[\"]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, ClosingSignleQuoteMissing) {
whenInputIs("[\']");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, StringWithEscapedChars) {
whenInputIs("[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
}
TEST_F(JsonParser_Array_Tests, StringWithUnterminatedEscapeSequence) {
whenInputIs("\"\\\0\"", 4);
parseMustFail();
}

View File

@ -75,6 +75,13 @@ TEST_F(JsonParser_Object_Test, OneStringSingleQuotes) {
keyMustHaveValue("key", "value");
}
TEST_F(JsonParser_Object_Test, OneStringNoQuotes) {
whenInputIs("{key:value}");
parseMustSucceed();
sizeMustBe(1);
keyMustHaveValue("key", "value");
}
TEST_F(JsonParser_Object_Test, OneStringSpaceBeforeKey) {
whenInputIs("{ \"key\":\"value\"}");
parseMustSucceed();

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson/JsonVariant.hpp>
#include "Printers.hpp"
using namespace ArduinoJson;

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson.h>
#include "Printers.hpp"
class JsonVariant_Undefined_Tests : public ::testing::Test {
protected:

View File

@ -6,16 +6,18 @@
#include <gtest/gtest.h>
#include <ArduinoJson/Internals/QuotedString.hpp>
#include <ArduinoJson/Internals/JsonWriter.hpp>
#include <ArduinoJson/Internals/StringBuilder.hpp>
using namespace ArduinoJson::Internals;
class QuotedString_PrintTo_Tests : public testing::Test {
class JsonWriter_WriteString_Tests : public testing::Test {
protected:
void whenInputIs(const char *input) {
StringBuilder sb(buffer, sizeof(buffer));
returnValue = QuotedString::printTo(input, sb);
JsonWriter writer(sb);
writer.writeString(input);
returnValue = writer.bytesWritten();
}
void outputMustBe(const char *expected) {
@ -28,52 +30,52 @@ class QuotedString_PrintTo_Tests : public testing::Test {
size_t returnValue;
};
TEST_F(QuotedString_PrintTo_Tests, Null) {
TEST_F(JsonWriter_WriteString_Tests, Null) {
whenInputIs(0);
outputMustBe("null");
}
TEST_F(QuotedString_PrintTo_Tests, EmptyString) {
TEST_F(JsonWriter_WriteString_Tests, EmptyString) {
whenInputIs("");
outputMustBe("\"\"");
}
TEST_F(QuotedString_PrintTo_Tests, QuotationMark) {
TEST_F(JsonWriter_WriteString_Tests, QuotationMark) {
whenInputIs("\"");
outputMustBe("\"\\\"\"");
}
TEST_F(QuotedString_PrintTo_Tests, ReverseSolidus) {
TEST_F(JsonWriter_WriteString_Tests, ReverseSolidus) {
whenInputIs("\\");
outputMustBe("\"\\\\\"");
}
TEST_F(QuotedString_PrintTo_Tests, Solidus) {
TEST_F(JsonWriter_WriteString_Tests, Solidus) {
whenInputIs("/");
outputMustBe("\"/\""); // but the JSON format allows \/
}
TEST_F(QuotedString_PrintTo_Tests, Backspace) {
TEST_F(JsonWriter_WriteString_Tests, Backspace) {
whenInputIs("\b");
outputMustBe("\"\\b\"");
}
TEST_F(QuotedString_PrintTo_Tests, Formfeed) {
TEST_F(JsonWriter_WriteString_Tests, Formfeed) {
whenInputIs("\f");
outputMustBe("\"\\f\"");
}
TEST_F(QuotedString_PrintTo_Tests, Newline) {
TEST_F(JsonWriter_WriteString_Tests, Newline) {
whenInputIs("\n");
outputMustBe("\"\\n\"");
}
TEST_F(QuotedString_PrintTo_Tests, CarriageReturn) {
TEST_F(JsonWriter_WriteString_Tests, CarriageReturn) {
whenInputIs("\r");
outputMustBe("\"\\r\"");
}
TEST_F(QuotedString_PrintTo_Tests, HorizontalTab) {
TEST_F(JsonWriter_WriteString_Tests, HorizontalTab) {
whenInputIs("\t");
outputMustBe("\"\\t\"");
}

View File

@ -1,50 +0,0 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "Printers.hpp"
#include <ArduinoJson/JsonArray.hpp>
class StreamPrintAdapter : public Print {
public:
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
virtual size_t write(uint8_t c) {
_os << static_cast<char>(c);
return 1;
}
private:
// cannot be assigned
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
std::ostream& _os;
};
std::ostream& ArduinoJson::operator<<(std::ostream& os,
const ArduinoJson::JsonVariant& v) {
StreamPrintAdapter adapter(os);
v.printTo(adapter);
return os;
}
std::ostream& ArduinoJson::operator<<(std::ostream& os,
const ArduinoJson::JsonArray& v) {
StreamPrintAdapter adapter(os);
v.printTo(adapter);
return os;
}
std::ostream& ArduinoJson::operator<<(
std::ostream& os, const ArduinoJson::JsonObjectSubscript& v) {
JsonVariant value = v;
return os << value;
}
std::ostream& ArduinoJson::operator<<(
std::ostream& os, const ArduinoJson::JsonArraySubscript& v) {
JsonVariant value = v;
return os << value;
}

View File

@ -1,17 +0,0 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include <ArduinoJson.h>
#include <ostream>
namespace ArduinoJson {
std::ostream& operator<<(std::ostream& os, const JsonVariant& v);
std::ostream& operator<<(std::ostream& os, const JsonArray& v);
std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& v);
std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& v);
}

View File

@ -1,136 +0,0 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#include <ArduinoJson/Internals/QuotedString.hpp>
using namespace ArduinoJson::Internals;
class QuotedString_ExtractFrom_Tests : public testing::Test {
protected:
void whenInputIs(const char *json) {
strcpy(_jsonString, json);
_result = QuotedString::extractFrom(_jsonString, &_trailing);
}
void resultMustBe(const char *expected) { EXPECT_STREQ(expected, _result); }
void trailingMustBe(const char *expected) {
EXPECT_STREQ(expected, _trailing);
}
private:
char _jsonString[256];
char *_result;
char *_trailing;
};
TEST_F(QuotedString_ExtractFrom_Tests, EmptyDoubleQuotedString) {
whenInputIs("\"\"");
resultMustBe("");
trailingMustBe("");
}
TEST_F(QuotedString_ExtractFrom_Tests, NoQuotes) {
whenInputIs("hello world");
resultMustBe(0);
}
TEST_F(QuotedString_ExtractFrom_Tests, MissingClosingQuote) {
whenInputIs("\"hello world");
resultMustBe(0);
}
TEST_F(QuotedString_ExtractFrom_Tests, EmptySingleQuotedString) {
whenInputIs("''");
resultMustBe("");
trailingMustBe("");
}
TEST_F(QuotedString_ExtractFrom_Tests, SimpleDoubleQuotedString) {
whenInputIs("\"hello world\"");
resultMustBe("hello world");
trailingMustBe("");
}
TEST_F(QuotedString_ExtractFrom_Tests, DoubleQuotedStringWithTrailing) {
whenInputIs("\"hello\" world");
resultMustBe("hello");
trailingMustBe(" world");
}
TEST_F(QuotedString_ExtractFrom_Tests, SingleQuotedStringWithTrailing) {
whenInputIs("'hello' world");
resultMustBe("hello");
trailingMustBe(" world");
}
TEST_F(QuotedString_ExtractFrom_Tests, CurlyBraces) {
whenInputIs("\"{hello:world}\"");
resultMustBe("{hello:world}");
}
TEST_F(QuotedString_ExtractFrom_Tests, SquareBraquets) {
whenInputIs("\"[hello,world]\"");
resultMustBe("[hello,world]");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedDoubleQuote) {
whenInputIs("\"hello \\\"world\\\"\"");
resultMustBe("hello \"world\"");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedSingleQuote) {
whenInputIs("\"hello \\\'world\\\'\"");
resultMustBe("hello 'world'");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedSolidus) {
whenInputIs("\"hello \\/world\\/\"");
resultMustBe("hello /world/");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedReverseSolidus) {
whenInputIs("\"hello \\\\world\\\\\"");
resultMustBe("hello \\world\\");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedBackspace) {
whenInputIs("\"hello \\bworld\\b\"");
resultMustBe("hello \bworld\b");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedFormfeed) {
whenInputIs("\"hello \\fworld\\f\"");
resultMustBe("hello \fworld\f");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedNewline) {
whenInputIs("\"hello \\nworld\\n\"");
resultMustBe("hello \nworld\n");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedCarriageReturn) {
whenInputIs("\"hello \\rworld\\r\"");
resultMustBe("hello \rworld\r");
}
TEST_F(QuotedString_ExtractFrom_Tests, EscapedTab) {
whenInputIs("\"hello \\tworld\\t\"");
resultMustBe("hello \tworld\t");
}
TEST_F(QuotedString_ExtractFrom_Tests, AllEscapedCharsTogether) {
whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
resultMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
}

View File

@ -8,44 +8,49 @@
#include <ArduinoJson.h>
TEST(StaticJsonBuffer_CreateObject_Tests, GrowsWithObject) {
StaticJsonBuffer<JSON_OBJECT_SIZE(3)> json;
StaticJsonBuffer<JSON_OBJECT_SIZE(3)> 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_OBJECT_SIZE(0)> json;
StaticJsonBuffer<JSON_OBJECT_SIZE(0)> buffer;
JsonObject &object = json.createObject();
JsonObject &object = buffer.createObject();
ASSERT_TRUE(object.success());
}
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());
}
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["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);
}

62
test/StdStream.cpp Normal file
View File

@ -0,0 +1,62 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <sstream>
#include <gtest/gtest.h>
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson.h>
TEST(StdStream, JsonVariantFalse) {
std::ostringstream os;
JsonVariant variant = false;
os << variant;
ASSERT_EQ("false", os.str());
}
TEST(StdStream, JsonVariantString) {
std::ostringstream os;
JsonVariant variant = "coucou";
os << variant;
ASSERT_EQ("\"coucou\"", os.str());
}
TEST(StdStream, JsonObject) {
std::ostringstream os;
DynamicJsonBuffer jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
object["key"] = "value";
os << object;
ASSERT_EQ("{\"key\":\"value\"}", os.str());
}
TEST(StdStream, JsonObjectSubscript) {
std::ostringstream os;
DynamicJsonBuffer jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
object["key"] = "value";
os << object["key"];
ASSERT_EQ("\"value\"", os.str());
}
TEST(StdStream, JsonArray) {
std::ostringstream os;
DynamicJsonBuffer jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("value");
os << array;
ASSERT_EQ("[\"value\"]", os.str());
}
TEST(StdStream, JsonArraySubscript) {
std::ostringstream os;
DynamicJsonBuffer jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("value");
os << array[0];
ASSERT_EQ("\"value\"", os.str());
}