Compare commits

...

42 Commits
v3.0 ... v3.2

Author SHA1 Message Date
7246db7691 Added a note to avoid issue #10 2014-08-04 15:12:09 +02:00
4bdbc6c1fc Updated CHANGELOG.md 2014-08-04 14:59:09 +02:00
8e6fdb20eb Added tag in filename 2014-08-04 14:56:19 +02:00
016d0d699e Added a script to create Arduino package 2014-08-04 14:47:32 +02:00
6771603a05 Simplified JsonArray tests 2014-08-04 12:18:17 +02:00
d067cf0e84 Fixed tests 2014-08-04 09:35:57 +02:00
13593d73a3 Fixed nested object in arrays bug 2014-08-04 09:30:57 +02:00
bc86ae800a Changed JsonArray tests to show the issue 2014-08-04 09:22:45 +02:00
df52dceaa1 Added tests for issue #10 2014-08-04 09:21:04 +02:00
d460b59b50 Fixed CHANGELOG.md 2014-08-03 15:54:16 +02:00
8e5ea91f8d Updated README 2014-08-03 13:48:22 +02:00
4a8b7d0cb4 Updated code size 2014-08-03 13:23:40 +02:00
96c9b5deee Updated changelog. 2014-08-03 13:18:59 +02:00
8e81b9bb26 Added JsonObjectBase::remove() 2014-08-03 13:16:35 +02:00
817cc09975 Added typedef JsonKey 2014-08-03 13:09:07 +02:00
1bc45f1fd7 Extracted method getMatchingPair() 2014-08-02 16:25:18 +02:00
d2fe9ddf49 Added JsonObjectBase::containsKey() 2014-08-02 16:11:02 +02:00
5cc06180e6 Removed JsonValue::null(), moved the instance to JsonObjectBase 2014-08-02 15:55:46 +02:00
65e8b6d405 Optimized size of JsonObjectBase indexer (-58 bytes) 2014-08-02 15:37:01 +02:00
09294cb5e6 Made EscapedString pure static 2014-08-01 15:32:05 +02:00
158f4600fb Added static EscapedString::printTo 2014-08-01 15:27:58 +02:00
0d28612507 Fixed casting JsonValue to string 2014-08-01 15:23:14 +02:00
7c99d4d63d Reduced usages of EscapedString 2014-08-01 15:22:30 +02:00
1a01800782 Test casting a JsonValue to a JsonArray 2014-08-01 15:06:31 +02:00
6384bc414a Test casting a JsonValue to a float 2014-08-01 14:58:16 +02:00
c10bcee324 Test casting a JsonValue to a double 2014-08-01 14:56:46 +02:00
028ff6676e Test casting a JsonValue to a bool 2014-08-01 14:54:34 +02:00
23b5237f74 Test casting a JsonValue to a long 2014-08-01 14:53:05 +02:00
88510705be Test casting a JsonValue to an int 2014-08-01 14:52:15 +02:00
15d3068d78 Test casting a JsonValue to a string 2014-08-01 14:47:48 +02:00
ae6beb9340 Cleaned JsonValue tests 2014-08-01 14:38:28 +02:00
c1f4128ccd Added a failng test 2014-08-01 14:35:54 +02:00
5fb6edfc91 Cleaned JsonObject unit tests 2014-08-01 14:25:55 +02:00
2771b830b7 Replace the examples with the new API 2014-07-31 20:33:12 +02:00
84aa627038 Updated changelog 2014-07-31 20:28:52 +02:00
4528b8fc95 Use operator[] in example (-68 bytes) 2014-07-31 20:16:14 +02:00
60c6f2db47 Added operator[] 2014-07-31 20:11:55 +02:00
13c386c7a3 Moved JsonValue to namespace ArduinoJson::Generator 2014-07-31 19:57:52 +02:00
7877ee1b4c Replaced set() by operator=() 2014-07-31 19:48:51 +02:00
2c29327ebd Return a JsonValue& instead of a KeyValuePair* (+40 bytes) 2014-07-31 19:42:09 +02:00
85ffb83aa6 Fixed failing test 2014-07-31 18:50:01 +02:00
1ce6661fa6 Created a failing test 2014-07-31 18:16:04 +02:00
23 changed files with 719 additions and 275 deletions

