Compare commits

..

33 Commits

Author SHA1 Message Date
ef2641b49b Store parsed token as string and allow conversion between various types (issues #64, #69, #90, #93) 2015-08-10 17:22:22 +02:00
bce101578d Merge branch 'master' into 5.0 2015-08-02 14:28:20 +02:00
10e466426a Removed the wrong #include 2015-08-02 09:20:21 +02:00
9b90aeffa5 Added call to arduino compiler in travis 2015-08-02 09:20:08 +02:00
601b51890f Fixed segmentation fault in when memory allocation fails (issue #92) 2015-08-01 16:57:29 +02:00
2524a00a96 Fixed segmentation fault in DynamicJsonBuffer when memory allocation fails (issue #92) 2015-08-01 16:31:59 +02:00
e31d667bec Added support of comments in JSON input (issue #88) 2015-07-27 22:18:54 +02:00
c161f698fc Implicitly duplicate String in the JsonBuffer (issue #84, #87) 2015-07-25 15:38:12 +02:00
92e687303d Added support of non standard JSON input (issue #44) 2015-07-10 22:11:26 +02:00
f5b83f9314 Added greeting to Giancarlo Canales Barreto 2015-06-14 15:26:33 +02:00
5e7b9ec688 Fix buffer overflow (pull request #81) 2015-06-10 21:33:20 +02:00
78ae0b8aee Updated changelog 2015-05-31 14:42:09 +02:00
283dffc035 Switched to the new library layout 2015-05-31 14:31:41 +02:00
0aded2a798 Reduced code size 2015-05-31 14:25:01 +02:00
1b5be892b9 Added support of String class (issue #55, #56, #70, #77) 2015-05-25 15:38:58 +02:00
756c279cdc Redesigned JsonVariant to leverage converting constructors instead of assignment operators 2015-05-23 15:32:50 +02:00
08d05df00e Added JsonPrintable::measureLength() (issue #75) 2015-05-09 16:53:48 +02:00
c385862be1 Updated change log for v4.3 2015-05-03 15:49:44 +02:00
0eff567910 Added JsonArray::removeAt() (issue #58) 2015-05-02 15:16:18 +02:00
94d38c0680 Added issue #68 in changelog 2015-04-27 16:01:05 +02:00
81285f49fe Fixed issue #68 2015-04-27 15:57:40 +02:00
877096d49d Fixed issue #67 2015-04-23 21:27:58 +02:00
bfe60243a4 Fixed issue #65 2015-04-18 15:37:15 +02:00
ca9d606e72 Added example JsonUdpBeacon 2015-02-25 22:27:30 +01:00
24d21467dd Updated change log for v4.2 2015-02-07 20:49:05 +01:00
41651136bf Switched back to old library layout (issues #39, #43 and #45) 2015-02-07 20:46:46 +01:00
5e5f060fc0 Updated copyright for 2015 2015-02-07 16:05:48 +01:00
29ab5fc9c2 Reduced code size by 12 bytes 2015-02-07 16:01:09 +01:00
80913b8044 Fixed Visual Studio's warnings 2015-02-07 15:05:46 +01:00
02960f28e4 Fix coveralls command line 2015-02-03 14:38:44 +01:00
8db338ba14 Removed global new operator overload (issue #40, #45 and #46) 2015-02-01 20:59:31 +01:00
dadd8986dc Mute compiler warning (issue #47) 2015-01-15 21:05:14 +01:00
e2016cf65b Added an example with EthernetServer 2015-01-10 15:25:27 +01:00
118 changed files with 3663 additions and 1481 deletions

3
.clang-format Normal file
View File

@ -0,0 +1,3 @@
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Google

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sh text eol=lf

1
.gitignore vendored
View File

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

View File

@ -3,10 +3,18 @@ compiler:
- gcc
- clang
before_install:
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
- sleep 3
- export DISPLAY=:1.0
- wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz
- tar xf arduino-1.6.5-linux64.tar.xz
- sudo mv arduino-1.6.5 /usr/local/share/arduino
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
- sudo ln -s $PWD /usr/local/share/arduino/libraries/ArduinoJson
- sudo pip install cpp-coveralls
before_script:
- cmake -DCOVERAGE=true .
script:
- make && make test
- cmake -DCOVERAGE=true . && make && make test
- arduino --verify --board arduino:avr:uno $PWD/examples/JsonParserExample/JsonParserExample.ino
- arduino --verify --board arduino:avr:uno $PWD/examples/JsonGeneratorExample/JsonGeneratorExample.ino
after_success:
- coveralls --include include --include src --gcov-options '\-lp'
- if [ "$CC" = "gcc" ]; then coveralls --exclude third-party --gcov-options '\-lp'; fi

View File

@ -1,5 +1,63 @@
Arduino JSON: change log
========================
ArduinoJson: change log
=======================
v5.0 (currently in beta)
----
* 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 comments in JSON input (issue #88)
* Added implicit cast between numerical types (issues #64, #69, #93)
* Added ability to read number values as string (issue #90)
* 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()`
- `JsonArray::at()` and `JsonObject::at()` were renamed to `get()`
- Number of digits of floating point value are now set with `double_with_n_digits()`
**Personal note about the `String` class**:
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 predictable.
You certainly don't want that in an embedded environment!
v4.6
----
* Fixed segmentation fault in `DynamicJsonBuffer` when memory allocation fails (issue #92)
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
----
* Added `JsonArray::measureLength()` and `JsonObject::measureLength()` (issue #75)
v4.3
----
* Added `JsonArray::removeAt()` to remove an element of an array (issue #58)
* Fixed stack-overflow in `DynamicJsonBuffer` when parsing huge JSON files (issue #65)
* Fixed wrong return value of `parseArray()` and `parseObject()` when allocation fails (issue #68)
v4.2
----
* Switched back to old library layout (issues #39, #43 and #45)
* Removed global new operator overload (issue #40, #45 and #46)
* Added an example with EthernetServer
v4.1
----
@ -114,4 +172,4 @@ v1.1
v1.0
----
Initial release
Initial release

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

@ -12,10 +12,12 @@ It has been written with Arduino in mind, but it isn't linked to Arduino librari
Features
--------
* JSON decoding
* JSON decoding (comments are supported)
* JSON encoding (with optional indentation)
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Efficient (no malloc, nor copy)
* Portable (written in C++98)
* Self-contained (no external dependency)
* Small footprint
* MIT License
@ -78,4 +80,4 @@ From GitHub user `zacsketches`:
---
Found this library useful? [Help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile:
Found this library useful? [Help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile:

View File

@ -16,8 +16,8 @@ void setup() {
root["time"] = 1351824120;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080, 6); // 6 is the number of decimals to print
data.add(2.302038, 6); // if not specified, 2 digits are printed
data.add(double_with_n_digits(48.756080, 6));
data.add(double_with_n_digits(2.302038, 6));
root.printTo(Serial);
// This prints:

View File

@ -0,0 +1,74 @@
// Sample Arduino Json Web Server
// Created by Benoit Blanchon.
// Heavily inspired by "Web Server" from David A. Mellis and Tom Igoe
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoJson.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 0, 177);
EthernetServer server(80);
bool readRequest(EthernetClient& client) {
bool currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
return true;
} else if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
return false;
}
JsonObject& prepareResponse(JsonBuffer& jsonBuffer) {
JsonObject& root = jsonBuffer.createObject();
JsonArray& analogValues = root.createNestedArray("analog");
for (int pin = 0; pin < 6; pin++) {
int value = analogRead(pin);
analogValues.add(value);
}
JsonArray& digitalValues = root.createNestedArray("digital");
for (int pin = 0; pin < 14; pin++) {
int value = digitalRead(pin);
digitalValues.add(value);
}
return root;
}
void writeResponse(EthernetClient& client, JsonObject& json) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: application/json");
client.println("Connection: close");
client.println();
json.prettyPrintTo(client);
}
void setup() {
Ethernet.begin(mac, ip);
server.begin();
}
void loop() {
EthernetClient client = server.available();
if (client) {
bool success = readRequest(client);
if (success) {
StaticJsonBuffer<500> jsonBuffer;
JsonObject& json = prepareResponse(jsonBuffer);
writeResponse(client, json);
}
delay(1);
client.stop();
}
}

View File

@ -0,0 +1,55 @@
// Send a JSON object on UDP at regular interval
//
// You can easily test this program with netcat:
// $ nc -ulp 8888
//
// by Benoit Blanchon, MIT License 2015
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoJson.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress localIp(192, 168, 0, 177);
IPAddress remoteIp(192, 168, 0, 109);
unsigned int remotePort = 8888;
unsigned localPort = 8888;
EthernetUDP udp;
JsonObject& buildJson(JsonBuffer& jsonBuffer) {
JsonObject& root = jsonBuffer.createObject();
JsonArray& analogValues = root.createNestedArray("analog");
for (int pin = 0; pin < 6; pin++) {
int value = analogRead(pin);
analogValues.add(value);
}
JsonArray& digitalValues = root.createNestedArray("digital");
for (int pin = 0; pin < 14; pin++) {
int value = digitalRead(pin);
digitalValues.add(value);
}
return root;
}
void sendJson(JsonObject& json) {
udp.beginPacket(remoteIp, remotePort);
json.printTo(udp);
udp.println();
udp.endPacket();
}
void setup() {
Ethernet.begin(mac, localIp);
udp.begin(localPort);
}
void loop() {
delay(1000);
StaticJsonBuffer<300> jsonBuffer;
JsonObject& json = buildJson(jsonBuffer);
sendJson(json);
}

View File

@ -4,9 +4,9 @@
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../include/ArduinoJson/DynamicJsonBuffer.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
#include "../include/ArduinoJson/StaticJsonBuffer.hpp"
#include "ArduinoJson/DynamicJsonBuffer.hpp"
#include "ArduinoJson/JsonArray.hpp"
#include "ArduinoJson/JsonObject.hpp"
#include "ArduinoJson/StaticJsonBuffer.hpp"
using namespace ArduinoJson;

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -11,7 +11,7 @@
#include <stddef.h>
#include <stdint.h>
// This class reproduces Arduino's Print
// This class reproduces Arduino's Print class
class Print {
public:
virtual ~Print() {}

View File

@ -0,0 +1,32 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#ifndef ARDUINO
#include <string>
// This class reproduces Arduino's String class
class String : public std::string {
public:
String(const char *cstr = "") : std::string(cstr) {}
String(const String &str) : std::string(str) {}
explicit String(char c);
explicit String(unsigned char);
explicit String(int);
explicit String(unsigned int);
explicit String(long);
explicit String(unsigned long);
explicit String(float, unsigned char decimalPlaces = 2);
explicit String(double, unsigned char decimalPlaces = 2);
};
#else
#include <WString.h>
#endif

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,62 +6,12 @@
#pragma once
#include "JsonBuffer.hpp"
#include "Internals/BlockJsonBuffer.hpp"
namespace ArduinoJson {
// Implements a JsonBuffer with dynamic memory allocation.
// You are strongly encouraged to consider using StaticJsonBuffer which is much
// more suitable for embedded systems.
class DynamicJsonBuffer : public JsonBuffer {
public:
DynamicJsonBuffer() : _next(NULL), _size(0) {}
~DynamicJsonBuffer() { delete _next; }
size_t size() const { return _size + (_next ? _next->size() : 0); }
size_t blockCount() const { return 1 + (_next ? _next->blockCount() : 0); }
static const size_t BLOCK_CAPACITY = 32;
protected:
virtual void* alloc(size_t bytes) {
if (canAllocInThisBlock(bytes))
return allocInThisBlock(bytes);
else if (canAllocInOtherBlocks(bytes))
return allocInOtherBlocks(bytes);
else
return NULL;
}
private:
bool canAllocInThisBlock(size_t bytes) const {
return _size + bytes <= BLOCK_CAPACITY;
}
void* allocInThisBlock(size_t bytes) {
void* p = _buffer + _size;
_size += bytes;
return p;
}
bool canAllocInOtherBlocks(size_t bytes) const {
// by design a DynamicJsonBuffer can't alloc a block bigger than
// BLOCK_CAPACITY
return bytes <= BLOCK_CAPACITY;
}
void* allocInOtherBlocks(size_t bytes) {
if (!_next) {
_next = new DynamicJsonBuffer();
if (!_next) return NULL;
}
return _next->alloc(bytes);
}
DynamicJsonBuffer* _next;
size_t _size;
uint8_t _buffer[BLOCK_CAPACITY];
};
typedef Internals::BlockJsonBuffer<Internals::DefaultAllocator>
DynamicJsonBuffer;
}

View File

@ -0,0 +1,93 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../JsonBuffer.hpp"
#include <stdlib.h>
namespace ArduinoJson {
namespace Internals {
class DefaultAllocator {
public:
void* allocate(size_t size) { return malloc(size); }
void deallocate(void* pointer) { free(pointer); }
};
template <typename TAllocator>
class BlockJsonBuffer : public JsonBuffer {
struct Block;
struct EmptyBlock {
Block* next;
size_t capacity;
size_t size;
};
struct Block : EmptyBlock {
uint8_t data[1];
};
public:
BlockJsonBuffer() : _head(NULL) {}
~BlockJsonBuffer() {
Block* currentBlock = _head;
while (currentBlock != NULL) {
Block* nextBlock = currentBlock->next;
_allocator.deallocate(currentBlock);
currentBlock = nextBlock;
}
}
size_t size() const {
size_t total = 0;
for (const Block* b = _head; b; b = b->next) total += b->size;
return total;
}
protected:
virtual void* alloc(size_t bytes) {
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
}
private:
static const size_t FIRST_BLOCK_CAPACITY = 32;
bool canAllocInHead(size_t bytes) const {
return _head != NULL && _head->size + bytes <= _head->capacity;
}
void* allocInHead(size_t bytes) {
void* p = _head->data + _head->size;
_head->size += bytes;
return p;
}
void* allocInNewBlock(size_t bytes) {
size_t capacity = FIRST_BLOCK_CAPACITY;
if (_head != NULL) capacity = _head->capacity * 2;
if (bytes > capacity) capacity = bytes;
if (!addNewBlock(capacity)) return NULL;
return allocInHead(bytes);
}
bool addNewBlock(size_t capacity) {
size_t size = sizeof(EmptyBlock) + capacity;
Block* block = static_cast<Block*>(_allocator.allocate(size));
if (block == NULL) return false;
block->capacity = capacity;
block->size = 0;
block->next = _head;
_head = block;
return true;
}
Block* _head;
TAllocator _allocator;
};
}
}

View File

@ -0,0 +1,13 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
namespace ArduinoJson {
namespace Internals {
const char *skipSpacesAndComments(const char *ptr);
}
}

View File

@ -0,0 +1,20 @@
// 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 {
// A dummy Print implementation used in JsonPrintable::measureLength()
class DummyPrint : public Print {
public:
virtual size_t write(uint8_t) { return 1; }
};
}
}

View File

@ -0,0 +1,29 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../Arduino/Print.hpp"
#include "../Arduino/String.hpp"
namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a String
class DynamicStringBuilder : public Print {
public:
DynamicStringBuilder(String &str) : _str(str) {}
virtual size_t write(uint8_t c) {
_str += c;
return 1;
}
private:
String &_str;
};
}
}

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

@ -0,0 +1,13 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#ifdef _MSC_VER
#define FORCE_INLINE __forceinline
#else
#define FORCE_INLINE __attribute__((always_inline))
#endif

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -0,0 +1,24 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../JsonBuffer.hpp"
namespace ArduinoJson {
namespace Internals {
class JsonBufferAllocated {
public:
void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() {
if (!jsonBuffer) return NULL;
return jsonBuffer->alloc(n);
}
void operator delete(void *, JsonBuffer *) throw() {}
};
}
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -18,24 +18,28 @@ 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();
private:
bool skip(char charToSkip);
bool skip(const char *wordToSkip);
void skipSpaces();
void parseAnythingTo(JsonVariant &destination);
inline void parseBooleanTo(JsonVariant &destination);
inline void parseNullTo(JsonVariant &destination);
inline void parseNumberTo(JsonVariant &destination);
inline const char *parseString();
const char *parseString();
bool parseAnythingTo(JsonVariant *destination);
FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination);
inline bool parseArrayTo(JsonVariant *destination);
inline bool parseObjectTo(JsonVariant *destination);
inline bool parseStringTo(JsonVariant *destination);
JsonBuffer *_buffer;
char *_ptr;
const char *_readPtr;
char *_writePtr;
uint8_t _nestingLimit;
};
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,10 +6,16 @@
#pragma once
#include "DummyPrint.hpp"
#include "IndentedPrint.hpp"
#include "JsonWriter.hpp"
#include "Prettyfier.hpp"
#include "StringBuilder.hpp"
#include "StaticStringBuilder.hpp"
#include "DynamicStringBuilder.hpp"
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
#include "StreamPrintAdapter.hpp"
#endif
namespace ArduinoJson {
namespace Internals {
@ -27,8 +33,21 @@ 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);
StaticStringBuilder sb(buffer, bufferSize);
return printTo(sb);
}
size_t printTo(String &str) const {
DynamicStringBuilder sb(str);
return printTo(sb);
}
@ -38,7 +57,7 @@ class JsonPrintable {
}
size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
StringBuilder sb(buffer, bufferSize);
StaticStringBuilder sb(buffer, bufferSize);
return prettyPrintTo(sb);
}
@ -47,8 +66,30 @@ class JsonPrintable {
return prettyPrintTo(indentedPrint);
}
size_t prettyPrintTo(String &str) const {
DynamicStringBuilder sb(str);
return prettyPrintTo(sb);
}
size_t measureLength() const {
DummyPrint dp;
return printTo(dp);
}
size_t measurePrettyLength() const {
DummyPrint dp;
return prettyPrintTo(dp);
}
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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -17,9 +17,8 @@ namespace Internals {
// A union that defines the actual content of a JsonVariant.
// The enum JsonVariantType determines which member is in use.
union JsonVariantContent {
bool asBoolean;
double asDouble; // asDouble is also used for float
long asLong; // asLong is also used for char, short and int
long asLong; // asLong is also used for bool, char, short and int
const char* asString; // asString can be null
JsonArray* asArray; // asArray cannot be null
JsonObject* asObject; // asObject cannot be null

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -7,18 +7,21 @@
#pragma once
namespace ArduinoJson {
class JsonArray;
class JsonObject;
namespace Internals {
// Enumerated type to know the current type of a JsonVariant.
// The value determines which member of JsonVariantContent is used.
enum JsonVariantType {
JSON_INVALID, // a special state for JsonVariant::invalid()
JSON_UNDEFINED, // the JsonVariant has not been initialized
JSON_UNPARSED, // the JsonVariant contains an unparsed string
JSON_STRING, // the JsonVariant stores a const char*
JSON_BOOLEAN, // the JsonVariant stores a bool
JSON_LONG, // the JsonVariant stores a long
JSON_ARRAY, // the JsonVariant stores a pointer to a JsonArray
JSON_OBJECT, // the JsonVariant stores a pointer to a JsonObject
JSON_BOOLEAN, // the JsonVariant stores a bool
JSON_STRING, // the JsonVariant stores a const char*
JSON_LONG, // the JsonVariant stores a long
// The following values are reserved for double values
// Multiple values are used for double, depending on the number of decimal

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -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,19 +37,36 @@ 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);
}
void writeRaw(const char *s) { return write(s); }
protected:
void write(char c) { _length += _sink.write(c); }
void write(const char *s) { _length += _sink.print(s); }

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -9,7 +9,6 @@
#include "../JsonBuffer.hpp"
#include "ListConstIterator.hpp"
#include "ListIterator.hpp"
#include "PlacementNew.hpp"
namespace ArduinoJson {
namespace Internals {
@ -40,7 +39,7 @@ class List {
// Returns the numbers of elements in the list.
// For a JsonObject, it would return the number of key-value pairs
int size() const;
size_t size() const;
iterator begin() { return iterator(_firstNode); }
iterator end() { return iterator(NULL); }
@ -49,22 +48,7 @@ class List {
const_iterator end() const { return const_iterator(NULL); }
protected:
node_type *createNode() {
if (!_buffer) return NULL;
void *ptr = _buffer->alloc(sizeof(node_type));
return ptr ? new (ptr) node_type() : NULL;
}
void addNode(node_type *nodeToAdd) {
if (_firstNode) {
node_type *lastNode = _firstNode;
while (lastNode->next) lastNode = lastNode->next;
lastNode->next = nodeToAdd;
} else {
_firstNode = nodeToAdd;
}
}
node_type *addNewNode();
void removeNode(node_type *nodeToRemove);
JsonBuffer *_buffer;

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -8,16 +8,18 @@
#include <stddef.h> // for NULL
#include "JsonBufferAllocated.hpp"
namespace ArduinoJson {
namespace Internals {
// A node for a singly-linked list.
// Used by List<T> and its iterators.
template <typename T>
struct ListNode {
struct ListNode : public Internals::JsonBufferAllocated {
ListNode() : next(NULL) {}
ListNode<T>* next;
ListNode<T> *next;
T content;
};
}

View File

@ -1,19 +0,0 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#ifdef ARDUINO
// Declares the placement new as in <new>.
// This is required for Arduino IDE because it doesn't include the <new> header.
inline void *operator new(size_t, void *p) throw() { return p; }
#else
#include <new>
#endif

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -31,7 +31,7 @@ class Prettyfier : public Print {
size_t handleBlockClose(uint8_t);
size_t handleBlockOpen(uint8_t);
size_t handleColumn();
size_t handleColon();
size_t handleComma();
size_t handleQuoteOpen();
size_t handleNormalChar(uint8_t);

View File

@ -1,29 +0,0 @@
// Copyright Benoit Blanchon 2014
// 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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -12,9 +12,9 @@ namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a char[]
class StringBuilder : public Print {
class StaticStringBuilder : public Print {
public:
StringBuilder(char *buf, int size)
StaticStringBuilder(char *buf, int size)
: buffer(buf), capacity(size - 1), length(0) {
buffer[0] = '\0';
}

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

@ -0,0 +1,20 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
namespace ArduinoJson {
namespace Internals {
class Unparsed {
public:
explicit Unparsed(const char* str) : _str(str) {}
operator const char*() const { return _str; }
private:
const char* _str;
};
}
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,6 +6,7 @@
#pragma once
#include "Internals/JsonBufferAllocated.hpp"
#include "Internals/JsonPrintable.hpp"
#include "Internals/List.hpp"
#include "Internals/ReferenceType.hpp"
@ -21,6 +22,7 @@ namespace ArduinoJson {
// Forward declarations
class JsonObject;
class JsonBuffer;
class JsonArraySubscript;
// An array of JsonVariant.
//
@ -30,36 +32,67 @@ class JsonBuffer;
// It can also be deserialized from a JSON string via JsonBuffer::parseArray().
class JsonArray : public Internals::JsonPrintable<JsonArray>,
public Internals::ReferenceType,
public Internals::List<JsonVariant> {
// JsonBuffer is a friend because it needs to call the private constructor.
friend class JsonBuffer;
public Internals::List<JsonVariant>,
public Internals::JsonBufferAllocated {
public:
// Returns the JsonVariant at the specified index (synonym for operator[])
JsonVariant &at(int index) const;
// Create an empty JsonArray attached to the specified JsonBuffer.
// You should not call this constructor directly.
// Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray().
explicit JsonArray(JsonBuffer *buffer)
: Internals::List<JsonVariant>(buffer) {}
// Returns the JsonVariant at the specified index (synonym for at())
JsonVariant &operator[](int index) const { return at(index); }
// Gets the value at the specified index
FORCE_INLINE JsonVariant operator[](size_t index) const;
// Adds an uninitialized JsonVariant at the end of the array.
// Return a reference or JsonVariant::invalid() if allocation fails.
JsonVariant &add();
// 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(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, 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;
// Gets the value at the specified index.
template <typename T>
void add(T value) {
add().set(value);
}
FORCE_INLINE T get(size_t index) const;
// Adds the specified double value at the end of the array.
// The value will be printed with the specified number of decimal digits.
void add(double value, uint8_t decimals) { add().set(value, decimals); }
// Adds a reference to the specified JsonArray at the end of the array.
void add(JsonArray &array) { add().set(array); }
// Adds a reference to the specified JsonObject at the end of the array.
void add(JsonObject &obejct) { add().set(obejct); }
// Check the type of the value at specified index.
template <typename T>
FORCE_INLINE T is(size_t index) const;
// Creates a JsonArray and adds a reference at the end of the array.
// It's a shortcut for JsonBuffer::createArray() and JsonArray::add()
@ -69,6 +102,9 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// It's a shortcut for JsonBuffer::createObject() and JsonArray::add()
JsonObject &createNestedObject();
// Removes element at specified index.
void removeAt(size_t index);
// Returns a reference an invalid JsonArray.
// This object is meant to replace a NULL pointer.
// This is used when memory allocation or JSON parsing fail.
@ -78,11 +114,20 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
void writeTo(Internals::JsonWriter &writer) const;
private:
// Create an empty JsonArray attached to the specified JsonBuffer.
explicit JsonArray(JsonBuffer *buffer)
: Internals::List<JsonVariant>(buffer) {}
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;
};
}
#include "JsonArray.ipp"

View File

@ -0,0 +1,217 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "JsonArray.hpp"
#include "JsonArraySubscript.hpp"
namespace ArduinoJson {
inline JsonArraySubscript JsonArray::operator[](size_t index) {
return JsonArraySubscript(*this, index);
}
inline JsonVariant JsonArray::operator[](size_t index) const {
return get(index);
}
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 == 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 {
node_type *node = getNodeAt(index);
return node ? node->content : JsonVariant();
}
template <typename T>
inline T JsonArray::get(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content.as<T>() : JsonVariant::invalid<T>();
}
template <typename T>
inline T JsonArray::is(size_t index) const {
node_type *node = getNodeAt(index);
return node ? node->content.is<T>() : false;
}
template <typename TImplem>
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
int index) const {
return asArray()[index];
}
template <>
inline JsonArray &JsonVariant::invalid<JsonArray &>() {
return JsonArray::invalid();
}
template <>
inline JsonArray const &JsonVariant::invalid<JsonArray const &>() {
return JsonArray::invalid();
}
template <>
inline JsonArray &JsonVariant::as<JsonArray &>() const {
if (_type == Internals::JSON_ARRAY) return *_content.asArray;
return JsonArray::invalid();
}
template <>
inline const JsonArray &JsonVariant::as<const JsonArray &>() const {
if (_type == Internals::JSON_ARRAY) return *_content.asArray;
return JsonArray::invalid();
}
}

View File

@ -0,0 +1,61 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "JsonSubscriptBase.hpp"
namespace ArduinoJson {
class JsonArraySubscript : public JsonSubscriptBase<JsonArraySubscript> {
public:
FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
: _array(array), _index(index) {}
using JsonSubscriptBase::operator=;
FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& other) {
// to prevent Visual Studio warning C4512: assignment operator could not be
// generated
_array.set(_index, other._array.get(other._index));
return *this;
}
FORCE_INLINE bool success() const { return _index < _array.size(); }
FORCE_INLINE operator JsonVariant() const { return _array.get(_index); }
template <typename T>
FORCE_INLINE T as() const {
return _array.get<T>(_index);
}
template <typename T>
FORCE_INLINE T is() const {
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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -8,6 +8,16 @@
#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"
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
namespace ArduinoJson {
class JsonArray;
@ -49,6 +59,11 @@ class JsonBuffer {
// allocation fails.
JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
// Same as above with a String class
JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
return parseArray(strdup(json), nesting);
}
// Allocates and populate a JsonObject from a JSON string.
//
// The First argument is a pointer to the JSON string, the memory must be
@ -61,6 +76,16 @@ class JsonBuffer {
// allocation fails.
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
// Same as above with a String class
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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,6 +6,8 @@
#pragma once
#include "Arduino/String.hpp"
#include "Internals/JsonBufferAllocated.hpp"
#include "Internals/JsonPrintable.hpp"
#include "Internals/List.hpp"
#include "Internals/ReferenceType.hpp"
@ -30,76 +32,115 @@ class JsonBuffer;
// It can also be deserialized from a JSON string via JsonBuffer::parseObject().
class JsonObject : public Internals::JsonPrintable<JsonObject>,
public Internals::ReferenceType,
public Internals::List<JsonPair> {
// JsonBuffer is a friend because it needs to call the private constructor.
friend class JsonBuffer;
public Internals::List<JsonPair>,
public Internals::JsonBufferAllocated {
public:
typedef const char *key_type;
typedef JsonPair value_type;
// Create an empty JsonArray attached to the specified JsonBuffer.
// You should not use this constructor directly.
// Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
FORCE_INLINE explicit JsonObject(JsonBuffer* buffer)
: Internals::List<JsonPair>(buffer) {}
// Gets the JsonVariant associated with the specified key.
// Returns a reference or JsonVariant::invalid() if not found.
JsonVariant &at(key_type key);
// Gets or sets the value associated with the specified key.
FORCE_INLINE JsonObjectSubscript<const char*> operator[](const char* key);
FORCE_INLINE JsonObjectSubscript<const String&> operator[](const String& key);
// Gets the JsonVariant associated with the specified key.
// Returns a constant reference or JsonVariant::invalid() if not found.
const JsonVariant &at(key_type key) const;
// Gets the value associated with the specified key.
FORCE_INLINE JsonVariant operator[](JsonObjectKey key) const;
// Gets or create the JsonVariant associated with the specified key.
// Returns a reference or JsonVariant::invalid() if allocation failed.
JsonVariant &operator[](key_type key);
// Sets the specified key with the specified 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 JsonVariant associated with the specified key.
// Returns a constant reference or JsonVariant::invalid() if not found.
const JsonVariant &operator[](key_type key) const { return at(key); }
// Gets the value associated with the specified key.
FORCE_INLINE JsonVariant get(JsonObjectKey) const;
// Adds an uninitialized JsonVariant associated with the specified key.
// Return a reference or JsonVariant::invalid() if allocation fails.
JsonVariant &add(key_type key) { return (*this)[key]; }
// Adds the specified key with the specified value.
// Gets the value associated with the specified key.
template <typename T>
void add(key_type key, T value) {
add(key).set(value);
}
FORCE_INLINE T get(JsonObjectKey) const;
// Adds the specified key with a reference to the specified JsonArray.
void add(key_type key, JsonArray &array) { add(key).set(array); }
// Adds the specified key with a reference to the specified JsonObject.
void add(key_type key, JsonObject &object) { add(key).set(object); }
// Checks the type of the value associated with the specified key.
template <typename T>
FORCE_INLINE bool is(JsonObjectKey) const;
// Creates and adds a JsonArray.
// This is a shortcut for JsonBuffer::createArray() and JsonObject::add().
JsonArray &createNestedArray(key_type 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(key_type 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.
bool containsKey(key_type key) const { return at(key).success(); }
FORCE_INLINE bool containsKey(JsonObjectKey key) const;
// Removes the specified key and the associated value.
void remove(key_type key);
void remove(JsonObjectKey key);
// Returns a reference an invalid JsonObject.
// This object is meant to replace a NULL pointer.
// This is used when memory allocation or JSON parsing fail.
static JsonObject &invalid() { return _invalid; }
static JsonObject& invalid() { return _invalid; }
// Serialize the object to the specified JsonWriter
void writeTo(Internals::JsonWriter &writer) const;
void writeTo(Internals::JsonWriter& writer) const;
private:
// Create an empty JsonArray attached to the specified JsonBuffer.
explicit JsonObject(JsonBuffer *buffer) : Internals::List<JsonPair>(buffer) {}
// Returns the list node that matches the specified key.
node_type *getNodeAt(key_type key) const;
node_type* getNodeAt(JsonObjectKey key) const;
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;
};
}
#include "JsonObject.ipp"

View File

@ -0,0 +1,232 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "JsonObject.hpp"
#include "JsonObjectSubscript.hpp"
namespace ArduinoJson {
inline JsonVariant JsonObject::get(JsonObjectKey key) const {
node_type *node = getNodeAt(key);
return node ? node->content.value : JsonVariant();
}
template <typename T>
inline T JsonObject::get(JsonObjectKey key) const {
node_type *node = getNodeAt(key);
return node ? node->content.value.as<T>() : JsonVariant::invalid<T>();
}
template <typename T>
inline bool JsonObject::is(JsonObjectKey key) const {
node_type *node = getNodeAt(key);
return node ? node->content.value.is<T>() : false;
}
inline JsonObjectSubscript<const char *> JsonObject::operator[](
const char *key) {
return JsonObjectSubscript<const char *>(*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(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;
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<const char *> JsonVariantBase<TImplem>::
operator[](const char *key) const {
return asObject()[key];
}
template <typename TImplem>
inline const JsonObjectSubscript<const String &> JsonVariantBase<TImplem>::
operator[](const String &key) const {
return asObject()[key];
}
template <>
inline JsonObject const &JsonVariant::invalid<JsonObject const &>() {
return JsonObject::invalid();
}
template <>
inline JsonObject &JsonVariant::invalid<JsonObject &>() {
return JsonObject::invalid();
}
template <>
inline JsonObject &JsonVariant::as<JsonObject &>() const {
if (_type == Internals::JSON_OBJECT) return *_content.asObject;
return JsonObject::invalid();
}
template <>
inline const JsonObject &JsonVariant::as<const JsonObject &>() const {
if (_type == Internals::JSON_OBJECT) return *_content.asObject;
return JsonObject::invalid();
}
}

View File

@ -0,0 +1,24 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "Arduino/String.hpp"
namespace ArduinoJson {
class JsonObjectKey {
public:
JsonObjectKey() {}
JsonObjectKey(const char* key) : _data(key) {}
JsonObjectKey(const String& key) : _data(key.c_str()) {}
operator const char*() const { return _data; }
private:
const char* _data;
};
}

View File

@ -0,0 +1,70 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "JsonSubscriptBase.hpp"
namespace ArduinoJson {
template <typename TKey>
class JsonObjectSubscript
: public JsonSubscriptBase<JsonObjectSubscript<TKey> > {
public:
FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key)
: _object(object), _key(key) {}
using JsonSubscriptBase<JsonObjectSubscript<TKey> >::operator=;
FORCE_INLINE JsonObjectSubscript<TKey>& operator=(
const JsonObjectSubscript<TKey>& other) {
// to prevent Visual Studio warning C4512: assignment operator could not be
// generated
return set(other.get());
}
FORCE_INLINE bool success() const { return _object.containsKey(_key); }
FORCE_INLINE operator JsonVariant() const { return _object.get(_key); }
template <typename TValue>
FORCE_INLINE TValue as() const {
return _object.get<TValue>(_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;
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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,13 +6,14 @@
#pragma once
#include "JsonObjectKey.hpp"
#include "JsonVariant.hpp"
namespace ArduinoJson {
// A key value pair for JsonObject.
struct JsonPair {
const char* key;
JsonObjectKey key;
JsonVariant value;
};
}

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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -12,6 +12,8 @@
#include "Internals/JsonPrintable.hpp"
#include "Internals/JsonVariantContent.hpp"
#include "Internals/JsonVariantType.hpp"
#include "Internals/Unparsed.hpp"
#include "JsonVariantBase.hpp"
namespace ArduinoJson {
@ -26,261 +28,76 @@ 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> {
class JsonVariant : public JsonVariantBase<JsonVariant> {
public:
// Creates an uninitialized JsonVariant
JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
// Initializes a JsonVariant with the specified value.
template <typename T>
explicit JsonVariant(T value) {
set(value);
}
// Tells weither the variant is valid.
bool success() const {
return _type != Internals::JSON_INVALID &&
_type != Internals::JSON_UNDEFINED;
}
// Sets the variant to a boolean value.
// Create a JsonVariant containing a boolean value.
// It will be serialized as "true" or "false" in JSON.
void set(bool value);
FORCE_INLINE JsonVariant(bool value);
// Sets the variant to a floating point value.
// Create a JsonVariant containing a floating point value.
// The second argument specifies the number of decimal digits to write in
// the JSON string.
void set(double value, uint8_t decimals = 2);
FORCE_INLINE JsonVariant(float value, uint8_t decimals = 2);
FORCE_INLINE JsonVariant(double value, uint8_t decimals = 2);
// Sets the variant to be an integer value.
void set(signed long value);
void set(signed char value) { set(static_cast<long>(value)); }
void set(signed int value) { set(static_cast<long>(value)); }
void set(signed short value) { set(static_cast<long>(value)); }
void set(unsigned char value) { set(static_cast<long>(value)); }
void set(unsigned int value) { set(static_cast<long>(value)); }
void set(unsigned long value) { set(static_cast<long>(value)); }
void set(unsigned short value) { set(static_cast<long>(value)); }
// Create a JsonVariant containing an integer value.
FORCE_INLINE JsonVariant(signed char value);
FORCE_INLINE JsonVariant(signed long value);
FORCE_INLINE JsonVariant(signed int value);
FORCE_INLINE JsonVariant(signed short value);
FORCE_INLINE JsonVariant(unsigned char value);
FORCE_INLINE JsonVariant(unsigned long value);
FORCE_INLINE JsonVariant(unsigned int value);
FORCE_INLINE JsonVariant(unsigned short value);
// Sets the variant to be a string.
void set(const char *value);
// Create a JsonVariant containing a string.
FORCE_INLINE JsonVariant(const char *value);
// Sets the variant to be a reference to an array.
void set(JsonArray &array);
// Create a JsonVariant containing an unparsed string
FORCE_INLINE JsonVariant(Internals::Unparsed value);
// Sets the variant to be a reference to an object.
void set(JsonObject &object);
// Create a JsonVariant containing a reference to an array.
FORCE_INLINE JsonVariant(JsonArray &array);
// Sets the variant to the specified value.
template <typename T>
JsonVariant &operator=(T value) {
set(value);
return *this;
}
// Sets the variant to be a reference to an array.
JsonVariant &operator=(JsonArray &array) {
set(array);
return *this;
}
// Sets the variant to be a reference to an object.
JsonVariant &operator=(JsonObject &object) {
set(object);
return *this;
}
// Gets the variant as a boolean value.
// Returns false if the variant is not a boolean value.
operator bool() const;
// Gets the variant as a floating-point value.
// Returns 0.0 if the variant is not a floating-point value
operator double() const;
operator float() const { return static_cast<float>(as<double>()); }
// Gets the variant as an integer value.
// Returns 0 if the variant is not an integer value.
operator signed long() const;
operator signed char() const { return cast_long_to<signed char>(); }
operator signed int() const { return cast_long_to<signed int>(); }
operator signed short() const { return cast_long_to<signed short>(); }
operator unsigned char() const { return cast_long_to<unsigned char>(); }
operator unsigned int() const { return cast_long_to<unsigned int>(); }
operator unsigned long() const { return cast_long_to<unsigned long>(); }
operator unsigned short() const { return cast_long_to<unsigned short>(); }
// Gets the variant as a string.
// Returns NULL if variant is not a string.
operator const char *() const;
const char *asString() const { return as<const char *>(); }
// Gets the variant as an array.
// Returns a reference to the JsonArray or JsonArray::invalid() if the variant
// is not an array.
operator JsonArray &() const;
JsonArray &asArray() const { return as<JsonArray &>(); }
// Gets the variant as an object.
// Returns a reference to the JsonObject or JsonObject::invalid() if the
// variant is not an object.
operator JsonObject &() const;
JsonObject &asObject() const { return as<JsonObject &>(); }
// Create a JsonVariant containing a reference to an object.
FORCE_INLINE JsonVariant(JsonObject &object);
// Get the variant as the specified type.
// See cast operators for details.
template <typename T>
T as() const {
return static_cast<T>(*this);
}
T as() const;
// Tells weither the variant has the specified type.
// Returns true if the variant has type type T, false otherwise.
template <typename T>
bool is() const {
return false;
}
// Returns an invalid variant.
// This is meant to replace a NULL pointer.
static JsonVariant &invalid() { return _invalid; }
bool is() const;
// Serialize the variant to a JsonWriter
void writeTo(Internals::JsonWriter &writer) const;
// Mimics an array or an object.
// Returns the size of the array or object if the variant has that type.
// Returns 0 if the variant is neither an array nor an object
size_t size() const;
// Mimics an array.
// Returns the element at specified index if the variant is an array.
// Returns JsonVariant::invalid() if the variant is not an array.
JsonVariant &operator[](int index);
// Mimics an object.
// Returns the value associated with the specified key if the variant is an
// object.
// Return JsonVariant::invalid() if the variant is not an object.
JsonVariant &operator[](const char *key);
// TODO: rename
template <typename T>
static T invalid();
private:
// Special constructor used only to create _invalid.
explicit JsonVariant(Internals::JsonVariantType type) : _type(type) {}
// Helper for interger cast operators
template <typename T>
T cast_long_to() const {
return static_cast<T>(as<long>());
}
// The current type of the variant
Internals::JsonVariantType _type;
// The various alternatives for the value of the variant.
Internals::JsonVariantContent _content;
// The instance returned by JsonVariant::invalid()
static JsonVariant _invalid;
};
template <>
inline bool JsonVariant::is<long>() const {
return _type == Internals::JSON_LONG;
inline JsonVariant float_with_n_digits(float value, uint8_t digits) {
return JsonVariant(value, digits);
}
template <>
inline bool JsonVariant::is<double>() const {
return _type >= Internals::JSON_DOUBLE_0_DECIMALS;
inline JsonVariant double_with_n_digits(double value, uint8_t digits) {
return JsonVariant(value, digits);
}
}
template <>
inline bool JsonVariant::is<bool>() const {
return _type == Internals::JSON_BOOLEAN;
}
template <>
inline bool JsonVariant::is<const char *>() const {
return _type == Internals::JSON_STRING;
}
template <>
inline bool JsonVariant::is<JsonArray &>() const {
return _type == Internals::JSON_ARRAY;
}
template <>
inline bool JsonVariant::is<const JsonArray &>() const {
return _type == Internals::JSON_ARRAY;
}
template <>
inline bool JsonVariant::is<JsonObject &>() const {
return _type == Internals::JSON_OBJECT;
}
template <>
inline bool JsonVariant::is<const JsonObject &>() const {
return _type == Internals::JSON_OBJECT;
}
template <typename T>
inline bool operator==(const JsonVariant &left, T right) {
return left.as<T>() == right;
}
template <typename T>
inline bool operator==(T left, const JsonVariant &right) {
return left == right.as<T>();
}
template <typename T>
inline bool operator!=(const JsonVariant &left, T right) {
return left.as<T>() != right;
}
template <typename T>
inline bool operator!=(T left, const JsonVariant &right) {
return left != right.as<T>();
}
template <typename T>
inline bool operator<=(const JsonVariant &left, T right) {
return left.as<T>() <= right;
}
template <typename T>
inline bool operator<=(T left, const JsonVariant &right) {
return left <= right.as<T>();
}
template <typename T>
inline bool operator>=(const JsonVariant &left, T right) {
return left.as<T>() >= right;
}
template <typename T>
inline bool operator>=(T left, const JsonVariant &right) {
return left >= right.as<T>();
}
template <typename T>
inline bool operator<(const JsonVariant &left, T right) {
return left.as<T>() < right;
}
template <typename T>
inline bool operator<(T left, const JsonVariant &right) {
return left < right.as<T>();
}
template <typename T>
inline bool operator>(const JsonVariant &left, T right) {
return left.as<T>() > right;
}
template <typename T>
inline bool operator>(T left, const JsonVariant &right) {
return left > right.as<T>();
}
}
// Include inline implementations
#include "JsonVariant.ipp"

View File

@ -0,0 +1,239 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "JsonVariant.hpp"
namespace ArduinoJson {
inline JsonVariant::JsonVariant(bool value) {
_type = Internals::JSON_BOOLEAN;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(const char *value) {
_type = Internals::JSON_STRING;
_content.asString = value;
}
inline JsonVariant::JsonVariant(Internals::Unparsed value) {
_type = Internals::JSON_UNPARSED;
_content.asString = value;
}
inline JsonVariant::JsonVariant(double value, uint8_t decimals) {
_type = static_cast<Internals::JsonVariantType>(
Internals::JSON_DOUBLE_0_DECIMALS + decimals);
_content.asDouble = value;
}
inline JsonVariant::JsonVariant(float value, uint8_t decimals) {
_type = static_cast<Internals::JsonVariantType>(
Internals::JSON_DOUBLE_0_DECIMALS + decimals);
_content.asDouble = value;
}
inline JsonVariant::JsonVariant(JsonArray &array) {
_type = Internals::JSON_ARRAY;
_content.asArray = &array;
}
inline JsonVariant::JsonVariant(JsonObject &object) {
_type = Internals::JSON_OBJECT;
_content.asObject = &object;
}
inline JsonVariant::JsonVariant(signed char value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(signed int value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(signed long value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(signed short value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(unsigned char value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(unsigned int value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(unsigned long value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
inline JsonVariant::JsonVariant(unsigned short value) {
_type = Internals::JSON_LONG;
_content.asLong = value;
}
template <>
double JsonVariant::as<double>() const;
template <>
long JsonVariant::as<long>() const;
template <>
String JsonVariant::as<String>() const;
template <>
const char *JsonVariant::as<const char *>() const;
template <>
inline bool JsonVariant::as<bool>() const {
return as<long>();
}
template <>
inline signed char JsonVariant::as<signed char>() const {
return static_cast<signed char>(as<long>());
}
template <>
inline unsigned char JsonVariant::as<unsigned char>() const {
return static_cast<unsigned char>(as<long>());
}
template <>
inline signed short JsonVariant::as<signed short>() const {
return static_cast<signed short>(as<long>());
}
template <>
inline unsigned short JsonVariant::as<unsigned short>() const {
return static_cast<unsigned short>(as<long>());
}
template <>
inline signed int JsonVariant::as<signed int>() const {
return static_cast<signed int>(as<long>());
}
template <>
inline unsigned int JsonVariant::as<unsigned int>() const {
return static_cast<unsigned int>(as<long>());
}
template <>
inline unsigned long JsonVariant::as<unsigned long>() const {
return static_cast<unsigned long>(as<long>());
}
template <>
inline float JsonVariant::as<float>() const {
return static_cast<float>(as<double>());
}
template <typename T>
inline T JsonVariant::invalid() {
return T();
}
template <typename T>
inline bool JsonVariant::is() const {
return false;
}
template <> // in .cpp
bool JsonVariant::is<signed long>() const;
template <> // in .cpp
bool JsonVariant::is<double>() const;
template <>
inline bool JsonVariant::is<bool>() const {
return _type == Internals::JSON_BOOLEAN;
}
template <>
inline bool JsonVariant::is<char const *>() const {
return _type == Internals::JSON_STRING;
}
template <>
inline bool JsonVariant::is<float>() const {
return is<double>();
}
template <>
inline bool JsonVariant::is<JsonArray &>() const {
return _type == Internals::JSON_ARRAY;
}
template <>
inline bool JsonVariant::is<JsonArray const &>() const {
return _type == Internals::JSON_ARRAY;
}
template <>
inline bool JsonVariant::is<JsonObject &>() const {
return _type == Internals::JSON_OBJECT;
}
template <>
inline bool JsonVariant::is<JsonObject const &>() const {
return _type == Internals::JSON_OBJECT;
}
template <>
inline bool JsonVariant::is<signed char>() const {
return is<signed long>();
}
template <>
inline bool JsonVariant::is<signed int>() const {
return is<signed long>();
}
template <>
inline bool JsonVariant::is<signed short>() const {
return is<signed long>();
}
template <>
inline bool JsonVariant::is<unsigned char>() const {
return is<signed long>();
}
template <>
inline bool JsonVariant::is<unsigned int>() const {
return is<signed long>();
}
template <>
inline bool JsonVariant::is<unsigned long>() const {
return is<signed long>();
}
template <>
inline bool JsonVariant::is<unsigned short>() const {
return is<signed 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

@ -0,0 +1,151 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "Internals/ForceInline.hpp"
#include "JsonObjectKey.hpp"
namespace ArduinoJson {
// Forward declarations.
class JsonArraySubscript;
template <typename TKey>
class JsonObjectSubscript;
template <typename TImpl>
class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
public:
// Gets the variant as a boolean value.
// Returns false if the variant is not a boolean value.
FORCE_INLINE operator bool() const { return as<bool>(); }
// Gets the variant as a floating-point value.
// Returns 0.0 if the variant is not a floating-point value
FORCE_INLINE operator double() const { return as<double>(); }
FORCE_INLINE operator float() const { return as<float>(); }
// Gets the variant as an integer value.
// Returns 0 if the variant is not an integer value.
FORCE_INLINE operator signed long() const { return as<signed long>(); }
FORCE_INLINE operator signed char() const { return as<signed char>(); }
FORCE_INLINE operator signed int() const { return as<signed int>(); }
FORCE_INLINE operator signed short() const { return as<signed short>(); }
FORCE_INLINE operator unsigned char() const { return as<unsigned char>(); }
FORCE_INLINE operator unsigned int() const { return as<unsigned int>(); }
FORCE_INLINE operator unsigned long() const { return as<unsigned long>(); }
FORCE_INLINE operator unsigned short() const { return as<unsigned short>(); }
// Gets the variant as a string.
// Returns NULL if variant is not a string.
FORCE_INLINE operator const char *() const { return as<const char *>(); }
FORCE_INLINE const char *asString() const { return as<const char *>(); }
FORCE_INLINE operator String() const { return as<String>(); }
// Gets the variant as an array.
// Returns a reference to the JsonArray or JsonArray::invalid() if the
// variant
// is not an array.
FORCE_INLINE operator JsonArray &() const { return as<JsonArray &>(); }
FORCE_INLINE JsonArray &asArray() const { return as<JsonArray &>(); }
// Gets the variant as an object.
// Returns a reference to the JsonObject or JsonObject::invalid() if the
// variant is not an object.
FORCE_INLINE operator JsonObject &() const { return as<JsonObject &>(); }
FORCE_INLINE JsonObject &asObject() const { return as<JsonObject &>(); }
template <typename T>
FORCE_INLINE const T as() const {
return impl()->template as<T>();
}
// Mimics an array or an object.
// Returns the size of the array or object if the variant has that type.
// Returns 0 if the variant is neither an array nor an object
size_t size() const { return asArray().size() + asObject().size(); }
// Mimics an array.
// Returns the element at specified index if the variant is an array.
// Returns JsonVariant::invalid() if the variant is not an array.
FORCE_INLINE const JsonArraySubscript operator[](int index) const;
// Mimics an object.
// 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<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); }
};
template <typename TImpl, typename TComparand>
inline bool operator==(const JsonVariantBase<TImpl> &left, TComparand right) {
return left.template as<TComparand>() == right;
}
template <typename TImpl, typename TComparand>
inline bool operator==(TComparand left, const JsonVariantBase<TImpl> &right) {
return left == right.template as<TComparand>();
}
template <typename TImpl, typename TComparand>
inline bool operator!=(const JsonVariantBase<TImpl> &left, TComparand right) {
return left.template as<TComparand>() != right;
}
template <typename TImpl, typename TComparand>
inline bool operator!=(TComparand left, const JsonVariantBase<TImpl> &right) {
return left != right.template as<TComparand>();
}
template <typename TImpl, typename TComparand>
inline bool operator<=(const JsonVariantBase<TImpl> &left, TComparand right) {
return left.template as<TComparand>() <= right;
}
template <typename TImpl, typename TComparand>
inline bool operator<=(TComparand left, const JsonVariantBase<TImpl> &right) {
return left <= right.template as<TComparand>();
}
template <typename TImpl, typename TComparand>
inline bool operator>=(const JsonVariantBase<TImpl> &left, TComparand right) {
return left.template as<TComparand>() >= right;
}
template <typename TImpl, typename TComparand>
inline bool operator>=(TComparand left, const JsonVariantBase<TImpl> &right) {
return left >= right.template as<TComparand>();
}
template <typename TImpl, typename TComparand>
inline bool operator<(const JsonVariantBase<TImpl> &left, TComparand right) {
return left.template as<TComparand>() < right;
}
template <typename TImpl, typename TComparand>
inline bool operator<(TComparand left, const JsonVariantBase<TImpl> &right) {
return left < right.template as<TComparand>();
}
template <typename TImpl, typename TComparand>
inline bool operator>(const JsonVariantBase<TImpl> &left, TComparand right) {
return left.template as<TComparand>() > right;
}
template <typename TImpl, typename TComparand>
inline bool operator>(TComparand left, const JsonVariantBase<TImpl> &right) {
return left > right.template as<TComparand>();
}
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,8 +1,8 @@
name=ArduinoJson
version=4.0
author=Benoit Blanchon <http://blog.benoitblanchon.fr/>
maintainer=Benoit Blanchon <http://blog.benoitblanchon.fr/>
sentence=An efficient and elegant JSON library for Arduino
paragraph=Supports JSON parsing and formatting. Uses fixed memory allocation.
version=5.0.0
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=An efficient and elegant JSON library for Arduino.
paragraph=Like this project? Please star it on GitHub!
url=https://github.com/bblanchon/ArduinoJson
architectures=*
architectures=*

View File

@ -1,21 +1,21 @@
#!/bin/bash
ZIP="C:\Program Files\7-Zip\7z.exe"
TAG=$(git describe)
OUTPUT="ArduinoJson-$TAG.zip"
cd ../..
# remove existing file
rm -f $OUTPUT
# create zip
"$ZIP" a $OUTPUT \
ArduinoJson/CHANGELOG.md \
ArduinoJson/examples \
ArduinoJson/include \
ArduinoJson/keywords.txt \
ArduinoJson/library.properties \
ArduinoJson/LICENSE.md \
ArduinoJson/README.md \
ArduinoJson/src
#!/bin/bash
TAG=$(git describe)
OUTPUT="ArduinoJson-$TAG.zip"
cd $(dirname $0)/../..
# remove existing file
rm -f $OUTPUT
# create zip
7z a $OUTPUT \
ArduinoJson/CHANGELOG.md \
ArduinoJson/examples \
ArduinoJson/include \
ArduinoJson/keywords.txt \
ArduinoJson/library.properties \
ArduinoJson/LICENSE.md \
ArduinoJson/README.md \
ArduinoJson/src \
-x!ArduinoJson/src/CMakeLists.txt

View File

@ -20,10 +20,10 @@ build-env()
if [[ $(uname) == MINGW* ]]
then
build-env "Make" "MinGW Makefiles"
build-env "SublimeText" "Sublime Text 2 - MinGW Makefiles"
build-env "SublimeText" "Sublime Text 2 - Ninja"
build-env "VisualStudio" "Visual Studio 12 2013"
else
build-env "SublimeText" "Sublime Text 2 - Unix Makefiles"
build-env "SublimeText" "Sublime Text 2 - Ninja"
build-env "Make" "Unix Makefiles"
build-env "Xcode" "Xcode"
fi

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -8,7 +8,14 @@
#include "../../include/ArduinoJson/Arduino/Print.hpp"
#include <stdio.h> // for sprintf
#include <math.h> // for isnan() and isinf()
#include <stdio.h> // for sprintf()
// only for GCC 4.9+
#if defined(__GNUC__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif
size_t Print::print(const char s[]) {
size_t n = 0;
@ -19,8 +26,24 @@ size_t Print::print(const char s[]) {
}
size_t Print::print(double value, int digits) {
// https://github.com/arduino/Arduino/blob/db8cbf24c99dc930b9ccff1a43d018c81f178535/hardware/arduino/sam/cores/arduino/Print.cpp#L218
if (isnan(value)) return print("nan");
if (isinf(value)) return print("inf");
char tmp[32];
sprintf(tmp, "%.*f", digits, value);
// https://github.com/arduino/Arduino/blob/db8cbf24c99dc930b9ccff1a43d018c81f178535/hardware/arduino/sam/cores/arduino/Print.cpp#L220
bool isBigDouble = value > 4294967040.0 || value < -4294967040.0;
if (isBigDouble) {
// Arduino's implementation prints "ovf"
// We prefer trying to use scientific notation, since we have sprintf
sprintf(tmp, "%g", value);
} else {
// Here we have the exact same output as Arduino's implementation
sprintf(tmp, "%.*f", digits, value);
}
return print(tmp);
}

31
src/Arduino/String.cpp Normal file
View File

@ -0,0 +1,31 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#ifndef ARDUINO
#include "../../include/ArduinoJson/Arduino/String.hpp"
#include <stdio.h> // for sprintf()
String::String(double value, unsigned char digits) {
char tmp[32];
sprintf(tmp, "%.*f", digits, value);
*this = tmp;
}
String::String(int value) {
char tmp[32];
sprintf(tmp, "%d", value);
*this = tmp;
}
String::String(long value) {
char tmp[32];
sprintf(tmp, "%ld", value);
*this = tmp;
}
#endif

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,5 +1,6 @@
file(GLOB_RECURSE INC_FILES ../include/*.hpp)
file(GLOB_RECURSE SRC_FILES *.cpp)
file(GLOB_RECURSE HPP_FILES ../include/*.hpp)
file(GLOB_RECURSE IPP_FILES ../include/*.ipp)
file(GLOB_RECURSE CPP_FILES *.cpp)
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
add_definitions(
@ -20,6 +21,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
-Wno-sign-conversion
-Wno-unused
-Wno-variadic-macros
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
@ -44,4 +46,4 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
)
endif()
add_library(ArduinoJson ${SRC_FILES} ${INC_FILES})
add_library(ArduinoJson ${CPP_FILES} ${HPP_FILES} ${IPP_FILES})

View File

@ -0,0 +1,51 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../../include/ArduinoJson/Internals/Comments.hpp"
inline static const char *skipCStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0') return ptr;
if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2;
ptr++;
}
}
inline static const char *skipCppStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
ptr++;
}
}
const char *ArduinoJson::Internals::skipSpacesAndComments(const char *ptr) {
for (;;) {
switch (ptr[0]) {
case ' ':
case '\t':
case '\r':
case '\n':
ptr++;
continue;
case '/':
switch (ptr[1]) {
case '*':
ptr = skipCStyleComment(ptr);
break;
case '/':
ptr = skipCppStyleComment(ptr);
break;
default:
return ptr;
}
break;
default:
return ptr;
}
}
}

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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,10 +6,8 @@
#include "../../include/ArduinoJson/Internals/JsonParser.hpp"
#include <stdlib.h> // for strtol, strtod
#include <ctype.h>
#include "../../include/ArduinoJson/Internals/QuotedString.hpp"
#include "../../include/ArduinoJson/Internals/Comments.hpp"
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
#include "../../include/ArduinoJson/JsonArray.hpp"
#include "../../include/ArduinoJson/JsonBuffer.hpp"
#include "../../include/ArduinoJson/JsonObject.hpp"
@ -17,73 +15,35 @@
using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
void JsonParser::skipSpaces() {
while (isspace(*_ptr)) _ptr++;
}
bool JsonParser::skip(char charToSkip) {
skipSpaces();
if (*_ptr != charToSkip) return false;
_ptr++;
skipSpaces();
register const char *ptr = skipSpacesAndComments(_readPtr);
if (*ptr != charToSkip) return false;
ptr++;
_readPtr = skipSpacesAndComments(ptr);
return true;
}
bool JsonParser::skip(const char *wordToSkip) {
const char *charToSkip = wordToSkip;
while (*charToSkip && *_ptr == *charToSkip) {
charToSkip++;
_ptr++;
}
return *charToSkip == '\0';
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
if (_nestingLimit == 0) return false;
_nestingLimit--;
bool success = parseAnythingToUnsafe(destination);
_nestingLimit++;
return success;
}
void JsonParser::parseAnythingTo(JsonVariant &destination) {
if (_nestingLimit == 0) return;
_nestingLimit--;
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
_readPtr = skipSpacesAndComments(_readPtr);
skipSpaces();
switch (*_ptr) {
switch (*_readPtr) {
case '[':
destination = parseArray();
break;
return parseArrayTo(destination);
case '{':
destination = parseObject();
break;
return parseObjectTo(destination);
case 't':
case 'f':
parseBooleanTo(destination);
break;
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
parseNumberTo(destination);
break;
case 'n':
parseNullTo(destination);
break;
case '\'':
case '\"':
destination = parseString();
break;
default:
return parseStringTo(destination);
}
_nestingLimit++;
}
JsonArray &JsonParser::parseArray() {
@ -97,9 +57,9 @@ JsonArray &JsonParser::parseArray() {
// Read each value
for (;;) {
// 1 - Parse value
JsonVariant &value = array.add();
parseAnythingTo(value);
if (!value.success()) goto ERROR_INVALID_VALUE;
JsonVariant value;
if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
if (!array.add(value)) goto ERROR_NO_MEMORY;
// 2 - More values?
if (skip(']')) goto SUCCES_NON_EMPTY_ARRAY;
@ -113,9 +73,18 @@ SUCCES_NON_EMPTY_ARRAY:
ERROR_INVALID_VALUE:
ERROR_MISSING_BRACKET:
ERROR_MISSING_COMMA:
ERROR_NO_MEMORY:
return JsonArray::invalid();
}
bool JsonParser::parseArrayTo(JsonVariant *destination) {
JsonArray &array = parseArray();
if (!array.success()) return false;
*destination = array;
return true;
}
JsonObject &JsonParser::parseObject() {
// Create an empty object
JsonObject &object = _buffer->createObject();
@ -132,9 +101,9 @@ JsonObject &JsonParser::parseObject() {
if (!skip(':')) goto ERROR_MISSING_COLON;
// 2 - Parse value
JsonVariant &value = object.add(key);
parseAnythingTo(value);
if (!value.success()) goto ERROR_INVALID_VALUE;
JsonVariant value;
if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
if (!object.set(key, value)) goto ERROR_NO_MEMORY;
// 3 - More keys/values?
if (skip('}')) goto SUCCESS_NON_EMPTY_OBJECT;
@ -150,48 +119,82 @@ ERROR_INVALID_VALUE:
ERROR_MISSING_BRACE:
ERROR_MISSING_COLON:
ERROR_MISSING_COMMA:
ERROR_NO_MEMORY:
return JsonObject::invalid();
}
void JsonParser::parseBooleanTo(JsonVariant &destination) {
if (skip("true"))
destination = true;
else if (skip("false"))
destination = false;
else
destination = JsonVariant::invalid();
bool JsonParser::parseObjectTo(JsonVariant *destination) {
JsonObject &object = parseObject();
if (!object.success()) return false;
*destination = object;
return true;
}
void JsonParser::parseNumberTo(JsonVariant &destination) {
char *endOfLong;
long longValue = strtol(_ptr, &endOfLong, 10);
char stopChar = *endOfLong;
// Could it be a floating point value?
bool couldBeFloat = stopChar == '.' || stopChar == 'e' || stopChar == 'E';
if (couldBeFloat) {
// Yes => parse it as a double
double doubleValue = strtod(_ptr, &_ptr);
// Count the decimal digits
uint8_t decimals = static_cast<uint8_t>(_ptr - endOfLong - 1);
// Set the variant as a double
destination.set(doubleValue, decimals);
} else {
// No => set the variant as a long
_ptr = endOfLong;
destination = longValue;
}
static inline bool isInRange(char c, char min, char max) {
return min <= c && c <= max;
}
void JsonParser::parseNullTo(JsonVariant &destination) {
const char *NULL_STRING = NULL;
if (skip("null"))
destination = NULL_STRING;
else
destination = JsonVariant::invalid();
static inline bool isLetterOrNumber(char c) {
return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') ||
isInRange(c, 'A', 'Z') || c == '-' || c == '.';
}
static inline bool isQuote(char c) { return c == '\'' || c == '\"'; }
const char *JsonParser::parseString() {
return QuotedString::extractFrom(_ptr, &_ptr);
const char *readPtr = _readPtr;
char *writePtr = _writePtr;
char c = *readPtr;
if (isQuote(c)) { // quotes
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 { // no quotes
for (;;) {
if (!isLetterOrNumber(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) {
bool hasQuotes = isQuote(_readPtr[0]);
const char *value = parseString();
if (value == NULL) return false;
if (hasQuotes) {
*destination = value;
} else {
*destination = Unparsed(value);
}
return true;
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -6,7 +6,6 @@
#include "../../include/ArduinoJson/Internals/List.hpp"
#include "../../include/ArduinoJson/Internals/PlacementNew.hpp"
#include "../../include/ArduinoJson/JsonPair.hpp"
#include "../../include/ArduinoJson/JsonVariant.hpp"
@ -14,12 +13,27 @@ using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
template <typename T>
int List<T>::size() const {
int nodeCount = 0;
size_t List<T>::size() const {
size_t nodeCount = 0;
for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
return nodeCount;
}
template <typename T>
typename List<T>::node_type *List<T>::addNewNode() {
node_type *newNode = new (_buffer) node_type();
if (_firstNode) {
node_type *lastNode = _firstNode;
while (lastNode->next) lastNode = lastNode->next;
lastNode->next = newNode;
} else {
_firstNode = newNode;
}
return newNode;
}
template <typename T>
void List<T>::removeNode(node_type *nodeToRemove) {
if (!nodeToRemove) return;

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -33,7 +33,7 @@ inline size_t Prettyfier::handleMarkupChar(uint8_t c) {
return handleBlockClose(c);
case ':':
return handleColumn();
return handleColon();
case ',':
return handleComma();
@ -54,7 +54,7 @@ inline size_t Prettyfier::handleBlockClose(uint8_t c) {
return unindentIfNeeded() + _sink.write(c);
}
inline size_t Prettyfier::handleColumn() {
inline size_t Prettyfier::handleColon() {
return _sink.write(':') + _sink.write(' ');
}

View File

@ -1,98 +0,0 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../../include/ArduinoJson/Internals/QuotedString.hpp"
using namespace ArduinoJson::Internals;
static inline char getSpecialChar(char c) {
// Optimized for code size on a 8-bit AVR
const char *p = "\"\"\\\\\bb\ff\nn\rr\tt\0";
while (p[0] && p[0] != c) {
p += 2;
}
return p[1];
}
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 = "b\bf\fn\nr\rt\t";
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

@ -1,14 +1,14 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../../include/ArduinoJson/Internals/StringBuilder.hpp"
#include "../../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
using namespace ArduinoJson::Internals;
size_t StringBuilder::write(uint8_t c) {
size_t StaticStringBuilder::write(uint8_t c) {
if (length >= capacity) return 0;
buffer[length++] = c;

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -14,19 +14,10 @@ using namespace ArduinoJson::Internals;
JsonArray JsonArray::_invalid(NULL);
JsonVariant &JsonArray::at(int index) const {
JsonArray::node_type *JsonArray::getNodeAt(size_t index) const {
node_type *node = _firstNode;
while (node && index--) node = node->next;
return node ? node->content : JsonVariant::invalid();
}
JsonVariant &JsonArray::add() {
node_type *node = createNode();
if (!node) return JsonVariant::invalid();
addNode(node);
return node->content;
return node;
}
JsonArray &JsonArray::createNestedArray() {
@ -43,6 +34,8 @@ JsonObject &JsonArray::createNestedObject() {
return object;
}
void JsonArray::removeAt(size_t index) { removeNode(getNodeAt(index)); }
void JsonArray::writeTo(JsonWriter &writer) const {
writer.beginArray();

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -7,7 +7,6 @@
#include "../include/ArduinoJson/JsonBuffer.hpp"
#include "../include/ArduinoJson/Internals/JsonParser.hpp"
#include "../include/ArduinoJson/Internals/PlacementNew.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
@ -15,15 +14,13 @@ using namespace ArduinoJson;
using namespace ArduinoJson::Internals;
JsonArray &JsonBuffer::createArray() {
void *ptr = alloc(sizeof(JsonArray));
if (ptr) return *new (ptr) JsonArray(this);
return JsonArray::invalid();
JsonArray *ptr = new (this) JsonArray(this);
return ptr ? *ptr : JsonArray::invalid();
}
JsonObject &JsonBuffer::createObject() {
void *ptr = alloc(sizeof(JsonObject));
if (ptr) return *new (ptr) JsonObject(this);
return JsonObject::invalid();
JsonObject *ptr = new (this) JsonObject(this);
return ptr ? *ptr : JsonObject::invalid();
}
JsonArray &JsonBuffer::parseArray(char *json, uint8_t nestingLimit) {
@ -35,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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -8,8 +8,7 @@
#include <string.h> // for strcmp
#include "../include/ArduinoJson/Internals/PlacementNew.hpp"
#include "../include/ArduinoJson/Internals/StringBuilder.hpp"
#include "../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonBuffer.hpp"
@ -18,49 +17,35 @@ using namespace ArduinoJson::Internals;
JsonObject JsonObject::_invalid(NULL);
JsonVariant &JsonObject::at(const char *key) {
node_type *node = getNodeAt(key);
return node ? node->content.value : JsonVariant::invalid();
JsonObject::node_type *JsonObject::getOrCreateNodeAt(JsonObjectKey key) {
node_type *existingNode = getNodeAt(key);
if (existingNode) return existingNode;
node_type *newNode = addNewNode();
return newNode;
}
const JsonVariant &JsonObject::at(const char *key) const {
node_type *node = getNodeAt(key);
return node ? node->content.value : JsonVariant::invalid();
}
JsonVariant &JsonObject::operator[](const char *key) {
// try to find an existing node
node_type *node = getNodeAt(key);
// not fount => create a new one
if (!node) {
node = createNode();
if (!node) return JsonVariant::invalid();
node->content.key = key;
addNode(node);
}
return node->content.value;
}
void JsonObject::remove(char const *key) { removeNode(getNodeAt(key)); }
JsonArray &JsonObject::createNestedArray(char const *key) {
template <typename TKey>
JsonArray &JsonObject::createArrayAt(TKey key) {
if (!_buffer) return JsonArray::invalid();
JsonArray &array = _buffer->createArray();
add(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(const char *key) {
template <typename TKey>
JsonObject &JsonObject::createObjectAt(TKey key) {
if (!_buffer) return JsonObject::invalid();
JsonObject &object = _buffer->createObject();
add(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(const char *key) const {
JsonObject::node_type *JsonObject::getNodeAt(JsonObjectKey key) const {
for (node_type *node = _firstNode; node; node = node->next) {
if (!strcmp(node->content.key, key)) return node;
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -9,100 +9,111 @@
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
using namespace ArduinoJson;
#include <errno.h> // for errno
#include <stdlib.h> // for strtol, strtod
using namespace ArduinoJson::Internals;
JsonVariant JsonVariant::_invalid(JSON_INVALID);
namespace ArduinoJson {
JsonVariant::operator JsonArray &() const {
return _type == JSON_ARRAY ? *_content.asArray : JsonArray::invalid();
template <>
const char *JsonVariant::as<const char *>() const {
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
}
JsonVariant::operator JsonObject &() const {
return _type == JSON_OBJECT ? *_content.asObject : JsonObject::invalid();
template <>
double JsonVariant::as<double>() const {
if (_type >= JSON_DOUBLE_0_DECIMALS) return _content.asDouble;
if (_type == JSON_LONG || _type == JSON_BOOLEAN)
return static_cast<double>(_content.asLong);
if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString)
return strtod(_content.asString, NULL);
return 0.0;
}
JsonVariant::operator bool() const {
return _type == JSON_BOOLEAN ? _content.asBoolean : false;
template <>
long JsonVariant::as<long>() const {
if (_type == JSON_LONG || _type == JSON_BOOLEAN) return _content.asLong;
if (_type >= JSON_DOUBLE_0_DECIMALS)
return static_cast<long>(_content.asDouble);
if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) {
if (!strcmp("true", _content.asString)) return 1;
return strtol(_content.asString, NULL, 10);
}
return 0L;
}
JsonVariant::operator const char *() const {
return _type == JSON_STRING ? _content.asString : NULL;
template <>
String JsonVariant::as<String>() const {
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
_content.asString != NULL)
return String(_content.asString);
if (_type == JSON_LONG || _type == JSON_BOOLEAN)
return String(_content.asLong);
if (_type >= JSON_DOUBLE_0_DECIMALS) {
uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
return String(_content.asDouble, decimals);
}
String s;
printTo(s);
return s;
}
JsonVariant::operator double() const {
return _type >= JSON_DOUBLE_0_DECIMALS ? _content.asDouble : 0;
template <>
bool JsonVariant::is<signed long>() const {
if (_type == JSON_LONG) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtol(_content.asString, &end, 10);
return *end == '\0' && errno == 0;
}
JsonVariant::operator long() const {
return _type == JSON_LONG ? _content.asLong : 0;
}
template <>
bool JsonVariant::is<double>() const {
if (_type >= JSON_DOUBLE_0_DECIMALS) return true;
void JsonVariant::set(bool value) {
if (_type == JSON_INVALID) return;
_type = Internals::JSON_BOOLEAN;
_content.asBoolean = value;
}
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
void JsonVariant::set(const char *value) {
if (_type == JSON_INVALID) return;
_type = JSON_STRING;
_content.asString = value;
}
char *end;
errno = 0;
strtod(_content.asString, &end);
void JsonVariant::set(double value, uint8_t decimals) {
if (_type == JSON_INVALID) return;
_type = static_cast<JsonVariantType>(JSON_DOUBLE_0_DECIMALS + decimals);
_content.asDouble = value;
}
void JsonVariant::set(long value) {
if (_type == JSON_INVALID) return;
_type = JSON_LONG;
_content.asLong = value;
}
void JsonVariant::set(JsonArray &array) {
if (_type == JSON_INVALID) return;
_type = JSON_ARRAY;
_content.asArray = &array;
}
void JsonVariant::set(JsonObject &object) {
if (_type == JSON_INVALID) return;
_type = JSON_OBJECT;
_content.asObject = &object;
}
size_t JsonVariant::size() const {
if (_type == JSON_ARRAY) return _content.asArray->size();
if (_type == JSON_OBJECT) return _content.asObject->size();
return 0;
}
JsonVariant &JsonVariant::operator[](int index) {
if (_type != JSON_ARRAY) return JsonVariant::invalid();
return _content.asArray->operator[](index);
}
JsonVariant &JsonVariant::operator[](const char *key) {
if (_type != JSON_OBJECT) return JsonVariant::invalid();
return _content.asObject->operator[](key);
return *end == '\0' && errno == 0 && !is<long>();
}
void JsonVariant::writeTo(JsonWriter &writer) const {
if (is<const JsonArray &>())
as<const JsonArray &>().writeTo(writer);
else if (is<const JsonObject &>())
as<const JsonObject &>().writeTo(writer);
else if (is<const char *>())
writer.writeString(as<const char *>());
else if (is<long>())
writer.writeLong(as<long>());
else if (is<bool>())
writer.writeBoolean(as<bool>());
else if (is<double>()) {
if (_type == JSON_ARRAY) _content.asArray->writeTo(writer);
if (_type == JSON_OBJECT) _content.asObject->writeTo(writer);
if (_type == JSON_STRING) writer.writeString(_content.asString);
if (_type == JSON_UNPARSED) writer.writeRaw(_content.asString);
if (_type == JSON_LONG) writer.writeLong(_content.asLong);
if (_type == JSON_BOOLEAN) writer.writeBoolean(_content.asLong);
if (_type >= JSON_DOUBLE_0_DECIMALS) {
uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
writer.writeDouble(as<double>(), decimals);
writer.writeDouble(_content.asDouble, decimals);
}
}
}

View File

@ -0,0 +1,200 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#include <ArduinoJson.h>
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_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_F(ArduinoStringTests, JsonObject_Subscript) {
char json[] = "{\"key\":\"value\"}";
JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object[String("key")]);
}
TEST_F(ArduinoStringTests, JsonObject_ConstSubscript) {
char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object[String("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_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);
ASSERT_STREQ("value", object.get(String("key")));
}
TEST_F(ArduinoStringTests, JsonObject_GetT) {
char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_STREQ("value", object.get<const char *>(String("key")));
}
TEST_F(ArduinoStringTests, JsonObject_IsT) {
char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_TRUE(object.is<const char *>(String("key")));
}
TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) {
String key = "key";
char json[64];
JsonObject &object = _jsonBuffer.createObject();
object.createNestedObject(key);
eraseString(key);
object.printTo(json, sizeof(json));
ASSERT_STREQ("{\"key\":{}}", json);
}
TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) {
String key = "key";
char json[64];
JsonObject &object = _jsonBuffer.createObject();
object.createNestedArray(key);
eraseString(key);
object.printTo(json, sizeof(json));
ASSERT_STREQ("{\"key\":[]}", json);
}
TEST_F(ArduinoStringTests, JsonObject_ContainsKey) {
char json[] = "{\"key\":\"value\"}";
const JsonObject &object = _jsonBuffer.parseObject(json);
ASSERT_TRUE(object.containsKey(String("key")));
}
TEST_F(ArduinoStringTests, JsonObject_Remove) {
char json[] = "{\"key\":\"value\"}";
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]);
}
TEST_F(ArduinoStringTests, JsonArray_PrintTo) {
JsonArray &array = _jsonBuffer.createArray();
array.add(4);
array.add(2);
String json;
array.printTo(json);
ASSERT_EQ(String("[4,2]"), json);
}
TEST_F(ArduinoStringTests, JsonArray_PrettyPrintTo) {
JsonArray &array = _jsonBuffer.createArray();
array.add(4);
array.add(2);
String json;
array.prettyPrintTo(json);
ASSERT_EQ(String("[\r\n 4,\r\n 2\r\n]"), json);
}
TEST_F(ArduinoStringTests, JsonObject_PrintTo) {
JsonObject &object = _jsonBuffer.createObject();
object["key"] = "value";
String json;
object.printTo(json);
ASSERT_EQ(String("{\"key\":\"value\"}"), json);
}
TEST_F(ArduinoStringTests, JsonObject_PrettyPrintTo) {
JsonObject &object = _jsonBuffer.createObject();
object["key"] = "value";
String json;
object.prettyPrintTo(json);
ASSERT_EQ(String("{\r\n \"key\": \"value\"\r\n}"), json);
}

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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -20,40 +20,11 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, InitialSizeIsZero) {
ASSERT_EQ(0, buffer.size());
}
TEST_F(DynamicJsonBuffer_Basic_Tests, InitialBlockCountIsOne) {
ASSERT_EQ(1, buffer.blockCount());
}
TEST_F(DynamicJsonBuffer_Basic_Tests, SizeIncreasesAfterAlloc) {
buffer.alloc(1);
ASSERT_EQ(1, buffer.size());
buffer.alloc(1);
ASSERT_EQ(2, buffer.size());
buffer.alloc(DynamicJsonBuffer::BLOCK_CAPACITY);
ASSERT_EQ(2 + DynamicJsonBuffer::BLOCK_CAPACITY, buffer.size());
}
TEST_F(DynamicJsonBuffer_Basic_Tests, BlockCountDoesntChangeWhenNotFull) {
buffer.alloc(DynamicJsonBuffer::BLOCK_CAPACITY);
ASSERT_EQ(1, buffer.blockCount());
}
TEST_F(DynamicJsonBuffer_Basic_Tests, BlockCountChangesWhenFull) {
buffer.alloc(DynamicJsonBuffer::BLOCK_CAPACITY);
buffer.alloc(1);
ASSERT_EQ(2, buffer.blockCount());
}
TEST_F(DynamicJsonBuffer_Basic_Tests, CanAllocLessThanBlockCapacity) {
void* p1 = buffer.alloc(DynamicJsonBuffer::BLOCK_CAPACITY);
ASSERT_TRUE(p1);
void* p2 = buffer.alloc(DynamicJsonBuffer::BLOCK_CAPACITY);
ASSERT_TRUE(p2);
}
TEST_F(DynamicJsonBuffer_Basic_Tests, CantAllocMoreThanBlockCapacity) {
void* p = buffer.alloc(DynamicJsonBuffer::BLOCK_CAPACITY + 1);
ASSERT_FALSE(p);
}
TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {

View File

@ -0,0 +1,37 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#include <ArduinoJson.h>
class DynamicJsonBuffer_NoMemory_Tests : public ::testing::Test {
class NoMemoryAllocator {
public:
void* allocate(size_t) { return NULL; }
void deallocate(void*) {}
};
protected:
Internals::BlockJsonBuffer<NoMemoryAllocator> _jsonBuffer;
};
TEST_F(DynamicJsonBuffer_NoMemory_Tests, CreateArray) {
ASSERT_FALSE(_jsonBuffer.createArray().success());
}
TEST_F(DynamicJsonBuffer_NoMemory_Tests, CreateObject) {
ASSERT_FALSE(_jsonBuffer.createObject().success());
}
TEST_F(DynamicJsonBuffer_NoMemory_Tests, ParseArray) {
char json[] = "[]";
ASSERT_FALSE(_jsonBuffer.parseArray(json).success());
}
TEST_F(DynamicJsonBuffer_NoMemory_Tests, ParseObject) {
char json[] = "{}";
ASSERT_FALSE(_jsonBuffer.parseObject(json).success());
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -13,12 +13,12 @@ TEST(DynamicJsonBuffer_Object_Tests, GrowsWithObject) {
JsonObject &obj = json.createObject();
ASSERT_EQ(JSON_OBJECT_SIZE(0), json.size());
obj["hello"];
obj["hello"] = 1;
ASSERT_EQ(JSON_OBJECT_SIZE(1), json.size());
obj["world"];
obj["world"] = 2;
ASSERT_EQ(JSON_OBJECT_SIZE(2), json.size());
obj["world"]; // <- same value, should not grow
obj["world"] = 3; // <- same key, should not grow
ASSERT_EQ(JSON_OBJECT_SIZE(2), json.size());
}

View File

@ -1,12 +1,12 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// 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:
@ -37,7 +37,7 @@ class GbathreeBug : public testing::Test {
TEST_F(GbathreeBug, Success) { EXPECT_TRUE(_object.success()); }
TEST_F(GbathreeBug, ProtocolName) {
EXPECT_STREQ("fluorescence", _object.at("protocol_name").asString());
EXPECT_STREQ("fluorescence", _object["protocol_name"]);
}
TEST_F(GbathreeBug, Repeats) { EXPECT_EQ(1, _object["repeats"]); }
@ -69,7 +69,7 @@ TEST_F(GbathreeBug, Calintensity) { EXPECT_EQ(255, _object["calintensity"]); }
TEST_F(GbathreeBug, Pulses) {
// "pulses":[50,50,50]
JsonArray& array = _object.at("pulses");
JsonArray& array = _object["pulses"];
EXPECT_TRUE(array.success());
EXPECT_EQ(3, array.size());
@ -82,7 +82,7 @@ TEST_F(GbathreeBug, Pulses) {
TEST_F(GbathreeBug, Act) {
// "act":[2,1,2,2]
JsonArray& array = _object.at("act");
JsonArray& array = _object["act"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -95,7 +95,7 @@ TEST_F(GbathreeBug, Act) {
TEST_F(GbathreeBug, Detectors) {
// "detectors":[[34,34,34,34],[34,34,34,34],[34,34,34,34],[34,34,34,34]]
JsonArray& array = _object.at("detectors");
JsonArray& array = _object["detectors"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -110,7 +110,7 @@ TEST_F(GbathreeBug, Detectors) {
TEST_F(GbathreeBug, Alta) {
// alta:[2,2,2,2]
JsonArray& array = _object.at("alta");
JsonArray& array = _object["alta"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -123,7 +123,7 @@ TEST_F(GbathreeBug, Alta) {
TEST_F(GbathreeBug, Altb) {
// altb:[2,2,2,2]
JsonArray& array = _object.at("altb");
JsonArray& array = _object["altb"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -136,7 +136,7 @@ TEST_F(GbathreeBug, Altb) {
TEST_F(GbathreeBug, Measlights) {
// "measlights":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]]
JsonArray& array = _object.at("measlights");
JsonArray& array = _object["measlights"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -152,7 +152,7 @@ TEST_F(GbathreeBug, Measlights) {
TEST_F(GbathreeBug, Measlights2) {
// "measlights2":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]]
JsonArray& array = _object.at("measlights2");
JsonArray& array = _object["measlights2"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -167,7 +167,7 @@ TEST_F(GbathreeBug, Measlights2) {
TEST_F(GbathreeBug, Altc) {
// altc:[2,2,2,2]
JsonArray& array = _object.at("altc");
JsonArray& array = _object["altc"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());
@ -180,7 +180,7 @@ TEST_F(GbathreeBug, Altc) {
TEST_F(GbathreeBug, Altd) {
// altd:[2,2,2,2]
JsonArray& array = _object.at("altd");
JsonArray& array = _object["altd"];
EXPECT_TRUE(array.success());
EXPECT_EQ(4, array.size());

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

47
test/Issue67.cpp Normal file
View File

@ -0,0 +1,47 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#include <ArduinoJson.h>
class Issue67 : public testing::Test {
public:
void whenInputIs(double value) { _variant = value; }
void outputMustBe(const char* expected) {
char buffer[1024];
_variant.printTo(buffer, sizeof(buffer));
ASSERT_STREQ(expected, buffer);
}
private:
JsonVariant _variant;
};
TEST_F(Issue67, BigPositiveDouble) {
whenInputIs(1e100);
outputMustBe("1e+100");
}
TEST_F(Issue67, BigNegativeDouble) {
whenInputIs(-1e100);
outputMustBe("-1e+100");
}
TEST_F(Issue67, Zero) {
whenInputIs(0.0);
outputMustBe("0.00");
}
TEST_F(Issue67, SmallPositiveDouble) {
whenInputIs(111.111);
outputMustBe("111.11");
}
TEST_F(Issue67, SmallNegativeDouble) {
whenInputIs(-111.111);
outputMustBe("-111.11");
}

28
test/Issue90.cpp Normal file
View File

@ -0,0 +1,28 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#include <limits.h> // for LONG_MAX
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson.h>
#define SUITE Issue90
using namespace ArduinoJson::Internals;
static const char* superLong =
"12345678901234567890123456789012345678901234567890123456789012345678901234"
"5678901234567890123456789012345678901234567890123456789012345678901234567";
static const JsonVariant variant = Unparsed(superLong);
TEST(SUITE, IsNotALong) { ASSERT_FALSE(variant.is<long>()); }
TEST(SUITE, AsLong) { ASSERT_EQ(LONG_MAX, variant.as<long>()); }
TEST(SUITE, IsAString) { ASSERT_FALSE(variant.is<const char*>()); }
TEST(SUITE, AsString) { ASSERT_STREQ(superLong, variant.as<const char*>()); }

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -48,6 +48,11 @@ class JsonArray_Container_Tests : public ::testing::Test {
}
};
template <>
void JsonArray_Container_Tests::itemMustEqual(int index, const char* expected) {
EXPECT_STREQ(expected, _array[index].asString());
}
TEST_F(JsonArray_Container_Tests, SuccessIsTrue) {
EXPECT_TRUE(_array.success());
}
@ -62,6 +67,12 @@ TEST_F(JsonArray_Container_Tests, Grow_WhenValuesAreAdded) {
sizeMustBe(2);
}
TEST_F(JsonArray_Container_Tests, DontGrow_WhenValuesAreReplaced) {
_array.add("hello");
_array[0] = "world";
sizeMustBe(1);
}
TEST_F(JsonArray_Container_Tests, CanStoreIntegers) {
_array.add(123);
_array.add(456);
@ -87,14 +98,11 @@ TEST_F(JsonArray_Container_Tests, CanStoreBooleans) {
}
TEST_F(JsonArray_Container_Tests, CanStoreStrings) {
const char* firstString = "h3110";
const char* secondString = "w0r1d";
_array.add("hello");
_array.add("world");
_array.add(firstString);
_array.add(secondString);
firstMustEqual(firstString);
secondMustEqual(secondString);
firstMustEqual("hello");
secondMustEqual("world");
}
TEST_F(JsonArray_Container_Tests, CanStoreNestedArrays) {
@ -134,3 +142,39 @@ TEST_F(JsonArray_Container_Tests, CanCreateNestedObjects) {
firstMustReference(innerObject1);
secondMustReference(innerObject2);
}
TEST_F(JsonArray_Container_Tests, RemoveFirstElement) {
_array.add("one");
_array.add("two");
_array.add("three");
_array.removeAt(0);
sizeMustBe(2);
firstMustEqual("two");
secondMustEqual("three");
}
TEST_F(JsonArray_Container_Tests, RemoveMiddleElement) {
_array.add("one");
_array.add("two");
_array.add("three");
_array.removeAt(1);
sizeMustBe(2);
firstMustEqual("one");
secondMustEqual("three");
}
TEST_F(JsonArray_Container_Tests, RemoveLastElement) {
_array.add("one");
_array.add("two");
_array.add("three");
_array.removeAt(2);
sizeMustBe(2);
firstMustEqual("one");
secondMustEqual("two");
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -7,10 +7,6 @@
#include <gtest/gtest.h>
#include <ArduinoJson.h>
TEST(JsonArray_Invalid_Tests, AtFails) {
ASSERT_FALSE(JsonArray::invalid().at(0).success());
}
TEST(JsonArray_Invalid_Tests, SubscriptFails) {
ASSERT_FALSE(JsonArray::invalid()[0].success());
}
@ -33,4 +29,4 @@ TEST(JsonArray_Invalid_Tests, PrintToWritesBrackets) {
char buffer[32];
JsonArray::invalid().printTo(buffer, sizeof(buffer));
ASSERT_STREQ("[]", buffer);
}
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -16,13 +16,15 @@ class JsonArray_PrettyPrintTo_Tests : public testing::Test {
JsonArray& array;
void outputMustBe(const char* expected) {
size_t n = array.prettyPrintTo(_buffer, sizeof(_buffer));
EXPECT_STREQ(expected, _buffer);
EXPECT_EQ(strlen(expected), n);
}
char actual[256];
private:
char _buffer[256];
size_t actualLen = array.prettyPrintTo(actual, sizeof(actual));
size_t measuredLen = array.measurePrettyLength();
EXPECT_STREQ(expected, actual);
EXPECT_EQ(strlen(expected), actualLen);
EXPECT_EQ(strlen(expected), measuredLen);
}
};
TEST_F(JsonArray_PrettyPrintTo_Tests, Empty) { outputMustBe("[]"); }

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -16,9 +16,12 @@ class JsonArray_PrintTo_Tests : public testing::Test {
JsonArray &array;
void outputMustBe(const char *expected) {
size_t n = array.printTo(buffer, sizeof(buffer));
size_t actualLen = array.printTo(buffer, sizeof(buffer));
size_t measuredLen = array.measureLength();
EXPECT_STREQ(expected, buffer);
EXPECT_EQ(strlen(expected), n);
EXPECT_EQ(strlen(expected), actualLen);
EXPECT_EQ(strlen(expected), measuredLen);
}
private:
@ -60,7 +63,7 @@ TEST_F(JsonArray_PrintTo_Tests, OneDoubleDefaultDigits) {
}
TEST_F(JsonArray_PrintTo_Tests, OneDoubleFourDigits) {
array.add(3.14159265358979323846, 4);
array.add(double_with_n_digits(3.14159265358979323846, 4));
outputMustBe("[3.1416]");
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -21,24 +21,24 @@ TEST_F(JsonObject_Container_Tests, InitialSizeIsZero) {
}
TEST_F(JsonObject_Container_Tests, Grow_WhenValuesAreAdded) {
_object["hello"];
_object["hello"] = 1;
EXPECT_EQ(1, _object.size());
_object["world"];
_object.set("world", 2);
EXPECT_EQ(2, _object.size());
}
TEST_F(JsonObject_Container_Tests, DoNotGrow_WhenSameValueIsAdded) {
_object["hello"];
_object["hello"] = 1;
EXPECT_EQ(1, _object.size());
_object["hello"];
_object["hello"] = 2;
EXPECT_EQ(1, _object.size());
}
TEST_F(JsonObject_Container_Tests, Shrink_WhenValuesAreRemoved) {
_object["hello"];
_object["world"];
_object["hello"] = 1;
_object["world"] = 2;
_object.remove("hello");
EXPECT_EQ(1, _object.size());
@ -49,8 +49,8 @@ TEST_F(JsonObject_Container_Tests, Shrink_WhenValuesAreRemoved) {
TEST_F(JsonObject_Container_Tests,
DoNotShrink_WhenRemoveIsCalledWithAWrongKey) {
_object["hello"];
_object["world"];
_object["hello"] = 1;
_object["world"] = 2;
_object.remove(":-P");
@ -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,44 +83,39 @@ 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, ContainsKeyReturnFalseForNonExistingKey) {
TEST_F(JsonObject_Container_Tests, ContainsKeyReturnsFalseForNonExistingKey) {
EXPECT_FALSE(_object.containsKey("hello"));
}
TEST_F(JsonObject_Container_Tests, ContainsKeyReturnTrueForDefinedValue) {
_object.add("hello", 42);
TEST_F(JsonObject_Container_Tests, ContainsKeyReturnsTrueForDefinedValue) {
_object.set("hello", 42);
EXPECT_TRUE(_object.containsKey("hello"));
}
TEST_F(JsonObject_Container_Tests, ContainsKeyReturnFalseForUndefinedValue) {
_object.add("hello");
EXPECT_FALSE(_object.containsKey("hello"));
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -7,18 +7,14 @@
#include <gtest/gtest.h>
#include <ArduinoJson.h>
TEST(JsonObject_Invalid_Tests, AtFails) {
ASSERT_FALSE(JsonObject::invalid().at(0).success());
}
TEST(JsonObject_Invalid_Tests, SubscriptFails) {
ASSERT_FALSE(JsonObject::invalid()[0].success());
}
TEST(JsonObject_Invalid_Tests, AddFails) {
JsonObject& array = JsonObject::invalid();
array.add("hello", "world");
ASSERT_EQ(0, array.size());
JsonObject& object = JsonObject::invalid();
object.set("hello", "world");
ASSERT_EQ(0, object.size());
}
TEST(JsonObject_Invalid_Tests, CreateNestedArrayFails) {
@ -33,4 +29,4 @@ TEST(JsonObject_Invalid_Tests, PrintToWritesBraces) {
char buffer[32];
JsonObject::invalid().printTo(buffer, sizeof(buffer));
ASSERT_STREQ("{}", buffer);
}
}

View File

@ -1,12 +1,12 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// 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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -16,13 +16,15 @@ class JsonObject_PrettyPrintTo_Tests : public testing::Test {
JsonObject &_object;
void outputMustBe(const char *expected) {
size_t n = _object.prettyPrintTo(buffer, sizeof(buffer));
EXPECT_STREQ(expected, buffer);
EXPECT_EQ(strlen(expected), n);
}
char buffer[256];
private:
char buffer[256];
size_t actualLen = _object.prettyPrintTo(buffer, sizeof(buffer));
size_t measuredLen = _object.measurePrettyLength();
EXPECT_STREQ(expected, buffer);
EXPECT_EQ(strlen(expected), actualLen);
EXPECT_EQ(strlen(expected), measuredLen);
}
};
TEST_F(JsonObject_PrettyPrintTo_Tests, EmptyObject) { outputMustBe("{}"); }

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -11,129 +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];
int result = object.printTo(actual, sizeof(actual));
size_t actualLen = _object.printTo(actual, sizeof(actual));
size_t measuredLen = _object.measureLength();
EXPECT_STREQ(expected, actual);
EXPECT_EQ(strlen(expected), result);
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"].set(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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -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());
}
@ -35,11 +40,11 @@ class JsonParser_Array_Tests : public testing::Test {
template <typename T>
void elementAtIndexMustBe(int index, T expected) {
EXPECT_EQ(expected, _array->at(index).as<T>());
EXPECT_EQ(expected, (*_array)[index].as<T>());
}
void elementAtIndexMustBe(int index, const char *expected) {
EXPECT_STREQ(expected, _array->at(index).as<const char *>());
EXPECT_STREQ(expected, (*_array)[index].as<const char *>());
}
DynamicJsonBuffer _jsonBuffer;
@ -139,26 +144,196 @@ TEST_F(JsonParser_Array_Tests, TwoNulls) {
secondElementMustBe(nullCharPtr);
}
TEST_F(JsonParser_Array_Tests, IncompleteNull) {
whenInputIs("[nul!]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, IncompleteTrue) {
whenInputIs("[tru!]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, IncompleteFalse) {
whenInputIs("[fals!]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, TwoStrings) {
whenInputIs("[\"hello\",\"world\"]");
TEST_F(JsonParser_Array_Tests, TwoStringsDoubleQuotes) {
whenInputIs("[ \"hello\" , \"world\" ]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, TwoStringsSingleQuotes) {
whenInputIs("[ 'hello' , 'world' ]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, TwoStringsNoQuotes) {
whenInputIs("[ hello , world ]");
parseMustSucceed();
sizeMustBe(2);
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();
}
TEST_F(JsonParser_Array_Tests, CCommentBeforeOpeningBracket) {
whenInputIs("/*COMMENT*/[\"hello\"]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CCommentAfterOpeningBracket) {
whenInputIs("[/*COMMENT*/\"hello\"]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CCommentBeforeClosingBracket) {
whenInputIs("[\"hello\"/*COMMENT*/]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CCommentAfterClosingBracket) {
whenInputIs("[\"hello\"]/*COMMENT*/");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CCommentBeforeComma) {
whenInputIs("[\"hello\"/*COMMENT*/,\"world\"]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, CCommentAfterComma) {
whenInputIs("[\"hello\",/*COMMENT*/\"world\"]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, CppCommentBeforeOpeningBracket) {
whenInputIs("//COMMENT\n[\"hello\"]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CppCommentAfterOpeningBracket) {
whenInputIs("[//COMMENT\n\"hello\"]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CppCommentBeforeClosingBracket) {
whenInputIs("[\"hello\"//COMMENT\n]");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CppCommentAfterClosingBracket) {
whenInputIs("[\"hello\"]//COMMENT\n");
parseMustSucceed();
sizeMustBe(1);
firstElementMustBe("hello");
}
TEST_F(JsonParser_Array_Tests, CppCommentBeforeComma) {
whenInputIs("[\"hello\"//COMMENT\n,\"world\"]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, CppCommentAfterComma) {
whenInputIs("[\"hello\",//COMMENT\n\"world\"]");
parseMustSucceed();
sizeMustBe(2);
firstElementMustBe("hello");
secondElementMustBe("world");
}
TEST_F(JsonParser_Array_Tests, InvalidCppComment) {
whenInputIs("[/COMMENT\n]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, InvalidComment) {
whenInputIs("[/*/\n]");
parseMustFail();
}
TEST_F(JsonParser_Array_Tests, UnfinishedCComment) {
whenInputIs("[/*COMMENT]");
parseMustFail();
}

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

View File

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
@ -21,12 +21,12 @@ class JsonParser_Object_Test : public testing::Test {
void sizeMustBe(int expected) { EXPECT_EQ(expected, _object->size()); }
void keyMustHaveValue(const char *key, const char *expected) {
EXPECT_STREQ(expected, _object->at(key).as<const char *>());
EXPECT_STREQ(expected, (*_object)[key]);
}
template <typename T>
void keyMustHaveValue(const char *key, T expected) {
EXPECT_EQ(expected, _object->at(key).as<T>());
EXPECT_EQ(expected, (*_object)[key].as<T>());
}
private:
@ -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

@ -0,0 +1,177 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <gtest/gtest.h>
#define ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson.h>
static const char* null = 0;
TEST(JsonVariant_As_Tests, DoubleAsBool) {
JsonVariant variant = 4.2;
ASSERT_TRUE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, DoubleAsCstr) {
JsonVariant variant = 4.2;
ASSERT_FALSE(variant.as<const char*>());
}
TEST(JsonVariant_As_Tests, DoubleAsString) {
JsonVariant variant = 4.2;
ASSERT_EQ(String("4.20"), variant.as<String>());
}
TEST(JsonVariant_As_Tests, DoubleAsLong) {
JsonVariant variant = 4.2;
ASSERT_EQ(4L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, DoubleZeroAsBool) {
JsonVariant variant = 0.0;
ASSERT_FALSE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, DoubleZeroAsLong) {
JsonVariant variant = 0.0;
ASSERT_EQ(0L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, FalseAsBool) {
JsonVariant variant = false;
ASSERT_FALSE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, FalseAsDouble) {
JsonVariant variant = false;
ASSERT_EQ(0.0, variant.as<double>());
}
TEST(JsonVariant_As_Tests, FalseAsLong) {
JsonVariant variant = false;
ASSERT_EQ(0L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, FalseAsString) {
JsonVariant variant = false;
ASSERT_EQ(String("0"), variant.as<String>());
}
TEST(JsonVariant_As_Tests, TrueAsBool) {
JsonVariant variant = true;
ASSERT_TRUE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, TrueAsDouble) {
JsonVariant variant = true;
ASSERT_EQ(1.0, variant.as<double>());
}
TEST(JsonVariant_As_Tests, TrueAsLong) {
JsonVariant variant = true;
ASSERT_EQ(1L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, TrueAsString) {
JsonVariant variant = true;
ASSERT_EQ(String("1"), variant.as<String>());
}
TEST(JsonVariant_As_Tests, LongAsBool) {
JsonVariant variant = 42L;
ASSERT_TRUE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, LongZeroAsBool) {
JsonVariant variant = 0L;
ASSERT_FALSE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, LongAsDouble) {
JsonVariant variant = 42L;
ASSERT_EQ(42.0, variant.as<double>());
}
TEST(JsonVariant_As_Tests, LongAsString) {
JsonVariant variant = 42L;
ASSERT_EQ(String("42"), variant.as<String>());
}
TEST(JsonVariant_As_Tests, LongZeroAsDouble) {
JsonVariant variant = 0L;
ASSERT_EQ(0.0, variant.as<double>());
}
TEST(JsonVariant_As_Tests, NullAsBool) {
JsonVariant variant = null;
ASSERT_FALSE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, NullAsDouble) {
JsonVariant variant = null;
ASSERT_EQ(0.0, variant.as<double>());
}
TEST(JsonVariant_As_Tests, NullAsLong) {
JsonVariant variant = null;
ASSERT_EQ(0L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, NullAsString) {
JsonVariant variant = null;
ASSERT_EQ(String("null"), variant.as<String>());
}
TEST(JsonVariant_As_Tests, NumberStringAsBool) {
JsonVariant variant = "42";
ASSERT_TRUE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, NumberStringAsLong) {
JsonVariant variant = "42";
ASSERT_EQ(42L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, RandomStringAsBool) {
JsonVariant variant = "hello";
ASSERT_FALSE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, RandomStringAsLong) {
JsonVariant variant = "hello";
ASSERT_EQ(0L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, TrueStringAsBool) {
JsonVariant variant = "true";
ASSERT_TRUE(variant.as<bool>());
}
TEST(JsonVariant_As_Tests, TrueStringAsLong) {
JsonVariant variant = "true";
ASSERT_EQ(1L, variant.as<long>());
}
TEST(JsonVariant_As_Tests, ObjectAsString) {
DynamicJsonBuffer buffer;
JsonObject& obj = buffer.createObject();
obj["key"] = "value";
JsonVariant variant = obj;
ASSERT_EQ(String("{\"key\":\"value\"}"), variant.as<String>());
}
TEST(JsonVariant_As_Tests, ArrayAsString) {
DynamicJsonBuffer buffer;
JsonArray& arr = buffer.createArray();
arr.add(4);
arr.add(2);
JsonVariant variant = arr;
ASSERT_EQ(String("[4,2]"), variant.as<String>());
}

View File

@ -1,12 +1,12 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// 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

@ -1,4 +1,4 @@
// Copyright Benoit Blanchon 2014
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library

Some files were not shown because too many files have changed in this diff Show More