Compare commits

...

4 Commits

78 changed files with 1131 additions and 727 deletions

View File

@ -1,6 +1,35 @@
ArduinoJson: change log
=======================
v6.2.0-beta
-----------
* Disabled lazy number deserialization (issue #772)
* Improved float serialization when `-fsingle-precision-constant` is used
* Renamed function `RawJson()` to `serialized()`
* `serializeMsgPack()` now supports values marked with `serialized()`
> ### BREAKING CHANGES
>
> #### Non quoted strings
>
> Non quoted strings are now forbidden in values, but they are still allowed in keys.
> For example, `{key:"value"}` is accepted, but `{key:value}` is not.
>
> #### Preformatted values
>
> Old code:
>
> ```c++
> object["values"] = RawJson("[1,2,3,4]");
> ```
>
> New code:
>
> ```c++
> object["values"] = serialized("[1,2,3,4]");
> ```
v6.1.0-beta
-----------
@ -15,7 +44,7 @@ v6.1.0-beta
> JsonObject& obj = doc.to<JsonObject>();
> JsonArray& arr = obj.createNestedArray("key");
> if (!arr.success()) {
> Serial.println("No enough memory");
> Serial.println("Not enough memory");
> return;
> }
> ```
@ -26,7 +55,7 @@ v6.1.0-beta
> JsonObject obj = doc.to<JsonObject>();
> JsonArray arr = obj.createNestedArray("key");
> if (arr.isNull()) {
> Serial.println("No enough memory");
> Serial.println("Not enough memory");
> return;
> }
> ```

View File

@ -37,8 +37,9 @@ void setup() {
// JsonBuffer.
obj["sensor"] = F("gps");
// It works with RawJson too:
obj["sensor"] = RawJson(F("\"gps\""));
// It works with serialized() too:
obj["sensor"] = serialized(F("\"gps\""));
obj["sensor"] = serialized(F("\xA3gps"), 3);
// You can compare the content of a JsonVariant to a Flash String
if (obj["sensor"] == F("gps")) {

View File

@ -41,8 +41,8 @@ void setup() {
// WARNING: the content of the String will be duplicated in the JsonBuffer.
obj["sensor"] = sensor;
// It works with RawJson too:
obj["sensor"] = RawJson(sensor);
// It works with serialized() too:
obj["sensor"] = serialized(sensor);
// You can also concatenate strings
// WARNING: the content of the String will be duplicated in the JsonBuffer.

View File

@ -7,7 +7,7 @@
"type": "git",
"url": "https://github.com/bblanchon/ArduinoJson.git"
},
"version": "6.1.0-beta",
"version": "6.2.0-beta",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"

View File

@ -1,5 +1,5 @@
name=ArduinoJson
version=6.1.0-beta
version=6.2.0-beta
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=An efficient and elegant JSON library for Arduino.

View File

@ -18,9 +18,13 @@ struct JsonObjectData;
union JsonVariantContent {
JsonFloat asFloat; // used for double and float
JsonUInt asInteger; // used for bool, char, short, int and longs
const char* asString; // asString can be null
JsonArrayData* asArray; // asArray cannot be null
JsonObjectData* asObject; // asObject cannot be null
const char* asString; // asString can be null
struct {
const char* data;
size_t size;
} asRaw;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -7,7 +7,7 @@
#include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Strings/StringTraits.hpp"
#include "../Strings/StringTypes.hpp"
namespace ArduinoJson {
namespace Internals {
@ -21,30 +21,31 @@ struct ValueSaver {
}
};
template <typename Source>
// We duplicate all strings except const char*
template <typename TString>
struct ValueSaver<
Source, typename enable_if<StringTraits<Source>::should_duplicate>::type> {
TString, typename enable_if<IsString<TString>::value &&
!is_same<const char*, TString>::value>::type> {
template <typename Destination>
static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
if (!StringTraits<Source>::is_null(source)) {
typename StringTraits<Source>::duplicate_t dup =
StringTraits<Source>::duplicate(source, buffer);
if (!dup) return false;
dest = dup;
} else {
dest = reinterpret_cast<const char*>(0);
}
static bool save(JsonBuffer* buffer, Destination& dest, TString source) {
const char* dup = makeString(source).save(buffer);
if (!dup) return false;
dest = dup;
return true;
}
};
// const char*, const signed char*, const unsigned char*
template <typename Char>
// We duplicate all SerializedValue<T> except SerializedValue<const char*>
template <typename TString>
struct ValueSaver<
Char*, typename enable_if<!StringTraits<Char*>::should_duplicate>::type> {
const SerializedValue<TString>&,
typename enable_if<!is_same<const char*, TString>::value>::type> {
template <typename Destination>
static bool save(JsonBuffer*, Destination& dest, Char* source) {
dest = reinterpret_cast<const char*>(source);
static bool save(JsonBuffer* buffer, Destination& dest,
const SerializedValue<TString>& source) {
const char* dup = makeString(source.data(), source.size()).save(buffer);
if (!dup) return false;
dest = SerializedValue<const char*>(dup, source.size());
return true;
}
};

View File

@ -19,19 +19,22 @@ class IndentedPrint {
isNewLine = true;
}
size_t print(char c) {
size_t write(uint8_t c) {
size_t n = 0;
if (isNewLine) n += writeTabs();
n += sink->print(c);
n += sink->write(c);
isNewLine = c == '\n';
return n;
}
size_t print(const char *s) {
size_t write(const uint8_t *s, size_t n) {
// TODO: optimize
size_t n = 0;
while (*s) n += print(*s++);
return n;
size_t bytesWritten = 0;
while (n > 0) {
bytesWritten += write(*s++);
n--;
}
return bytesWritten;
}
// Adds one level of indentation
@ -57,7 +60,7 @@ class IndentedPrint {
size_t writeTabs() {
size_t n = 0;
for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
return n;
}

View File

@ -121,7 +121,7 @@ class JsonDeserializer {
for (;;) {
// Parse key
const char *key;
err = parseString(&key);
err = parseKey(&key);
if (err) return err;
// Skip spaces
@ -152,48 +152,69 @@ class JsonDeserializer {
}
DeserializationError parseValue(JsonVariant &variant) {
bool hasQuotes = isQuote(current());
const char *value;
DeserializationError error = parseString(&value);
if (error) return error;
if (hasQuotes) {
variant = value;
if (isQuote(current())) {
return parseStringValue(variant);
} else {
variant = RawJson(value);
return parseNumericValue(variant);
}
}
DeserializationError parseKey(const char **key) {
if (isQuote(current())) {
return parseQuotedString(key);
} else {
return parseNonQuotedString(key);
}
}
DeserializationError parseStringValue(JsonVariant &variant) {
const char *value;
DeserializationError err = parseQuotedString(&value);
if (err) return err;
variant = value;
return DeserializationError::Ok;
}
DeserializationError parseString(const char **result) {
DeserializationError parseQuotedString(const char **result) {
typename remove_reference<TStringStorage>::type::String str =
_stringStorage.startString();
char stopChar = current();
move();
for (;;) {
char c = current();
move();
if (c == stopChar) break;
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == 'u') return DeserializationError::NotSupported;
// replace char
c = EscapeSequence::unescapeChar(c);
if (c == '\0') return DeserializationError::InvalidInput;
move();
}
str.append(c);
}
*result = str.c_str();
if (*result == NULL) return DeserializationError::NoMemory;
return DeserializationError::Ok;
}
DeserializationError parseNonQuotedString(const char **result) {
typename remove_reference<TStringStorage>::type::String str =
_stringStorage.startString();
char c = current();
if (c == '\0') return DeserializationError::IncompleteInput;
if (isQuote(c)) { // quotes
move();
char stopChar = c;
for (;;) {
c = current();
move();
if (c == stopChar) break;
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == 'u') return DeserializationError::NotSupported;
// replace char
c = EscapeSequence::unescapeChar(c);
if (c == '\0') return DeserializationError::InvalidInput;
move();
}
str.append(c);
}
} else if (canBeInNonQuotedString(c)) { // no quotes
if (canBeInNonQuotedString(c)) { // no quotes
do {
move();
str.append(c);
@ -208,6 +229,34 @@ class JsonDeserializer {
return DeserializationError::Ok;
}
DeserializationError parseNumericValue(JsonVariant &result) {
char buffer[64];
uint8_t n = 0;
char c = current();
while (canBeInNonQuotedString(c) && n < 63) {
move();
buffer[n++] = c;
c = current();
}
buffer[n] = 0;
if (isInteger(buffer)) {
result = parseInteger<JsonInteger>(buffer);
} else if (isFloat(buffer)) {
result = parseFloat<JsonFloat>(buffer);
} else if (!strcmp(buffer, "true")) {
result = true;
} else if (!strcmp(buffer, "false")) {
result = false;
} else if (!strcmp(buffer, "null")) {
result = static_cast<const char *>(0);
} else {
return DeserializationError::InvalidInput;
}
return DeserializationError::Ok;
}
static inline bool isBetween(char c, char min, char max) {
return min <= c && c <= max;
}
@ -286,7 +335,7 @@ class JsonDeserializer {
uint8_t _nestingLimit;
char _current;
bool _loaded;
};
}; // namespace Internals
} // namespace Internals
template <typename TDocument, typename TInput>

View File

@ -11,10 +11,10 @@
namespace ArduinoJson {
namespace Internals {
template <typename TPrint>
template <typename TWriter>
class JsonSerializer {
public:
JsonSerializer(TPrint &destination) : _writer(destination) {}
JsonSerializer(TWriter &writer) : _writer(writer) {}
void acceptFloat(JsonFloat value) {
_writer.writeFloat(value);
@ -58,8 +58,9 @@ class JsonSerializer {
_writer.writeString(value);
}
void acceptRawJson(const char *value) {
_writer.writeRaw(value);
void acceptRawJson(const char *data, size_t n) {
// TODO
for (size_t i = 0; i < n; i++) _writer.writeRaw(data[i]);
}
void acceptNegativeInteger(JsonUInt value) {
@ -84,7 +85,7 @@ class JsonSerializer {
}
private:
JsonWriter<TPrint> _writer;
JsonWriter<TWriter> _writer;
};
} // namespace Internals

View File

@ -5,6 +5,7 @@
#pragma once
#include <stdint.h>
#include <string.h> // for strlen
#include "../Data/JsonInteger.hpp"
#include "../Numbers/FloatParts.hpp"
#include "../Polyfills/attributes.hpp"
@ -13,12 +14,12 @@
namespace ArduinoJson {
namespace Internals {
template <typename Print>
template <typename TWriter>
class JsonWriter {
public:
explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
explicit JsonWriter(TWriter &writer) : _writer(writer), _length(0) {}
// Returns the number of bytes sent to the Print implementation.
// Returns the number of bytes sent to the TWriter implementation.
size_t bytesWritten() const {
return _length;
}
@ -45,7 +46,10 @@ class JsonWriter {
}
void writeBoolean(bool value) {
writeRaw(value ? "true" : "false");
if (value)
writeRaw("true");
else
writeRaw("false");
}
void writeString(const char *value) {
@ -98,45 +102,53 @@ class JsonWriter {
template <typename UInt>
void writeInteger(UInt value) {
char buffer[22];
char *end = buffer + sizeof(buffer) - 1;
char *ptr = end;
char *end = buffer + sizeof(buffer);
char *begin = end;
*ptr = 0;
// write the string in reverse order
do {
*--ptr = char(value % 10 + '0');
*--begin = char(value % 10 + '0');
value = UInt(value / 10);
} while (value);
writeRaw(ptr);
// and dump it in the right order
writeRaw(begin, end);
}
void writeDecimals(uint32_t value, int8_t width) {
// buffer should be big enough for all digits, the dot and the null
// terminator
// buffer should be big enough for all digits and the dot
char buffer[16];
char *ptr = buffer + sizeof(buffer) - 1;
char *end = buffer + sizeof(buffer);
char *begin = end;
// write the string in reverse order
*ptr = 0;
while (width--) {
*--ptr = char(value % 10 + '0');
*--begin = char(value % 10 + '0');
value /= 10;
}
*--ptr = '.';
*--begin = '.';
// and dump it in the right order
writeRaw(ptr);
writeRaw(begin, end);
}
void writeRaw(const char *s) {
_length += _sink.print(s);
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s));
}
void writeRaw(const char *begin, const char *end) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(begin),
static_cast<size_t>(end - begin));
}
template <size_t N>
void writeRaw(const char (&s)[N]) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1);
}
void writeRaw(char c) {
_length += _sink.print(c);
_length += _writer.write(static_cast<uint8_t>(c));
}
protected:
Print &_sink;
TWriter &_writer;
size_t _length;
private:

View File

@ -10,25 +10,28 @@ namespace ArduinoJson {
namespace Internals {
// Converts a compact JSON string into an indented one.
template <typename Print>
template <typename TWriter>
class Prettyfier {
public:
explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
explicit Prettyfier(IndentedPrint<TWriter>& p) : _sink(p) {
_previousChar = 0;
_inString = false;
}
size_t print(char c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
_previousChar = c;
size_t write(uint8_t c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(char(c));
_previousChar = char(c);
return n;
}
size_t print(const char* s) {
size_t write(const uint8_t* s, size_t n) {
// TODO: optimize
size_t n = 0;
while (*s) n += print(*s++);
return n;
size_t bytesWritten = 0;
while (n > 0) {
bytesWritten += write(*s++);
n--;
}
return bytesWritten;
}
private:
@ -38,12 +41,12 @@ class Prettyfier {
return _previousChar == '{' || _previousChar == '[';
}
size_t handleStringChar(char c) {
size_t handleStringChar(uint8_t c) {
bool isQuote = c == '"' && _previousChar != '\\';
if (isQuote) _inString = false;
return _sink.print(c);
return _sink.write(c);
}
size_t handleMarkupChar(char c) {
@ -73,26 +76,26 @@ class Prettyfier {
size_t writeBlockClose(char c) {
size_t n = 0;
n += unindentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
size_t writeBlockOpen(char c) {
size_t n = 0;
n += indentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
size_t writeColon() {
size_t n = 0;
n += _sink.print(": ");
n += write(": ");
return n;
}
size_t writeComma() {
size_t n = 0;
n += _sink.print(",\r\n");
n += write(",\r\n");
return n;
}
@ -100,14 +103,14 @@ class Prettyfier {
_inString = true;
size_t n = 0;
n += indentIfNeeded();
n += _sink.print('"');
n += write('"');
return n;
}
size_t writeNormalChar(char c) {
size_t n = 0;
n += indentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
@ -115,19 +118,28 @@ class Prettyfier {
if (!inEmptyBlock()) return 0;
_sink.indent();
return _sink.print("\r\n");
return write("\r\n");
}
size_t unindentIfNeeded() {
if (inEmptyBlock()) return 0;
_sink.unindent();
return _sink.print("\r\n");
return write("\r\n");
}
size_t write(char c) {
return _sink.write(static_cast<uint8_t>(c));
}
template <size_t N>
size_t write(const char (&s)[N]) {
return _sink.write(reinterpret_cast<const uint8_t*>(s), N - 1);
}
char _previousChar;
IndentedPrint<Print>& _sink;
IndentedPrint<TWriter>& _sink;
bool _inString;
};
}
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -29,7 +29,7 @@ class JsonArray {
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArrayData, JsonObject
template <typename T>
bool add(const T& value) {
@ -154,7 +154,7 @@ class JsonArray {
// Sets the value at specified index.
//
// bool add(size_t index, const TValue&);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArrayData, JsonObject
template <typename T>
bool set(size_t index, const T& value) {

View File

@ -9,7 +9,6 @@
#include "JsonVariant.hpp"
#include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer.

View File

@ -27,7 +27,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// Replaces the value
//
// operator=(const TValue&)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename T>
FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
@ -60,7 +60,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// Replaces the value
//
// bool set(const TValue&)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) {

View File

@ -188,7 +188,7 @@ class JsonObject {
//
// bool set(TKey, TValue);
// TKey = const std::string&, const String&
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool set(const TString& key, const TValue& value) {
@ -205,7 +205,7 @@ class JsonObject {
//
// bool set(TKey, const TValue&);
// TKey = char*, const char*, const FlashStringHelper*
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool set(TString* key, const TValue& value) {
@ -254,7 +254,7 @@ class JsonObject {
iterator findKey(TStringRef key) {
iterator it;
for (it = begin(); it != end(); ++it) {
if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
if (Internals::makeString(key).equals(it->key)) break;
}
return it;
}
@ -288,7 +288,7 @@ class JsonObject {
if (!_data) return false;
// ignore null key
if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
if (Internals::makeString(key).is_null()) return false;
// search a matching key
iterator it = findKey<TStringRef>(key);

View File

@ -9,7 +9,6 @@
#include "JsonPair.hpp"
#include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer.

View File

@ -67,7 +67,8 @@ class JsonObjectSubscript
// Sets the specified value.
//
// bool set(const TValue&);
// TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, char, long, int, short, float, double, serialized,
// JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set(
@ -94,7 +95,7 @@ class JsonObjectSubscript
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals,
inline typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) const {
return impl()->template as<JsonObject>()[key];
@ -102,7 +103,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals,
inline typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) {
return impl()->template as<JsonObject>()[key];
@ -110,7 +111,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<const TString *>::has_equals,
inline typename enable_if<IsString<const TString *>::value,
JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) {
return impl()->template as<JsonObject>()[key];
@ -118,7 +119,7 @@ inline typename enable_if<StringTraits<const TString *>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString *>::has_equals,
inline typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) const {
return impl()->template as<JsonObject>()[key];

View File

@ -12,7 +12,8 @@
#include "Data/JsonVariantType.hpp"
#include "JsonVariantBase.hpp"
#include "Polyfills/type_traits.hpp"
#include "RawJson.hpp"
#include "Serialization/DynamicStringWriter.hpp"
#include "SerializedValue.hpp"
namespace ArduinoJson {
@ -99,9 +100,10 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
}
// Create a JsonVariant containing an unparsed string
JsonVariant(Internals::RawJsonString<const char *> value) {
JsonVariant(Internals::SerializedValue<const char *> value) {
_type = Internals::JSON_UNPARSED;
_content.asString = value;
_content.asRaw.data = value.data();
_content.asRaw.size = value.size();
}
JsonVariant(JsonArray array);
@ -153,7 +155,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
// std::string as<std::string>() const;
// String as<String>() const;
template <typename T>
typename Internals::enable_if<Internals::StringTraits<T>::has_append, T>::type
typename Internals::enable_if<Internals::IsWriteableString<T>::value, T>::type
as() const {
const char *cstr = variantAsString();
if (cstr) return T(cstr);
@ -276,7 +278,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
return visitor.acceptString(_content.asString);
case JSON_UNPARSED:
return visitor.acceptRawJson(_content.asString);
return visitor.acceptRawJson(_content.asRaw.data, _content.asRaw.size);
case JSON_NEGATIVE_INTEGER:
return visitor.acceptNegativeInteger(_content.asInteger);
@ -310,9 +312,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
return _type == Internals::JSON_OBJECT;
}
bool variantIsString() const {
return _type == Internals::JSON_STRING ||
(_type == Internals::JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString));
return _type == Internals::JSON_STRING;
}
// The current type of the variant

View File

@ -6,7 +6,7 @@
#include "Data/IsVariant.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
class JsonArray;
@ -104,16 +104,14 @@ class JsonVariantComparisons {
}
template <typename TString>
typename enable_if<StringTraits<TString>::has_equals, bool>::type equals(
typename enable_if<IsString<TString>::value, bool>::type equals(
const TString &comparand) const {
const char *value = as<const char *>();
return StringTraits<TString>::equals(comparand, value);
return makeString(comparand).equals(as<const char *>());
}
template <typename TComparand>
typename enable_if<!IsVariant<TComparand>::value &&
!StringTraits<TComparand>::has_equals,
bool>::type
typename enable_if<
!IsVariant<TComparand>::value && !IsString<TComparand>::value, bool>::type
equals(const TComparand &comparand) const {
return as<TComparand>() == comparand;
}
@ -132,8 +130,7 @@ class JsonVariantComparisons {
if (is<JsonObject>() && right.template is<JsonObject>())
return as<JsonObject>() == right.template as<JsonObject>();
if (is<char *>() && right.template is<char *>())
return StringTraits<const char *>::equals(as<char *>(),
right.template as<char *>());
return makeString(as<char *>()).equals(right.template as<char *>());
return false;
}

View File

@ -68,6 +68,7 @@ inline T JsonVariant::variantAsInteger() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
case JSON_UNPARSED:
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
@ -75,7 +76,6 @@ inline T JsonVariant::variantAsInteger() const {
case JSON_NEGATIVE_INTEGER:
return T(~_content.asInteger + 1);
case JSON_STRING:
case JSON_UNPARSED:
return parseInteger<T>(_content.asString);
default:
return T(_content.asFloat);
@ -84,11 +84,7 @@ inline T JsonVariant::variantAsInteger() const {
inline const char *JsonVariant::variantAsString() const {
using namespace Internals;
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
return _type == JSON_STRING ? _content.asString : NULL;
}
template <typename T>
@ -96,6 +92,7 @@ inline T JsonVariant::variantAsFloat() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
case JSON_UNPARSED:
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
@ -103,7 +100,6 @@ inline T JsonVariant::variantAsFloat() const {
case JSON_NEGATIVE_INTEGER:
return -static_cast<T>(_content.asInteger);
case JSON_STRING:
case JSON_UNPARSED:
return parseFloat<T>(_content.asString);
default:
return static_cast<T>(_content.asFloat);
@ -112,27 +108,20 @@ inline T JsonVariant::variantAsFloat() const {
inline bool JsonVariant::variantIsBoolean() const {
using namespace Internals;
if (_type == JSON_BOOLEAN) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
return !strcmp(_content.asString, "true") ||
!strcmp(_content.asString, "false");
return _type == JSON_BOOLEAN;
}
inline bool JsonVariant::variantIsInteger() const {
using namespace Internals;
return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && isInteger(_content.asString));
return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER;
}
inline bool JsonVariant::variantIsFloat() const {
using namespace Internals;
return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
_type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && isFloat(_content.asString));
_type == JSON_NEGATIVE_INTEGER;
}
} // namespace ArduinoJson

View File

@ -7,7 +7,7 @@
#include "Data/JsonVariantAs.hpp"
#include "Polyfills/attributes.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
class JsonArray;
@ -43,21 +43,21 @@ class JsonVariantSubscripts {
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE
typename enable_if<StringTraits<TString>::has_equals,
typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type
operator[](const TString &key) const;
//
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE typename enable_if<StringTraits<TString>::has_equals,
FORCE_INLINE typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type
operator[](const TString &key);
//
// JsonObjectSubscript operator[](TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE typename enable_if<StringTraits<const TString *>::has_equals,
FORCE_INLINE typename enable_if<IsString<const TString *>::value,
JsonObjectSubscript<const TString *> >::type
operator[](const TString *key);
//
@ -65,7 +65,7 @@ class JsonVariantSubscripts {
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE
typename enable_if<StringTraits<TString *>::has_equals,
typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<const TString *> >::type
operator[](const TString *key) const;

View File

@ -13,10 +13,10 @@
namespace ArduinoJson {
namespace Internals {
template <typename TPrint>
template <typename TWriter>
class MsgPackSerializer {
public:
MsgPackSerializer(TPrint& output) : _output(&output), _bytesWritten(0) {}
MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {}
template <typename T>
typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) {
@ -91,7 +91,9 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
}
void acceptRawJson(const char* /*value*/) {}
void acceptRawJson(const char* data, size_t size) {
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
}
void acceptNegativeInteger(JsonUInt value) {
JsonUInt negated = JsonUInt(~value + 1);
@ -150,12 +152,11 @@ class MsgPackSerializer {
private:
void writeByte(uint8_t c) {
_output->print(char(c));
_bytesWritten++;
_bytesWritten += _writer->write(c);
}
void writeBytes(const uint8_t* c, size_t n) {
for (; n > 0; --n, ++c) writeByte(*c);
void writeBytes(const uint8_t* p, size_t n) {
_bytesWritten += _writer->write(p, n);
}
template <typename T>
@ -164,7 +165,7 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
TPrint* _output;
TWriter* _writer;
size_t _bytesWritten;
};
} // namespace Internals

View File

@ -44,28 +44,46 @@ struct FloatTraits<T, 8 /*64bits*/> {
static T positiveBinaryPowerOfTen(int index) {
static T factors[] = {
1e1, 1e2, 1e4, 1e8, 1e16, 1e32,
// workaround to support platforms with single precision literals
forge(0x4D384F03, 0xE93FF9F5), forge(0x5A827748, 0xF9301D32),
forge(0x75154FDD, 0x7F73BF3C)};
1e1,
1e2,
1e4,
1e8,
1e16,
forge(0x4693B8B5, 0xB5056E17), // 1e32
forge(0x4D384F03, 0xE93FF9F5), // 1e64
forge(0x5A827748, 0xF9301D32), // 1e128
forge(0x75154FDD, 0x7F73BF3C) // 1e256
};
return factors[index];
}
static T negativeBinaryPowerOfTen(int index) {
static T factors[] = {
1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32,
// workaround to support platforms with single precision literals
forge(0x32A50FFD, 0x44F4A73D), forge(0x255BBA08, 0xCF8C979D),
forge(0x0AC80628, 0x64AC6F43)};
forge(0x3FB99999, 0x9999999A), // 1e-1
forge(0x3F847AE1, 0x47AE147B), // 1e-2
forge(0x3F1A36E2, 0xEB1C432D), // 1e-4
forge(0x3E45798E, 0xE2308C3A), // 1e-8
forge(0x3C9CD2B2, 0x97D889BC), // 1e-16
forge(0x3949F623, 0xD5A8A733), // 1e-32
forge(0x32A50FFD, 0x44F4A73D), // 1e-64
forge(0x255BBA08, 0xCF8C979D), // 1e-128
forge(0x0AC80628, 0x64AC6F43) // 1e-256
};
return factors[index];
}
static T negativeBinaryPowerOfTenPlusOne(int index) {
static T factors[] = {
1e0, 1e-1, 1e-3, 1e-7, 1e-15, 1e-31,
// workaround to support platforms with single precision literals
forge(0x32DA53FC, 0x9631D10D), forge(0x25915445, 0x81B7DEC2),
forge(0x0AFE07B2, 0x7DD78B14)};
1e0,
forge(0x3FB99999, 0x9999999A), // 1e-1
forge(0x3F50624D, 0xD2F1A9FC), // 1e-3
forge(0x3E7AD7F2, 0x9ABCAF48), // 1e-7
forge(0x3CD203AF, 0x9EE75616), // 1e-15
forge(0x398039D6, 0x65896880), // 1e-31
forge(0x32DA53FC, 0x9631D10D), // 1e-63
forge(0x25915445, 0x81B7DEC2), // 1e-127
forge(0x0AFE07B2, 0x7DD78B14) // 1e-255
};
return factors[index];
}
@ -77,6 +95,9 @@ struct FloatTraits<T, 8 /*64bits*/> {
return forge(0x7ff00000, 0x00000000);
}
// constructs a double floating point values from its binary representation
// we use this function to workaround platforms with single precision literals
// (for example, when -fsingle-precision-constant is passed to GCC)
static T forge(uint32_t msb, uint32_t lsb) {
union {
uint64_t integerBits;

View File

@ -10,7 +10,7 @@ namespace ArduinoJson {
namespace Internals {
inline bool isInteger(const char* s) {
if (!s) return false;
if (!s || !*s) return false;
if (issign(*s)) s++;
while (isdigit(*s)) s++;
return *s == '\0';

View File

@ -1,46 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
// A special type of data that can be used to insert pregenerated JSON portions.
template <typename T>
class RawJsonString {
public:
explicit RawJsonString(T str) : _str(str) {}
operator T() const {
return _str;
}
private:
T _str;
};
template <typename String>
struct StringTraits<RawJsonString<String>, void> {
static bool is_null(RawJsonString<String> source) {
return StringTraits<String>::is_null(static_cast<String>(source));
}
typedef RawJsonString<const char*> duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
return duplicate_t(StringTraits<String>::duplicate(source, buffer));
}
static const bool has_append = false;
static const bool has_equals = false;
static const bool should_duplicate = StringTraits<String>::should_duplicate;
};
}
template <typename T>
inline Internals::RawJsonString<T> RawJson(T str) {
return Internals::RawJsonString<T>(str);
}
}

View File

@ -7,14 +7,14 @@
namespace ArduinoJson {
namespace Internals {
class DummyPrint {
class DummyWriter {
public:
size_t print(char) {
size_t write(uint8_t) {
return 1;
}
size_t print(const char* s) {
return strlen(s);
size_t write(const uint8_t*, size_t n) {
return n;
}
};
} // namespace Internals

View File

@ -1,35 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Strings/StringTraits.hpp"
namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringBuilder {
public:
DynamicStringBuilder(TString &str) : _str(str) {}
size_t print(char c) {
StringTraits<TString>::append(_str, c);
return 1;
}
size_t print(const char *s) {
size_t initialLen = _str.length();
StringTraits<TString>::append(_str, s);
return _str.length() - initialLen;
}
private:
DynamicStringBuilder &operator=(const DynamicStringBuilder &);
TString &_str;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,81 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
namespace Internals {
template <typename>
struct IsWriteableString : false_type {};
// A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringWriter {};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct IsWriteableString<String> : true_type {};
template <>
class DynamicStringWriter<String> {
public:
DynamicStringWriter(String &str) : _str(&str) {}
size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c));
return 1;
}
size_t write(const uint8_t *s, size_t n) {
// CAUTION: Arduino String doesn't have append()
// and old version doesn't have size() either
_str->reserve(_str->length() + n);
while (n > 0) {
_str->operator+=(static_cast<char>(*s++));
n--;
}
return n;
}
private:
String *_str;
};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct IsWriteableString<std::string> : true_type {};
template <>
class DynamicStringWriter<std::string> {
public:
DynamicStringWriter(std::string &str) : _str(&str) {}
size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c));
return 1;
}
size_t write(const uint8_t *s, size_t n) {
_str->append(reinterpret_cast<const char *>(s), n);
return n;
}
private:
std::string *_str;
};
#endif
} // namespace Internals
} // namespace ArduinoJson

View File

@ -8,22 +8,25 @@ namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a char[]
class StaticStringBuilder {
class StaticStringWriter {
public:
StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) {
*p = '\0';
}
size_t print(char c) {
size_t write(uint8_t c) {
if (p >= end) return 0;
*p++ = c;
*p++ = static_cast<char>(c);
*p = '\0';
return 1;
}
size_t print(const char *s) {
size_t write(const uint8_t *s, size_t n) {
char *begin = p;
while (p < end && *s) *p++ = *s++;
while (p < end && n > 0) {
*p++ = static_cast<char>(*s++);
n--;
}
*p = '\0';
return size_t(p - begin);
}

View File

@ -13,27 +13,28 @@
namespace ArduinoJson {
namespace Internals {
class StreamPrintAdapter {
class StreamWriter {
public:
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
explicit StreamWriter(std::ostream& os) : _os(os) {}
size_t print(char c) {
size_t write(uint8_t c) {
_os << c;
return 1;
}
size_t print(const char* s) {
_os << s;
return strlen(s);
size_t write(const uint8_t* s, size_t n) {
_os.write(reinterpret_cast<const char*>(s),
static_cast<std::streamsize>(n));
return n;
}
private:
// cannot be assigned
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
StreamWriter& operator=(const StreamWriter&);
std::ostream& _os;
};
}
}
} // namespace Internals
} // namespace ArduinoJson
#endif // ARDUINOJSON_ENABLE_STD_STREAM

View File

@ -4,15 +4,15 @@
#pragma once
#include "./DummyPrint.hpp"
#include "./DummyWriter.hpp"
namespace ArduinoJson {
namespace Internals {
template <template <typename> class TSerializer, typename TSource>
size_t measure(const TSource &source) {
DummyPrint dp;
TSerializer<DummyPrint> serializer(dp);
DummyWriter dp;
TSerializer<DummyWriter> serializer(dp);
source.visit(serializer);
return serializer.bytesWritten();
}

View File

@ -4,11 +4,11 @@
#pragma once
#include "./DynamicStringBuilder.hpp"
#include "./StaticStringBuilder.hpp"
#include "./DynamicStringWriter.hpp"
#include "./StaticStringWriter.hpp"
#if ARDUINOJSON_ENABLE_STD_STREAM
#include "./StreamPrintAdapter.hpp"
#include "./StreamWriter.hpp"
#endif
namespace ArduinoJson {
@ -16,7 +16,7 @@ namespace Internals {
template <template <typename> class TSerializer, typename TSource,
typename TPrint>
typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize(
const TSource &source, TPrint &destination) {
TSerializer<TPrint> serializer(destination);
source.visit(serializer);
@ -26,29 +26,29 @@ typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
#if ARDUINOJSON_ENABLE_STD_STREAM
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, std::ostream &os) {
StreamPrintAdapter adapter(os);
return serialize<TSerializer>(source, adapter);
StreamWriter writer(os);
return serialize<TSerializer>(source, writer);
}
#endif
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, char *buffer, size_t bufferSize) {
StaticStringBuilder sb(buffer, bufferSize);
return serialize<TSerializer>(source, sb);
StaticStringWriter writer(buffer, bufferSize);
return serialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource, size_t N>
size_t serialize(const TSource &source, char (&buffer)[N]) {
StaticStringBuilder sb(buffer, N);
return serialize<TSerializer>(source, sb);
StaticStringWriter writer(buffer, N);
return serialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource,
typename TString>
typename enable_if<StringTraits<TString>::has_append, size_t>::type serialize(
typename enable_if<IsWriteableString<TString>::value, size_t>::type serialize(
const TSource &source, TString &str) {
DynamicStringBuilder<TString> sb(str);
return serialize<TSerializer>(source, sb);
DynamicStringWriter<TString> writer(str);
return serialize<TSerializer>(source, writer);
}
} // namespace Internals

View File

@ -0,0 +1,70 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
namespace Internals {
// A special type of data that can be used to insert pregenerated JSON portions.
template <typename T>
class SerializedValue {
public:
explicit SerializedValue(T str) : _str(str) {}
operator T() const {
return _str;
}
const char* data() const {
return _str.c_str();
}
size_t size() const {
// CAUTION: the old Arduino String doesn't have size()
return _str.length();
}
private:
T _str;
};
template <typename TChar>
class SerializedValue<TChar*> {
public:
explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {}
operator TChar*() const {
return _data;
}
TChar* data() const {
return _data;
}
size_t size() const {
return _size;
}
private:
TChar* _data;
size_t _size;
};
} // namespace Internals
template <typename T>
inline Internals::SerializedValue<T> serialized(T str) {
return Internals::SerializedValue<T>(str);
}
template <typename TChar>
inline Internals::SerializedValue<TChar*> serialized(TChar* p) {
return Internals::SerializedValue<TChar*>(p, Internals::makeString(p).size());
}
template <typename TChar>
inline Internals::SerializedValue<TChar*> serialized(TChar* p, size_t n) {
return Internals::SerializedValue<TChar*>(p, n);
}
} // namespace ArduinoJson

View File

@ -0,0 +1,60 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <WString.h>
namespace ArduinoJson {
namespace Internals {
class ArduinoString {
public:
ArduinoString(const ::String& str) : _str(&str) {}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str->c_str()) return NULL; // <- Arduino string can return NULL
size_t n = _str->length() + 1;
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup);
}
bool is_null() const {
// Arduino's String::c_str() can return NULL
return _str->c_str();
}
bool equals(const char* expected) const {
// Arduino's String::c_str() can return NULL
const char* actual = _str->c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
}
const char* data() const {
return _str->c_str();
}
size_t size() const {
return _str->length();
}
private:
const ::String* _str;
};
template <>
struct IsString< ::String> : true_type {};
template <>
struct IsString< ::StringSumHelper> : true_type {};
inline ArduinoString makeString(const ::String& str) {
return ArduinoString(str);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,44 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TChar>
struct CharPointerTraits {
static bool equals(const TChar* str, const char* expected) {
const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
static bool is_null(const TChar* str) {
return !str;
}
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str, size);
return static_cast<duplicate_t>(dup);
}
static const bool has_append = false;
static const bool has_equals = true;
static const bool should_duplicate = !is_const<TChar>::value;
};
// char*, unsigned char*, signed char*
// const char*, const unsigned char*, const signed char*
template <typename TChar>
struct StringTraits<TChar*, typename enable_if<sizeof(TChar) == 1>::type>
: CharPointerTraits<TChar> {};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,47 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class FixedSizeFlashString {
public:
FixedSizeFlashString(const __FlashStringHelper* str, size_t sz)
: _str(str), _size(sz) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp_P(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
void* dup = buffer->alloc(_size);
if (dup != NULL) memcpy_P(dup, (const char*)_str, _size);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen_P(reinterpret_cast<const char*>(_str));
}
private:
const __FlashStringHelper* _str;
size_t _size;
};
inline FixedSizeFlashString makeString(const __FlashStringHelper* str,
size_t sz) {
return FixedSizeFlashString(str, sz);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,48 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class FixedSizeRamString {
public:
FixedSizeRamString(const char* str, size_t n) : _str(str), _size(n) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
void* dup = buffer->alloc(_size);
if (!dup) return NULL;
memcpy(dup, _str, _size);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen(reinterpret_cast<const char*>(_str));
}
private:
const char* _str;
size_t _size;
};
template <typename TChar>
inline FixedSizeRamString makeString(const TChar* str, size_t size) {
return FixedSizeRamString(reinterpret_cast<const char*>(str), size);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,41 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_PROGMEM
namespace ArduinoJson {
namespace Internals {
template <>
struct StringTraits<const __FlashStringHelper*, void> {
static bool equals(const __FlashStringHelper* str, const char* expected) {
const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp_P(expected, actual) == 0;
}
static bool is_null(const __FlashStringHelper* str) {
return !str;
}
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen_P((const char*)str) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy_P(dup, (const char*)str, size);
return static_cast<duplicate_t>(dup);
}
static const bool has_append = false;
static const bool has_equals = true;
static const bool should_duplicate = true;
};
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -1,73 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
namespace Internals {
template <typename TString>
struct StdStringTraits {
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const TString& str, Buffer* buffer) {
if (!str.c_str()) return NULL; // <- Arduino string can return NULL
size_t size = str.length() + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str.c_str(), size);
return static_cast<duplicate_t>(dup);
}
static bool is_null(const TString& str) {
// Arduino's String::c_str() can return NULL
return !str.c_str();
}
static bool equals(const TString& str, const char* expected) {
// Arduino's String::c_str() can return NULL
const char* actual = str.c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
}
static void append(TString& str, char c) {
str += c;
}
static void append(TString& str, const char* s) {
str += s;
}
static const bool has_append = true;
static const bool has_equals = true;
static const bool should_duplicate = true;
};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct StringTraits<String, void> : StdStringTraits<String> {};
template <>
struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
#endif
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -0,0 +1,52 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string>
namespace ArduinoJson {
namespace Internals {
class StlString {
public:
StlString(const std::string& str) : _str(&str) {}
template <typename Buffer>
const char* save(Buffer* buffer) const {
size_t n = _str->length() + 1;
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup);
}
bool is_null() const {
return false;
}
bool equals(const char* expected) const {
return *_str == expected;
}
const char* data() const {
return _str->data();
}
size_t size() const {
return _str->size();
}
private:
const std::string* _str;
};
template <>
struct IsString<std::string> : true_type {};
inline StlString makeString(const std::string& str) {
return StlString(str);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,30 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string.h>
#include "../Configuration.hpp"
#include "../Polyfills/type_traits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename TString, typename Enable = void>
struct StringTraits {
static const bool has_append = false;
static const bool has_equals = false;
};
template <typename TString>
struct StringTraits<const TString, void> : StringTraits<TString> {};
template <typename TString>
struct StringTraits<TString&, void> : StringTraits<TString> {};
} // namespace Internals
} // namespace ArduinoJson
#include "CharPointer.hpp"
#include "FlashString.hpp"
#include "StdString.hpp"

View File

@ -0,0 +1,36 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename>
struct IsString : false_type {};
template <typename T>
struct IsString<const T> : IsString<T> {};
template <typename T>
struct IsString<T&> : IsString<T> {};
} // namespace Internals
} // namespace ArduinoJson
#include "FixedSizeRamString.hpp"
#include "ZeroTerminatedRamString.hpp"
#if ARDUINOJSON_ENABLE_STD_STRING
#include "StlString.hpp"
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include "ArduinoString.hpp"
#endif
#if ARDUINOJSON_ENABLE_PROGMEM
#include "FixedSizeFlashString.hpp"
#include "ZeroTerminatedFlashString.hpp"
#endif

View File

@ -0,0 +1,48 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class ZeroTerminatedFlashString {
public:
ZeroTerminatedFlashString(const __FlashStringHelper* str) : _str(str) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp_P(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
size_t n = size() + 1; // copy the terminator
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy_P(dup, (const char*)_str, n);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen_P(reinterpret_cast<const char*>(_str));
}
private:
const __FlashStringHelper* _str;
};
inline ZeroTerminatedFlashString makeString(const __FlashStringHelper* str) {
return ZeroTerminatedFlashString(str);
}
template <>
struct IsString<const __FlashStringHelper*> : true_type {};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,53 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class ZeroTerminatedRamString {
public:
ZeroTerminatedRamString(const char* str) : _str(str) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
size_t n = size() + 1;
void* dup = buffer->alloc(n);
if (!dup) return NULL;
memcpy(dup, _str, n);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen(reinterpret_cast<const char*>(_str));
}
private:
const char* _str;
};
template <typename TChar>
inline ZeroTerminatedRamString makeString(const TChar* str) {
return ZeroTerminatedRamString(reinterpret_cast<const char*>(str));
}
template <typename TChar>
struct IsString<TChar*> {
static const bool value = sizeof(TChar) == 1;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,7 +4,7 @@
#pragma once
#define ARDUINOJSON_VERSION "6.1.0-beta"
#define ARDUINOJSON_VERSION "6.2.0-beta"
#define ARDUINOJSON_VERSION_MAJOR 6
#define ARDUINOJSON_VERSION_MINOR 1
#define ARDUINOJSON_VERSION_MINOR 2
#define ARDUINOJSON_VERSION_REVISION 0

View File

@ -67,13 +67,13 @@ endif()
add_subdirectory(DynamicJsonBuffer)
add_subdirectory(IntegrationTests)
add_subdirectory(JsonArray)
add_subdirectory(JsonObject)
add_subdirectory(JsonDeserializer)
add_subdirectory(JsonObject)
add_subdirectory(JsonSerializer)
add_subdirectory(JsonVariant)
add_subdirectory(JsonWriter)
add_subdirectory(Misc)
add_subdirectory(MsgPackDeserializer)
add_subdirectory(MsgPackSerializer)
add_subdirectory(Polyfills)
add_subdirectory(Numbers)
add_subdirectory(StaticJsonBuffer)

View File

@ -4,6 +4,7 @@
add_executable(IntegrationTests
gbathree.cpp
issue772.cpp
round_trip.cpp
)

View File

@ -0,0 +1,27 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
// https://github.com/bblanchon/ArduinoJson/issues/772
TEST_CASE("Issue772") {
DynamicJsonDocument doc1, doc2;
DeserializationError err;
std::string data =
"{\"state\":{\"reported\":{\"timestamp\":\"2018-07-02T09:40:12Z\","
"\"mac\":\"2C3AE84FC076\",\"firmwareVersion\":\"v0.2.7-5-gf4d4d78\","
"\"visibleLight\":261,\"infraRed\":255,\"ultraViolet\":0.02,"
"\"Temperature\":26.63,\"Pressure\":101145.7,\"Humidity\":54.79883,"
"\"Vbat\":4.171261,\"soilMoisture\":0,\"ActB\":0}}}";
err = deserializeJson(doc1, data);
REQUIRE(err == DeserializationError::Ok);
data = "";
serializeMsgPack(doc1, data);
err = deserializeMsgPack(doc2, data);
REQUIRE(err == DeserializationError::Ok);
}

View File

@ -4,16 +4,17 @@
add_executable(JsonArrayTests
add.cpp
basics.cpp
copyFrom.cpp
copyTo.cpp
invalid.cpp
createNested.cpp
isNull.cpp
iterator.cpp
remove.cpp
set.cpp
size.cpp
std_string.cpp
subscript.cpp
undefined.cpp
)
target_link_libraries(JsonArrayTests catch)

View File

@ -100,14 +100,26 @@ TEST_CASE("JsonArray::add()") {
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should not duplicate RawJson(const char*)") {
_array.add(RawJson("{}"));
SECTION("should not duplicate serialized(const char*)") {
_array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate RawJson(char*)") {
_array.add(RawJson(const_cast<char*>("{}")));
SECTION("should duplicate serialized(char*)") {
_array.add(serialized(const_cast<char*>("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
_array.add(serialized(std::string("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
_array.add(serialized(std::string("\0XX", 3)));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
REQUIRE(expectedSize == doc.memoryUsage());
}

View File

@ -9,14 +9,6 @@ TEST_CASE("JsonArray basics") {
DynamicJsonDocument doc;
JsonArray array = doc.to<JsonArray>();
SECTION("isNull()") {
REQUIRE(array.isNull() == false);
}
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("CreateNestedArray") {
JsonArray arr = array.createNestedArray();
REQUIRE(arr == array[0].as<JsonArray>());

25
test/JsonArray/isNull.cpp Normal file
View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::isNull()") {
SECTION("returns true for undefined JsonArray") {
JsonArray array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == false);
}
SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == true);
}
}

View File

@ -7,29 +7,33 @@
TEST_CASE("JsonArray::size()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
JsonArray array = doc.to<JsonArray>();
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("increases after add()") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array.add("world");
REQUIRE(2U == _array.size());
array.add("world");
REQUIRE(2U == array.size());
}
SECTION("remains the same after set()") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array.set(0, "hello");
REQUIRE(1U == _array.size());
array.set(0, "hello");
REQUIRE(1U == array.size());
}
SECTION("remains the same after assigment") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array[0] = "hello";
REQUIRE(1U == _array.size());
array[0] = "hello";
REQUIRE(1U == array.size());
}
}

View File

@ -128,12 +128,7 @@ TEST_CASE("deserialize JSON array") {
SECTION("No quotes") {
DeserializationError err = deserializeJson(doc, "[ hello , world ]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == "hello");
REQUIRE(arr[1] == "world");
REQUIRE(err == DeserializationError::InvalidInput);
}
SECTION("Double quotes (empty strings)") {

View File

@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON object") {
}
SECTION("No quotes") {
DeserializationError err = deserializeJson(doc, "{key:value}");
DeserializationError err = deserializeJson(doc, "{key:'value'}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(err == DeserializationError::Ok);

View File

@ -21,7 +21,7 @@ TEST_CASE("deserializeJson(std::istream&)") {
}
SECTION("object") {
std::istringstream json(" { hello : world // comment\n }");
std::istringstream json(" { hello : 'world' // comment\n }");
DeserializationError err = deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();

View File

@ -3,10 +3,10 @@
# MIT License
add_executable(JsonObjectTests
basics.cpp
containsKey.cpp
get.cpp
invalid.cpp
isNull.cpp
iterator.cpp
remove.cpp
set.cpp

View File

@ -1,15 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject basics") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("isNull()") {
REQUIRE(obj.isNull() == false);
}
}

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::isNull()") {
SECTION("returns true for undefined JsonObject") {
JsonObject array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == false);
}
SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == true);
}
}

View File

@ -67,15 +67,15 @@ TEST_CASE("serializeJson(JsonArray)") {
check(array, "[1,2]");
}
SECTION("RawJson(const char*)") {
array.add(RawJson("{\"key\":\"value\"}"));
SECTION("serialized(const char*)") {
array.add(serialized("{\"key\":\"value\"}"));
check(array, "[{\"key\":\"value\"}]");
}
SECTION("RawJson(char*)") {
SECTION("serialized(char*)") {
char tmp[] = "{\"key\":\"value\"}";
array.add(RawJson(tmp));
array.add(serialized(tmp));
check(array, "[{\"key\":\"value\"}]");
}

View File

@ -68,9 +68,9 @@ TEST_CASE("serializeJson(JsonObject)") {
check(obj, "{\"a\":1,\"b\":2}");
}
SECTION("RawJson") {
obj["a"] = RawJson("[1,2]");
obj.set("b", RawJson("[4,5]"));
SECTION("serialized(const char*)") {
obj["a"] = serialized("[1,2]");
obj.set("b", serialized("[4,5]"));
check(obj, "{\"a\":[1,2],\"b\":[4,5]}");
}

View File

@ -95,21 +95,4 @@ TEST_CASE("JsonVariant::is()") {
SECTION("string") {
checkIsString("42");
}
SECTION("unparsed bool") {
checkIsBool(RawJson("true"));
checkIsBool(RawJson("false"));
}
SECTION("unparsed int") {
checkIsInteger(RawJson("42"));
}
SECTION("unparsed float") {
checkIsFloat(RawJson("4.2e-10"));
}
SECTION("unparsed null") {
checkIsString(RawJson("null"));
}
}

View File

@ -7,15 +7,15 @@
#include <string>
#include <ArduinoJson/Json/JsonWriter.hpp>
#include <ArduinoJson/Serialization/DynamicStringBuilder.hpp>
#include <ArduinoJson/Serialization/DynamicStringWriter.hpp>
using namespace ArduinoJson::Internals;
template <typename TFloat>
void check(TFloat input, const std::string& expected) {
std::string output;
DynamicStringBuilder<std::string> sb(output);
JsonWriter<DynamicStringBuilder<std::string> > writer(sb);
DynamicStringWriter<std::string> sb(output);
JsonWriter<DynamicStringWriter<std::string> > writer(sb);
writer.writeFloat(input);
REQUIRE(writer.bytesWritten() == output.size());
CHECK(expected == output);

View File

@ -5,14 +5,14 @@
#include <catch.hpp>
#include <ArduinoJson/Json/JsonWriter.hpp>
#include <ArduinoJson/Serialization/StaticStringBuilder.hpp>
#include <ArduinoJson/Serialization/StaticStringWriter.hpp>
using namespace ArduinoJson::Internals;
void check(const char* input, std::string expected) {
char output[1024];
StaticStringBuilder sb(output, sizeof(output));
JsonWriter<StaticStringBuilder> writer(sb);
StaticStringWriter sb(output, sizeof(output));
JsonWriter<StaticStringWriter> writer(sb);
writer.writeString(input);
REQUIRE(expected == output);
REQUIRE(writer.bytesWritten() == expected.size());

View File

@ -4,8 +4,7 @@
add_executable(MiscTests
FloatParts.cpp
StringBuilder.cpp
StringTraits.cpp
StringWriter.cpp
TypeTraits.cpp
unsigned_char.cpp
version.cpp

View File

@ -1,22 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
template <typename String>
bool should_duplicate() {
return StringTraits<String>::should_duplicate;
}
TEST_CASE("StringTraits") {
SECTION("should_duplicate") {
REQUIRE(false == should_duplicate<const char*>());
REQUIRE(true == should_duplicate<char*>());
REQUIRE(true == should_duplicate<RawJsonString<char*> >());
REQUIRE(false == should_duplicate<RawJsonString<const char*> >());
}
}

View File

@ -7,44 +7,49 @@
using namespace ArduinoJson::Internals;
template <typename StringBuilder, typename String>
void common_tests(StringBuilder& sb, const String& output) {
template <typename StringWriter>
static size_t print(StringWriter& sb, const char* s) {
return sb.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
}
template <typename StringWriter, typename String>
void common_tests(StringWriter& sb, const String& output) {
SECTION("InitialState") {
REQUIRE(std::string("") == output);
}
SECTION("EmptyString") {
REQUIRE(0 == sb.print(""));
REQUIRE(0 == print(sb, ""));
REQUIRE(std::string("") == output);
}
SECTION("OneString") {
REQUIRE(4 == sb.print("ABCD"));
REQUIRE(4 == print(sb, "ABCD"));
REQUIRE(std::string("ABCD") == output);
}
SECTION("TwoStrings") {
REQUIRE(4 == sb.print("ABCD"));
REQUIRE(4 == sb.print("EFGH"));
REQUIRE(4 == print(sb, "ABCD"));
REQUIRE(4 == print(sb, "EFGH"));
REQUIRE(std::string("ABCDEFGH") == output);
}
}
TEST_CASE("StaticStringBuilder") {
TEST_CASE("StaticStringWriter") {
char output[20];
StaticStringBuilder sb(output, sizeof(output));
StaticStringWriter sb(output, sizeof(output));
common_tests(sb, static_cast<const char*>(output));
SECTION("OverCapacity") {
REQUIRE(19 == sb.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
REQUIRE(0 == sb.print("ABC"));
REQUIRE(19 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
REQUIRE(0 == print(sb, "ABC"));
REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
}
}
TEST_CASE("DynamicStringBuilder") {
TEST_CASE("DynamicStringWriter") {
std::string output;
DynamicStringBuilder<std::string> sb(output);
DynamicStringWriter<std::string> sb(output);
common_tests(sb, output);
}

View File

@ -70,4 +70,14 @@ TEST_CASE("serialize MsgPack object") {
//
// check(object, expected);
// }
SECTION("serialized(const char*)") {
object["hello"] = serialized("\xDB\x00\x01\x00\x00", 5);
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
}
SECTION("serialized(std::string)") {
object["hello"] = serialized(std::string("\xDB\x00\x01\x00\x00", 5));
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
}
}

View File

@ -126,4 +126,9 @@ TEST_CASE("serialize MsgPack value") {
std::string shortest(65536, '?');
check(shortest.c_str(), std::string("\xDB\x00\x01\x00\x00", 5) + shortest);
}
SECTION("serialized(const char*)") {
check(serialized("\xDA\xFF\xFF"), "\xDA\xFF\xFF");
check(serialized("\xDB\x00\x01\x00\x00", 5), "\xDB\x00\x01\x00\x00");
}
}

View File

@ -2,12 +2,12 @@
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(PolyfillsTests
add_executable(NumbersTests
isFloat.cpp
isInteger.cpp
parseFloat.cpp
parseInteger.cpp
)
target_link_libraries(PolyfillsTests catch)
add_test(Polyfills PolyfillsTests)
target_link_libraries(NumbersTests catch)
add_test(Numbers NumbersTests)

80
test/Numbers/isFloat.cpp Normal file
View File

@ -0,0 +1,80 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Numbers/isFloat.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("isFloat()") {
SECTION("Input is NULL") {
REQUIRE(isFloat(NULL) == false);
}
SECTION("Empty string") {
REQUIRE(isFloat("") == false);
}
SECTION("NoExponent") {
REQUIRE(isFloat("3.14") == true);
REQUIRE(isFloat("-3.14") == true);
REQUIRE(isFloat("+3.14") == true);
}
SECTION("IntegralPartMissing") {
REQUIRE(isFloat(".14") == true);
REQUIRE(isFloat("-.14") == true);
REQUIRE(isFloat("+.14") == true);
}
SECTION("FractionalPartMissing") {
REQUIRE(isFloat("3.") == true);
REQUIRE(isFloat("-3.e14") == true);
REQUIRE(isFloat("+3.e-14") == true);
}
SECTION("NoDot") {
REQUIRE(isFloat("3e14") == true);
REQUIRE(isFloat("3e-14") == true);
REQUIRE(isFloat("3e+14") == true);
}
SECTION("Integer") {
REQUIRE(isFloat("14") == true);
REQUIRE(isFloat("-14") == true);
REQUIRE(isFloat("+14") == true);
}
SECTION("ExponentMissing") {
REQUIRE(isFloat("3.14e") == false);
REQUIRE(isFloat("3.14e-") == false);
REQUIRE(isFloat("3.14e+") == false);
}
SECTION("JustASign") {
REQUIRE(isFloat("-") == false);
REQUIRE(isFloat("+") == false);
}
SECTION("Empty") {
REQUIRE(isFloat("") == false);
}
SECTION("NaN") {
REQUIRE(isFloat("NaN") == true);
REQUIRE(isFloat("n") == false);
REQUIRE(isFloat("N") == false);
REQUIRE(isFloat("nan") == false);
REQUIRE(isFloat("-NaN") == false);
REQUIRE(isFloat("+NaN") == false);
}
SECTION("Infinity") {
REQUIRE(isFloat("Infinity") == true);
REQUIRE(isFloat("+Infinity") == true);
REQUIRE(isFloat("-Infinity") == true);
REQUIRE(isFloat("infinity") == false);
REQUIRE(isFloat("Inf") == false);
}
}

View File

@ -0,0 +1,40 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Numbers/isInteger.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("isInteger()") {
SECTION("Null") {
REQUIRE(isInteger(NULL) == false);
}
SECTION("Empty string") {
REQUIRE(isInteger("") == false);
}
SECTION("FloatNotInteger") {
REQUIRE(isInteger("3.14") == false);
REQUIRE(isInteger("-3.14") == false);
REQUIRE(isInteger("+3.14") == false);
}
SECTION("Spaces") {
REQUIRE(isInteger("42 ") == false);
REQUIRE(isInteger(" 42") == false);
}
SECTION("Valid") {
REQUIRE(isInteger("42") == true);
REQUIRE(isInteger("-42") == true);
REQUIRE(isInteger("+42") == true);
}
SECTION("ExtraSign") {
REQUIRE(isInteger("--42") == false);
REQUIRE(isInteger("++42") == false);
}
}

View File

@ -1,76 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Numbers/isFloat.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("isFloat()") {
SECTION("Input is NULL") {
REQUIRE(isFloat(NULL) == false);
}
SECTION("NoExponent") {
REQUIRE(isFloat("3.14"));
REQUIRE(isFloat("-3.14"));
REQUIRE(isFloat("+3.14"));
}
SECTION("IntegralPartMissing") {
REQUIRE(isFloat(".14"));
REQUIRE(isFloat("-.14"));
REQUIRE(isFloat("+.14"));
}
SECTION("FractionalPartMissing") {
REQUIRE(isFloat("3."));
REQUIRE(isFloat("-3.e14"));
REQUIRE(isFloat("+3.e-14"));
}
SECTION("NoDot") {
REQUIRE(isFloat("3e14"));
REQUIRE(isFloat("3e-14"));
REQUIRE(isFloat("3e+14"));
}
SECTION("Integer") {
REQUIRE(isFloat("14"));
REQUIRE(isFloat("-14"));
REQUIRE(isFloat("+14"));
}
SECTION("ExponentMissing") {
REQUIRE_FALSE(isFloat("3.14e"));
REQUIRE_FALSE(isFloat("3.14e-"));
REQUIRE_FALSE(isFloat("3.14e+"));
}
SECTION("JustASign") {
REQUIRE_FALSE(isFloat("-"));
REQUIRE_FALSE(isFloat("+"));
}
SECTION("Empty") {
REQUIRE_FALSE(isFloat(""));
}
SECTION("NaN") {
REQUIRE(isFloat("NaN"));
REQUIRE_FALSE(isFloat("n"));
REQUIRE_FALSE(isFloat("N"));
REQUIRE_FALSE(isFloat("nan"));
REQUIRE_FALSE(isFloat("-NaN"));
REQUIRE_FALSE(isFloat("+NaN"));
}
SECTION("Infinity") {
REQUIRE(isFloat("Infinity"));
REQUIRE(isFloat("+Infinity"));
REQUIRE(isFloat("-Infinity"));
REQUIRE_FALSE(isFloat("infinity"));
REQUIRE_FALSE(isFloat("Inf"));
}
}

View File

@ -1,36 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Numbers/isInteger.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("isInteger()") {
SECTION("Null") {
REQUIRE_FALSE(isInteger(NULL));
}
SECTION("FloatNotInteger") {
REQUIRE_FALSE(isInteger("3.14"));
REQUIRE_FALSE(isInteger("-3.14"));
REQUIRE_FALSE(isInteger("+3.14"));
}
SECTION("Spaces") {
REQUIRE_FALSE(isInteger("42 "));
REQUIRE_FALSE(isInteger(" 42"));
}
SECTION("Valid") {
REQUIRE(isInteger("42"));
REQUIRE(isInteger("-42"));
REQUIRE(isInteger("+42"));
}
SECTION("ExtraSign") {
REQUIRE_FALSE(isInteger("--42"));
REQUIRE_FALSE(isInteger("++42"));
}
}