13
BuildArduinoPackage.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
ZIP="C:\Program Files\7-Zip\7z.exe"
TAG=$(git describe)
OUTPUT="ArduinoJson-$TAG.zip"
cd ..
INPUT=$(find ArduinoJson -regex ".*\.\(cpp\|h\|md\|txt\|ino\)$" -not -regex ".*Tests/.*")
rm -f $OUTPUT
"$ZIP" a $OUTPUT $INPUT

View File

@ -1,6 +1,32 @@
Arduino JSON: change log
========================
v3.2
----
* Fixed a bug when adding nested object in `JsonArray` (bug introduced in v3.1).
v3.1
----
* Calling `Generator::JsonObject::add()` twice with the same `key` now replaces the `value`
* Added `Generator::JsonObject::operator[]`, see bellow the new API
* Added `Generator::JsonObject::remove()`
Old generator API:
JsonObject<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
New generator API:
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
v3.0
----

View File

@ -30,10 +30,8 @@ static inline size_t printCharTo(char c, Print& p)
: p.write(c);
}
size_t EscapedString::printTo(Print& p) const
size_t EscapedString::printTo(const char* s, Print& p)
{
const char* s = rawString;
if (!s) return p.print("null");
size_t n = p.write('\"');

View File

@ -14,16 +14,7 @@ namespace ArduinoJson
class EscapedString
{
public:
void set(const char* s)
{
rawString = s;
}
size_t printTo(Print&) const;
private:
const char* rawString;
static size_t printTo(const char*, Print&);
};
}
}

View File

@ -22,7 +22,7 @@ namespace ArduinoJson
}
private:
Internals::JsonValue items[N];
JsonValue items[N];
};
}
}

View File

@ -14,18 +14,40 @@ namespace ArduinoJson
class JsonArrayBase : public JsonPrintable
{
public:
JsonArrayBase(Internals::JsonValue* items, int capacity)
JsonArrayBase(JsonValue* items, int capacity)
: items(items), capacity(capacity), count(0)
{
}
template<typename T>
void add(T value)
void add(const Printable& value)
{
if (count >= capacity) return;
addIfPossible<const Printable&>(value);
}
items[count++].set(value);
void add(bool value)
{
addIfPossible<bool>(value);
}
void add(int value)
{
addIfPossible<long>(value);
}
void add(long value)
{
addIfPossible<long>(value);
}
void add(double value)
{
addIfPossible<double>(value);
}
void add(const char* value)
{
addIfPossible<const char*>(value);
}
template<int DIGITS>
@ -33,7 +55,7 @@ namespace ArduinoJson
{
if (count >= capacity) return;
Internals::JsonValue& v = items[count++];
JsonValue& v = items[count++];
v.set<DIGITS>(value);
}
@ -42,8 +64,15 @@ namespace ArduinoJson
using JsonPrintable::printTo;
private:
Internals::JsonValue* items;
JsonValue* items;
int capacity, count;
template<typename T>
void addIfPossible(T value)
{
if (count < capacity)
items[count++] = value;
}
};
}
}

View File

@ -4,8 +4,12 @@
*/
#include "JsonObjectBase.h"
#include <string.h> // for strcmp
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
JsonValue JsonObjectBase::nullValue;
size_t JsonObjectBase::printTo(Print& p) const
{
@ -18,7 +22,7 @@ size_t JsonObjectBase::printTo(Print& p) const
const KeyValuePair* current = items;
for (int i = count; i > 0; i--)
{
n += current->key.printTo(p);
n += EscapedString::printTo(current->key, p);
n += p.write(':');
n += current->value.printTo(p);
@ -33,4 +37,56 @@ size_t JsonObjectBase::printTo(Print& p) const
n += p.write('}');
return n;
}
JsonObjectBase::KeyValuePair* JsonObjectBase::getMatchingPair(JsonKey key) const
{
KeyValuePair* p = items;
for (int i = count; i > 0; --i)
{
if (!strcmp(p->key, key))
return p;
p++;
}
return 0;
}
JsonValue& JsonObjectBase::operator[](JsonKey key)
{
KeyValuePair* match = getMatchingPair(key);
if (match)
return match->value;
JsonValue* value;
if (count < capacity)
{
items[count].key = key;
value = &items[count].value;
count++;
}
else
{
value = &nullValue;
}
value->reset();
return *value;
}
bool JsonObjectBase::containsKey(JsonKey key) const
{
return getMatchingPair(key) != 0;
}
void JsonObjectBase::remove(JsonKey key)
{
KeyValuePair* match = getMatchingPair(key);
if (match == 0) return;
*match = items[--count];
}

View File

@ -12,28 +12,25 @@ namespace ArduinoJson
{
namespace Generator
{
typedef const char* JsonKey;
class JsonObjectBase : public JsonPrintable
{
public:
JsonValue& operator[](JsonKey);
bool containsKey(JsonKey) const;
void remove(JsonKey key);
template<typename T>
void add(const char* key, T value)
void add(JsonKey key, T value)
{
if (count >= capacity) return;
items[count].key.set(key);
items[count].value.set(value);
count++;
operator[](key) = value;
}
template<int DIGITS>
void add(const char* key, double value)
void add(JsonKey key, double value)
{
if (count >= capacity) return;
items[count].key.set(key);
items[count].value.set<DIGITS>(value);
count++;
operator[](key).set<DIGITS>(value);
}
using JsonPrintable::printTo;
@ -44,8 +41,8 @@ namespace ArduinoJson
struct KeyValuePair
{
Internals::EscapedString key;
Internals::JsonValue value;
JsonKey key;
JsonValue value;
};
JsonObjectBase(KeyValuePair* items, int capacity)
@ -56,6 +53,9 @@ namespace ArduinoJson
private:
KeyValuePair* items;
int capacity, count;
static JsonValue nullValue;
KeyValuePair* getMatchingPair(JsonKey key) const;
};
}
}

View File

@ -6,6 +6,7 @@
#include "EscapedString.h"
#include "JsonValue.h"
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
size_t JsonValue::printBoolTo(const Content& c, Print& p)
@ -28,5 +29,5 @@ size_t JsonValue::printPrintableTo(const Content& c, Print& p)
size_t JsonValue::printStringTo(const Content& c, Print& p)
{
return c.asString.printTo(p);
return EscapedString::printTo(c.asString, p);
}

View File

@ -11,43 +11,43 @@
namespace ArduinoJson
{
namespace Internals
namespace Generator
{
class JsonValue
{
public:
void set(bool value)
void operator=(bool value)
{
printToImpl = &printBoolTo;
content.asBool = value;
}
void set(long value)
void operator=(long value)
{
printToImpl = &printLongTo;
content.asLong = value;
}
void set(int value)
void operator=(int value)
{
printToImpl = &printLongTo;
content.asLong = value;
}
void set(Printable& value)
void operator=(const Printable& value)
{
printToImpl = &printPrintableTo;
content.asPrintable = &value;
}
void set(const char* value)
void operator=(const char* value)
{
printToImpl = &printStringTo;
content.asString.set(value);
content.asString = value;
}
void set(double value)
void operator=(double value)
{
set<2>(value);
}
@ -55,29 +55,70 @@ namespace ArduinoJson
template <int DIGITS>
void set(double value)
{
printToImpl = &printDoubleTo<DIGITS>;
printToImpl = &printDoubleTo < DIGITS > ;
content.asDouble = value;
}
operator bool()
{
return content.asBool;
}
operator const char*()
{
return content.asString;
}
operator double()
{
return content.asDouble;
}
operator float()
{
return (float)content.asDouble;
}
operator int()
{
return content.asLong;
}
operator long()
{
return content.asLong;
}
operator const Printable&()
{
return *content.asPrintable;
}
size_t printTo(Print& p) const
{
// handmade polymorphism
return printToImpl(content, p);
}
void reset()
{
content.asDouble = 0;
printToImpl = printStringTo;
}
private:
union Content
{
bool asBool;
long asLong;
Printable* asPrintable;
EscapedString asString;
double asDouble;
bool asBool;
double asDouble;
long asLong;
const Printable* asPrintable;
const char* asString;
};
Content content;
size_t(* printToImpl)(const Content&, Print&);
size_t(*printToImpl)(const Content&, Print&);
static size_t printBoolTo(const Content&, Print&);
static size_t printLongTo(const Content&, Print&);

View File

@ -1,9 +1,9 @@
Arduino JSON library - Generator
================================
This library is a simple JSON encoder for embedded systems.
*An elegant and efficient JSON encoder for embedded systems.*
It's design to be very lightweight, works without any allocation on the heap (no malloc) and supports nested objects.
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project.
@ -11,10 +11,10 @@ It has been written with Arduino in mind, but it isn't linked to Arduino librari
Features
--------
* Supports nested objects
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Small footprint
* Supports nested objects
* Implements Arduino's `Printable interface
* MIT License
@ -23,13 +23,13 @@ Example
-------
JsonArray<2> array;
array.add<6>(48.756080);
array.add<6>(2.302038);
array.add<6>(48.756080); // <6> specifies the number of digits in the output
array.add<6>(2.302038); // (the default is 2)
JsonObject<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
Serial.print(root); // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
@ -80,7 +80,7 @@ Then you can add strings, integer, booleans, etc:
array.add(42);
array.add(true);
There are two syntaxes for the floating point values:
There are two syntaxes for floating point values:
array.add<4>(3.1415); // 4 digits: "3.1415"
array.add(3.14); // 2 digits: "3.14"
@ -101,6 +101,33 @@ or
JsonObject<8> nestedObject;
array.add(nestedObject);
> ##### CAUTION! Nested objects must be in memory
> Calling `add()` makes the `JsonArray` store a pointer to the nested object.
> This is designed to avoid memory duplication.
> But it can only work if the object is in memory when `printTo()` is executed.
> For instance, don't do this:
>
> void addNestedObject()
> {
> JsonObject<2> nestedObject;
> // ...
> array.add(nestedObject); // <- DON'T !!
>
> // array now contains a pointer to a local variable that will be
> // discarded as soon as the function exits
> }
>
> For the same reason, don't do this either:
>
> for( int i=0; i<100; i++)
> {
> JsonObject<2> nestedObject;
> // ...
> array.add(nestedObject); // <- DON'T !!
> }
> // array now contains 100 pointers to the same a local variable
> // that is out of the scope anyway
#### JSON Object
You create a JSON object (ie hash-table/dictionary) with the following line:
@ -111,24 +138,29 @@ Like with the array class, there is a template parameter that gives the capacity
Then you can add strings, integer, booleans, etc:
object.add("key1", "bazinga!");
object.add("key2", 42);
object.add("key3", true);
object["key1"] = "bazinga!";
object["key2"] = 42;
object["key3"] = true;
As for the arrays, there are two syntaxes for the floating point values:
array.add<4>("key4", 3.1415); // 4 digits: "3.1415"
array.add("key5", 3.14); // 2 digits: "3.14"
object["key4"].set<4>(3.1415); // 4 digits "3.1415"
object["key5"] = 3.1415; // default: 2 digits "3.14"
Finally you can add nested objects:
JsonArray<8> nestedArray;
object.add("key6", nestedArray);
object["key6"] = nestedArray;
or
JsonObject<8> nestedObject;
object.add("key7", nestedObject);
object["key7"] = nestedObject;
> ##### Other JsonObject functions
> * `object.add(key, value)` is a synonym for `object[key] = value`
> * `object.containsKey(key)` returns `true` is the `key` is present in `object`
> * `object.remove(key)` removes the `value` associated with `key`
### 4. Get the JSON string
@ -177,15 +209,20 @@ This table is for an 8-bit Arduino, types would be bigger on a 32-bit processor.
Code size
---------
The following values has been obtained with Arduino IDE 1.0.5, targeting an Arduino Duelmilanove with an ATmega 328.
### Minimum setup
| Function | Size |
| ---------------------------- | ---- |
| `JsonObjectBase::printTo()` | 222 |
| `EscapedString::printTo()` | 202 |
| `JsonArrayBase::printTo()` | 164 |
| `Print::print(char const*)` | 146 |
| `JsonValue::printStringTo()` | 6 |
| Function | Size |
| ----------------------------------- | ---- |
| `JsonObjectBase::printTo()` | 234 |
| `EscapedString::printTo()` | 196 |
| `JsonArrayBase::printTo()` | 164 |
| `Print::print(char const*)` | 146 |
| `JsonObjectBase::operator[]` | 114 |
| `JsonObjectBase::getMatchingPair()` | 72 |
| `JsonValue::printPrintableTo()` | 40 |
| `JsonValue::printStringTo()` | 12 |
### Additional space for integers

View File

@ -16,8 +16,7 @@ namespace JsonGeneratorTests
{
char buffer[1024];
size_t returnValue;
EscapedString escapedString;
public:
TEST_METHOD(Null)
@ -83,9 +82,8 @@ namespace JsonGeneratorTests
private:
void whenInputIs(const char* input)
{
StringBuilder sb(buffer, sizeof(buffer));
escapedString.set(input);
returnValue = escapedString.printTo(sb);
StringBuilder sb(buffer, sizeof(buffer));
returnValue = EscapedString::printTo(input, sb);
}
void outputMustBe(const char* expected)

View File

@ -0,0 +1,73 @@
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace ArduinoJson::Generator;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace JsonGeneratorTests
{
TEST_CLASS(Issue10)
{
struct Person {
int id;
char name[32];
};
Person persons[2];
public:
TEST_METHOD_INITIALIZE(Initialize)
{
Person boss;
boss.id = 1;
strcpy(boss.name, "Jeff");
Person employee;
employee.id = 2;
strcpy(employee.name, "John");
persons[0] = boss;
persons[1] = employee;
}
TEST_METHOD(WrongWayToAddObjectInAnArray)
{
JsonArray<2> json;
for (int i = 0; i < 2; i++)
{
JsonObject<2> object;
object["id"] = persons[i].id;
object["name"] = persons[i].name;
json.add(object); // <- Adding a reference to a temporary variable
}
char buffer[256];
json.printTo(buffer, sizeof(buffer));
// the same values are repeated, that's normal
Assert::AreEqual("[{\"id\":2,\"name\":\"John\"},{\"id\":2,\"name\":\"John\"}]", buffer);
}
TEST_METHOD(RightWayToAddObjectInAnArray)
{
JsonArray<2> json;
JsonObject<2> object[2];
for (int i = 0; i < 2; i++)
{
object[i]["id"] = persons[i].id;
object[i]["name"] = persons[i].name;
json.add(object[i]);
}
char buffer[256];
json.printTo(buffer, sizeof(buffer));
Assert::AreEqual("[{\"id\":1,\"name\":\"Jeff\"},{\"id\":2,\"name\":\"John\"}]", buffer);
}
};
}

View File

@ -14,7 +14,7 @@ namespace JsonGeneratorTests
{
TEST_CLASS(JsonArrayTests)
{
JsonArray<2> arr;
JsonArray<2> array;
char buffer[256];
public:
@ -26,111 +26,117 @@ namespace JsonGeneratorTests
TEST_METHOD(Null)
{
add((char*)0);
array.add((char*) 0);
outputMustBe("[null]");
}
TEST_METHOD(OneString)
{
add("hello");
array.add("hello");
outputMustBe("[\"hello\"]");
}
TEST_METHOD(TwoStrings)
{
add("hello");
add("world");
array.add("hello");
array.add("world");
outputMustBe("[\"hello\",\"world\"]");
}
TEST_METHOD(OneStringOverCapacity)
{
add("hello");
add("world");
add("lost");
array.add("hello");
array.add("world");
array.add("lost");
outputMustBe("[\"hello\",\"world\"]");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
add(3.14159265358979323846);
array.add(3.14159265358979323846);
outputMustBe("[3.14]");
}
TEST_METHOD(OneDoubleFourDigits)
{
add<4>(3.14159265358979323846);
array.add<4>(3.14159265358979323846);
outputMustBe("[3.1416]");
}
TEST_METHOD(OneInteger)
{
add(1);
array.add(1);
outputMustBe("[1]");
}
TEST_METHOD(TwoIntegers)
{
add(1);
add(2);
array.add(1);
array.add(2);
outputMustBe("[1,2]");
}
TEST_METHOD(OneIntegerOverCapacity)
{
add(1);
add(2);
add(3);
array.add(1);
array.add(2);
array.add(3);
outputMustBe("[1,2]");
}
TEST_METHOD(OneTrue)
{
add(true);
array.add(true);
outputMustBe("[true]");
}
TEST_METHOD(OneFalse)
{
add(false);
array.add(false);
outputMustBe("[false]");
}
TEST_METHOD(TwoBooleans)
{
add(false);
add(true);
array.add(false);
array.add(true);
outputMustBe("[false,true]");
}
TEST_METHOD(OneBooleanOverCapacity)
{
add(false);
add(true);
add(false);
array.add(false);
array.add(true);
array.add(false);
outputMustBe("[false,true]");
}
TEST_METHOD(OneEmptyNestedArray)
{
addNested(JsonArray<1>());
JsonArray<1> nestedArray;
array.add(nestedArray);
outputMustBe("[[]]");
}
TEST_METHOD(OneEmptyNestedHash)
{
addNested(JsonHashTable<1>());
JsonObject<1> nestedObject;
array.add(nestedObject);
outputMustBe("[{}]");
}
@ -139,33 +145,16 @@ namespace JsonGeneratorTests
JsonArray<1> nestedArray;
nestedArray.add(1);
addNested(nestedArray);
array.add(nestedArray);
outputMustBe("[[1]]");
}
private:
void addNested(Printable& value)
{
arr.add<Printable&>(value);
}
template<typename T>
void add(T value)
{
arr.add(value);
}
template<int DIGITS>
void add(double value)
{
arr.add<DIGITS>(value);
}
void outputMustBe(const char* expected)
{
size_t n = arr.printTo(buffer, sizeof(buffer));
size_t n = array.printTo(buffer, sizeof(buffer));
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), n);
}

View File

@ -85,9 +85,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="EscapedStringTests.cpp" />
<ClCompile Include="Issue10.cpp" />
<ClCompile Include="JsonArrayTests.cpp" />
<ClCompile Include="JsonHashTableTests.cpp" />
<ClCompile Include="JsonValueTests.cpp" />
<ClCompile Include="JsonObject_Indexer_Tests.cpp" />
<ClCompile Include="JsonObject_PrintTo_Tests.cpp" />
<ClCompile Include="JsonValue_Cast_Tests.cpp" />
<ClCompile Include="JsonValue_PrintTo_Tests.cpp" />
<ClCompile Include="StringBuilderTests.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -18,17 +18,26 @@
<ClCompile Include="JsonArrayTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonHashTableTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValueTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StringBuilderTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EscapedStringTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObject_PrintTo_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObject_Indexer_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValue_PrintTo_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValue_Cast_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Issue10.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,124 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonHashTableTests)
{
JsonHashTable<2> hash;
char buffer[256];
public:
TEST_METHOD(Empty)
{
outputMustBe("{}");
}
TEST_METHOD(OneString)
{
add("key", "value");
outputMustBe("{\"key\":\"value\"}");
}
TEST_METHOD(TwoStrings)
{
add("key1", "value1");
add("key2", "value2");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(OneStringOverCapacity)
{
add("key1", "value1");
add("key2", "value2");
add("key3", "value3");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(OneInteger)
{
add("key", 1);
outputMustBe("{\"key\":1}");
}
TEST_METHOD(OneDoubleFourDigits)
{
add<4>("key", 3.14159265358979323846);
outputMustBe("{\"key\":3.1416}");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
add("key", 3.14159265358979323846);
outputMustBe("{\"key\":3.14}");
}
TEST_METHOD(OneNull)
{
add("key", (char*) 0);
outputMustBe("{\"key\":null}");
}
TEST_METHOD(OneTrue)
{
add("key", true);
outputMustBe("{\"key\":true}");
}
TEST_METHOD(OneFalse)
{
add("key", false);
outputMustBe("{\"key\":false}");
}
TEST_METHOD(OneEmptyNestedArray)
{
addNested("key", JsonArray<1>());
outputMustBe("{\"key\":[]}");
}
TEST_METHOD(OneEmptyNestedHash)
{
addNested("key", JsonHashTable<1>());
outputMustBe("{\"key\":{}}");
}
private:
void addNested(const char* key, Printable& value)
{
hash.add<Printable&>(key, value);
}
template<typename T>
void add(const char* key, T value)
{
hash.add(key, value);
}
template<int DIGITS>
void add(const char* key, double value)
{
hash.add<DIGITS>(key, value);
}
void outputMustBe(const char* expected)
{
size_t actual = hash.printTo(buffer, sizeof(buffer));
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), actual);
}
};
}

View File

@ -0,0 +1,73 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonObject_Indexer_Tests)
{
JsonObject<2> object;
public:
TEST_METHOD(Empty)
{
mustNotContain("key");
}
TEST_METHOD(TwoStrings)
{
object["key1"] = "value1";
object["key2"] = "value2";
mustContain("key1", "value1");
mustContain("key2", "value2");
}
TEST_METHOD(RemoveFirst)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key1");
mustNotContain("key1");
mustContain("key2", "value2");
}
TEST_METHOD(RemoveLast)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key2");
mustContain("key1", "value1");
mustNotContain("key2");
}
private:
void mustContain(const char* key, const char* expected)
{
Assert::IsTrue(object.containsKey(key));
const char* actual = object[key];
Assert::AreEqual(expected, actual);
}
void mustNotContain(const char* key)
{
Assert::IsFalse(object.containsKey(key));
const char* actual = object[key];
Assert::IsNull(actual);
}
};
}

View File

@ -0,0 +1,152 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonObject_PrintTo_Tests)
{
JsonObject<2> object;
public:
TEST_METHOD(Empty)
{
outputMustBe("{}");
}
TEST_METHOD(OneString)
{
object["key"] = "value";
outputMustBe("{\"key\":\"value\"}");
}
TEST_METHOD(TwoStrings)
{
object["key1"] = "value1";
object["key2"] = "value2";
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(RemoveFirst)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key1");
outputMustBe("{\"key2\":\"value2\"}");
}
TEST_METHOD(RemoveLast)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key2");
outputMustBe("{\"key1\":\"value1\"}");
}
TEST_METHOD(RemoveUnexistingKey)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key3");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(ReplaceExistingKey)
{
object["key"] = "value1";
object["key"] = "value2";
outputMustBe("{\"key\":\"value2\"}");
}
TEST_METHOD(OneStringOverCapacity)
{
object["key1"] = "value1";
object["key2"] = "value2";
object["key3"] = "value3";
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(OneInteger)
{
object["key"] = 1;
outputMustBe("{\"key\":1}");
}
TEST_METHOD(OneDoubleFourDigits)
{
object["key"].set<4>(3.14159265358979323846);
outputMustBe("{\"key\":3.1416}");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
object["key"] = 3.14159265358979323846;
outputMustBe("{\"key\":3.14}");
}
TEST_METHOD(OneNull)
{
object["key"] = (char*) 0;
outputMustBe("{\"key\":null}");
}
TEST_METHOD(OneTrue)
{
object["key"] = true;
outputMustBe("{\"key\":true}");
}
TEST_METHOD(OneFalse)
{
object["key"] = false;
outputMustBe("{\"key\":false}");
}
TEST_METHOD(OneEmptyNestedArray)
{
auto nestedArray = JsonArray<1>();
object["key"] = nestedArray;
outputMustBe("{\"key\":[]}");
}
TEST_METHOD(OneEmptyNestedObject)
{
auto nestedObject = JsonObject<1>();
object["key"] = nestedObject;
outputMustBe("{\"key\":{}}");
}
private:
void outputMustBe(const char* expected)
{
char buffer[256];
size_t result;
result = object.printTo(buffer, sizeof(buffer));
Assert::AreEqual(strlen(expected), result);
Assert::AreEqual(expected, buffer);
}
};
}

View File

@ -0,0 +1,78 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "StringBuilder.h"
#include "JsonValue.h"
#include "JsonArray.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonValue_Cast_Tests)
{
JsonValue value;
public:
TEST_METHOD(Bool)
{
setValueAndCheckCast(true);
setValueAndCheckCast(false);
}
TEST_METHOD(Double)
{
setValueAndCheckCast(3.14156);
}
TEST_METHOD(Float)
{
setValueAndCheckCast(3.14f);
}
TEST_METHOD(Integer)
{
setValueAndCheckCast(42);
}
TEST_METHOD(Long)
{
setValueAndCheckCast(42L);
}
TEST_METHOD(Array)
{
JsonArray<2> array;
setValueAndCheckCast(array);
}
TEST_METHOD(String)
{
setValueAndCheckCast("hello");
}
private:
template<typename T>
void setValueAndCheckCast(T expected)
{
value = expected;
T actual = value;
Assert::AreEqual(expected, actual);
}
template<int N>
void setValueAndCheckCast(JsonArray<N>& expected)
{
value = expected;
const Printable& actual = value;
Assert::AreEqual((void*) &expected, (void*) &actual);
}
};
}

View File

@ -8,11 +8,12 @@
#include "JsonValue.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonValueTests)
TEST_CLASS(JsonValue_PrintTo_Tests)
{
char buffer[1024];
size_t returnValue;
@ -21,62 +22,62 @@ namespace JsonGeneratorTests
TEST_METHOD(String)
{
whenInputIs("hello");
setValueTo("hello");
outputMustBe("\"hello\"");
}
TEST_METHOD(Float)
{
whenInputIs(3.1415f);
setValueTo(3.1415f);
outputMustBe("3.14");
}
TEST_METHOD(DoubleZeroDigits)
{
whenInputIs<0>(3.14159265358979323846);
setValueTo<0>(3.14159265358979323846);
outputMustBe("3");
}
TEST_METHOD(DoubleOneDigit)
{
whenInputIs<1>(3.14159265358979323846);
setValueTo<1>(3.14159265358979323846);
outputMustBe("3.1");
}
TEST_METHOD(DoubleTwoDigits)
{
whenInputIs<2>(3.14159265358979323846);
setValueTo<2>(3.14159265358979323846);
outputMustBe("3.14");
}
TEST_METHOD(Integer)
{
whenInputIs(314);
setValueTo(314);
outputMustBe("314");
}
TEST_METHOD(Char)
{
whenInputIs('A');
setValueTo('A');
outputMustBe("65");
}
TEST_METHOD(Short)
{
whenInputIs((short)314);
setValueTo((short)314);
outputMustBe("314");
}
TEST_METHOD(Long)
{
whenInputIs(314159265L);
setValueTo(314159265L);
outputMustBe("314159265");
}
private:
template<int DIGITS>
void whenInputIs(double value)
void setValueTo(double value)
{
StringBuilder sb(buffer, sizeof(buffer));
JsonValue jsonValue;
@ -85,11 +86,11 @@ namespace JsonGeneratorTests
}
template<typename T>
void whenInputIs(T value)
void setValueTo(T value)
{
StringBuilder sb(buffer, sizeof(buffer));
JsonValue jsonValue;
jsonValue.set(value);
jsonValue = value;
returnValue = jsonValue.printTo(sb);
}

View File

@ -3,7 +3,7 @@ Arduino JSON library
*An elegant and efficient JSON library for embedded systems.*
It's design to be very lightweight, works without any allocation on the heap (no malloc).
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project.
@ -22,9 +22,9 @@ Feature comparison
| Library | Memory allocation | Nested objects | Parser size | Encoder size |
| ------------ | ----------------- | -------------- | ----------- | ------------- |
| Arduino JSON | static | yes | 2642 Bytes | 628 bytes |
| Arduino JSON | static | yes | 2642 Bytes | 862 bytes |
| json-arduino | dynamic | no | 3348 (+27%) | not supported |
| aJson | dynamic | yes | 5088 (+93%) | 4678 (+640%) |
| aJson | dynamic | yes | 5088 (+93%) | 4678 (+540%) |
"Parser size" was measured with a program parsing `{"sensor":"outdoor","value":25.6}`.
For each library, I wrote a program that extracts a string and a float. I subtracted the size of a program doing the same without any JSON parsing involved. [Source files are here](https://gist.github.com/bblanchon/e8ba914a7109f3642c0f).

View File

@ -16,9 +16,9 @@ void setup()
array.add<6>(2.302038); // if not specified, 2 digits are printed
JsonObject<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
Serial.print(root); // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
}