mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-04 14:16:36 +02:00
Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
fec088e3ed | |||
4980ee8fb9 | |||
2ed77d2cc3 | |||
630107ae8a | |||
4eb8074358 | |||
80a02cd90d | |||
7427888e05 | |||
90c1d549a8 | |||
2af003e4e2 | |||
eaf55e174b | |||
0588e578d5 | |||
12f9aac4ea | |||
81bb3fce97 | |||
6011a2f51a | |||
6071bd07ec | |||
1c814d3bb6 | |||
9862048a58 | |||
ebc52a5a65 | |||
eacad922df | |||
d910996613 | |||
2fc220fa33 | |||
8cabda551d |
17
.travis.yml
17
.travis.yml
@ -31,7 +31,7 @@ matrix:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-5']
|
||||
env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 # SANITIZE=undefined
|
||||
env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 # SANITIZE=undefined
|
||||
- addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
@ -42,6 +42,11 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-7']
|
||||
env: SCRIPT=test _CC=gcc-7 _CXX=g++-7
|
||||
- addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-8']
|
||||
env: SCRIPT=test _CC=gcc-8 _CXX=g++-8
|
||||
- addons:
|
||||
apt:
|
||||
packages: ['g++-arm-linux-gnueabihf']
|
||||
@ -87,6 +92,16 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-6.0']
|
||||
packages: ['clang-6.0']
|
||||
env: SCRIPT=test _CC=clang-6.0 _CXX=clang++-6.0
|
||||
- addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-7']
|
||||
packages: ['clang-7']
|
||||
env: SCRIPT=test _CC=clang-7 _CXX=clang++-7
|
||||
- addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-8']
|
||||
packages: ['clang-8']
|
||||
env: SCRIPT=test _CC=clang-8 _CXX=clang++-8
|
||||
- env: SCRIPT=coverage
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
|
61
CHANGELOG.md
61
CHANGELOG.md
@ -1,6 +1,67 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v6.11.0 (2019-05-26)
|
||||
-------
|
||||
|
||||
* Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978)
|
||||
* Fixed invalid result from `operator|` (issue #981)
|
||||
* Made `deserializeJson()` more picky about trailing characters (issue #980)
|
||||
* Added `ARDUINOJSON_ENABLE_NAN` (default=0) to enable NaN in JSON (issue #973)
|
||||
* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
|
||||
* Removed implicit conversion in comparison operators (issue #998)
|
||||
* Added lexicographical comparison for `JsonVariant`
|
||||
* Added support for `nullptr` (issue #998)
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> #### NaN and Infinity
|
||||
>
|
||||
> The JSON specification allows neither NaN not Infinity, but previous
|
||||
> versions of ArduinoJson supported it. Now, ArduinoJson behaves like most
|
||||
> other libraries: a NaN or and Infinity in the `JsonDocument`, becomes
|
||||
> a `null` in the output JSON. Also, `deserializeJson()` returns
|
||||
> `InvalidInput` if the JSON document contains NaN or Infinity.
|
||||
>
|
||||
> This version still supports NaN and Infinity in JSON documents, but
|
||||
> it's disabled by default to be compatible with other JSON parsers.
|
||||
> If you need the old behavior back, define `ARDUINOJSON_ENABLE_NAN` and
|
||||
> `ARDUINOJSON_ENABLE_INFINITY` to `1`;:
|
||||
>
|
||||
> ```c++
|
||||
> #define ARDUINOJSON_ENABLE_NAN 1
|
||||
> #define ARDUINOJSON_ENABLE_INFINITY 1
|
||||
> #include <ArduinoJson.h>
|
||||
> ```
|
||||
>
|
||||
> #### The "or" operator
|
||||
>
|
||||
> This version slightly changes the behavior of the | operator when the
|
||||
> variant contains a float and the user requests an integer.
|
||||
>
|
||||
> Older versions returned the floating point value truncated.
|
||||
> Now, it returns the default value.
|
||||
>
|
||||
> ```c++
|
||||
> // suppose variant contains 1.2
|
||||
> int value = variant | 3;
|
||||
>
|
||||
> // old behavior:
|
||||
> value == 1
|
||||
>
|
||||
> // new behavior
|
||||
> value == 3
|
||||
> ```
|
||||
>
|
||||
> If you need the old behavior, you must add `if (variant.is<float>())`.
|
||||
|
||||
v6.10.1 (2019-04-23)
|
||||
-------
|
||||
|
||||
* Fixed error "attributes are not allowed on a function-definition"
|
||||
* Fixed `deserializeJson()` not being picky enough (issue #969)
|
||||
* Fixed error "no matching function for call to write(uint8_t)" (issue #972)
|
||||
|
||||
v6.10.0 (2019-03-22)
|
||||
-------
|
||||
|
||||
|
18
README.md
18
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
|
||||
[](https://www.ardu-badge.com/ArduinoJson/6.10.0)
|
||||
[](https://www.ardu-badge.com/ArduinoJson/6.11.0)
|
||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
||||
[](https://travis-ci.org/bblanchon/ArduinoJson)
|
||||
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
||||
@ -67,11 +67,10 @@ char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, json);
|
||||
|
||||
JsonObjectRef root = doc.as<JsonObject>();
|
||||
const char* sensor = root["sensor"];
|
||||
long time = root["time"];
|
||||
double latitude = root["data"][0];
|
||||
double longitude = root["data"][1];
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/decoding/?utm_source=github&utm_medium=readme)
|
||||
@ -83,11 +82,10 @@ Here is a program that generates a JSON document with ArduinoJson:
|
||||
```c++
|
||||
DynamicJsonDocument doc(1024);
|
||||
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
root["sensor"] = "gps";
|
||||
root["time"] = 1351824120;
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
|
||||
JsonArray data = root.createNestedArray("data");
|
||||
JsonArray data = doc.createNestedArray("data");
|
||||
data.add(48.756080);
|
||||
data.add(2.302038);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 6.9.1.{build}
|
||||
version: 6.11.0.{build}
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
@ -17,4 +17,4 @@ before_build:
|
||||
build_script:
|
||||
- cmake --build . --config %CONFIGURATION%
|
||||
test_script:
|
||||
- ctest --output-on-failure .
|
||||
- ctest -C %CONFIGURATION% --output-on-failure .
|
||||
|
@ -21,7 +21,8 @@
|
||||
//
|
||||
// Never use a JsonDocument to store the configuration!
|
||||
// A JsonDocument is *not* a permanent storage; it's only a temporary storage
|
||||
// used during the serialization phase.
|
||||
// used during the serialization phase. See:
|
||||
// https://arduinojson.org/v6/faq/why-must-i-create-a-separate-config-object/
|
||||
struct Config {
|
||||
char hostname[64];
|
||||
int port;
|
||||
|
@ -59,7 +59,8 @@ void setup() {
|
||||
// Check HTTP status
|
||||
char status[32] = {0};
|
||||
client.readBytesUntil('\r', status, sizeof(status));
|
||||
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
|
||||
// It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
|
||||
if (strcmp(status + 9, "200 OK") != 0) {
|
||||
Serial.print(F("Unexpected response: "));
|
||||
Serial.println(status);
|
||||
return;
|
||||
|
@ -7,7 +7,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||
},
|
||||
"version": "6.10.0",
|
||||
"version": "6.11.0",
|
||||
"authors": {
|
||||
"name": "Benoit Blanchon",
|
||||
"url": "https://blog.benoitblanchon.fr"
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ArduinoJson
|
||||
version=6.10.0
|
||||
version=6.11.0
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=An efficient and elegant JSON library for Arduino.
|
||||
|
@ -38,7 +38,7 @@ update_version_in_source () {
|
||||
}
|
||||
|
||||
commit_new_version () {
|
||||
git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties
|
||||
git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml
|
||||
git commit -m "Set version to $VERSION"
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,18 @@ pip install --user platformio
|
||||
|
||||
rm -r test
|
||||
|
||||
case $BOARD in
|
||||
uno)
|
||||
platformio lib install 868 # SD library
|
||||
platformio lib install 872 # Ethernet library
|
||||
;;
|
||||
esp01)
|
||||
platformio lib uninstall 161 || true
|
||||
platformio lib uninstall 868 || true
|
||||
platformio lib uninstall 872 || true
|
||||
;;
|
||||
esac
|
||||
|
||||
for EXAMPLE in $PWD/examples/*/*.ino;
|
||||
do
|
||||
platformio ci $EXAMPLE -l '.' -b $BOARD
|
||||
|
@ -12,8 +12,10 @@
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define ARDUINOJSON_HAS_LONG_LONG 1
|
||||
#define ARDUINOJSON_HAS_NULLPTR 1
|
||||
#else
|
||||
#define ARDUINOJSON_HAS_LONG_LONG 0
|
||||
#define ARDUINOJSON_HAS_NULLPTR 0
|
||||
#endif
|
||||
|
||||
// Small or big machine?
|
||||
@ -88,28 +90,38 @@
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
// Enable support for Arduino String
|
||||
// Enable support for Arduino's String class
|
||||
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||
#endif
|
||||
|
||||
// Enable support for Arduino Stream
|
||||
// Enable support for Arduino's Stream class
|
||||
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
|
||||
#endif
|
||||
|
||||
// Enable support for Arduino's Print class
|
||||
#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1
|
||||
#endif
|
||||
|
||||
#else // ARDUINO
|
||||
|
||||
// Disable support for Arduino String
|
||||
// Enable support for Arduino's String class
|
||||
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
||||
#endif
|
||||
|
||||
// Disable support for Arduino Stream
|
||||
// Enable support for Arduino's Stream class
|
||||
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
||||
#endif
|
||||
|
||||
// Enable support for Arduino's Print class
|
||||
#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
|
||||
#endif
|
||||
|
||||
#endif // ARDUINO
|
||||
|
||||
#ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||
@ -125,6 +137,16 @@
|
||||
#define ARDUINOJSON_DECODE_UNICODE 0
|
||||
#endif
|
||||
|
||||
// Support NaN in JSON
|
||||
#ifndef ARDUINOJSON_ENABLE_NAN
|
||||
#define ARDUINOJSON_ENABLE_NAN 0
|
||||
#endif
|
||||
|
||||
// Support Infinity in JSON
|
||||
#ifndef ARDUINOJSON_ENABLE_INFINITY
|
||||
#define ARDUINOJSON_ENABLE_INFINITY 0
|
||||
#endif
|
||||
|
||||
// Control the exponentiation threshold for big numbers
|
||||
// CAUTION: cannot be more that 1e9 !!!!
|
||||
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
|
||||
|
@ -12,22 +12,14 @@ namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
struct ArduinoStreamReader {
|
||||
Stream& _stream;
|
||||
char _current;
|
||||
bool _ended;
|
||||
|
||||
public:
|
||||
explicit ArduinoStreamReader(Stream& stream)
|
||||
: _stream(stream), _current(0), _ended(false) {}
|
||||
explicit ArduinoStreamReader(Stream& stream) : _stream(stream) {}
|
||||
|
||||
char read() {
|
||||
int read() {
|
||||
// don't use _stream.read() as it ignores the timeout
|
||||
char c = 0;
|
||||
_ended = _stream.readBytes(&c, 1) == 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
bool ended() const {
|
||||
return _ended;
|
||||
uint8_t c;
|
||||
return _stream.readBytes(&c, 1) ? c : -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,16 @@
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename T>
|
||||
struct IsCharOrVoid {
|
||||
static const bool value =
|
||||
is_same<T, void>::value || is_same<T, char>::value ||
|
||||
is_same<T, unsigned char>::value || is_same<T, signed char>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
|
||||
|
||||
class UnsafeCharPointerReader {
|
||||
const char* _ptr;
|
||||
|
||||
@ -13,13 +23,8 @@ class UnsafeCharPointerReader {
|
||||
explicit UnsafeCharPointerReader(const char* ptr)
|
||||
: _ptr(ptr ? ptr : reinterpret_cast<const char*>("")) {}
|
||||
|
||||
char read() {
|
||||
return static_cast<char>(*_ptr++);
|
||||
}
|
||||
|
||||
bool ended() const {
|
||||
// we cannot know, that's why it's unsafe
|
||||
return false;
|
||||
int read() {
|
||||
return static_cast<unsigned char>(*_ptr++);
|
||||
}
|
||||
};
|
||||
|
||||
@ -31,22 +36,25 @@ class SafeCharPointerReader {
|
||||
explicit SafeCharPointerReader(const char* ptr, size_t len)
|
||||
: _ptr(ptr ? ptr : reinterpret_cast<const char*>("")), _end(_ptr + len) {}
|
||||
|
||||
char read() {
|
||||
return static_cast<char>(*_ptr++);
|
||||
}
|
||||
|
||||
bool ended() const {
|
||||
return _ptr == _end;
|
||||
int read() {
|
||||
if (_ptr < _end)
|
||||
return static_cast<unsigned char>(*_ptr++);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TChar>
|
||||
inline UnsafeCharPointerReader makeReader(TChar* input) {
|
||||
inline typename enable_if<IsCharOrVoid<TChar>::value,
|
||||
UnsafeCharPointerReader>::type
|
||||
makeReader(TChar* input) {
|
||||
return UnsafeCharPointerReader(reinterpret_cast<const char*>(input));
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
inline SafeCharPointerReader makeReader(TChar* input, size_t n) {
|
||||
inline
|
||||
typename enable_if<IsCharOrVoid<TChar>::value, SafeCharPointerReader>::type
|
||||
makeReader(TChar* input, size_t n) {
|
||||
return SafeCharPointerReader(reinterpret_cast<const char*>(input), n);
|
||||
}
|
||||
|
||||
|
@ -14,14 +14,9 @@ class UnsafeFlashStringReader {
|
||||
explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr)
|
||||
: _ptr(reinterpret_cast<const char*>(ptr)) {}
|
||||
|
||||
char read() {
|
||||
int read() {
|
||||
return pgm_read_byte_near(_ptr++);
|
||||
}
|
||||
|
||||
bool ended() const {
|
||||
// this reader cannot detect the end
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlashStringReader {
|
||||
@ -32,12 +27,11 @@ class SafeFlashStringReader {
|
||||
explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size)
|
||||
: _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {}
|
||||
|
||||
char read() {
|
||||
return pgm_read_byte_near(_ptr++);
|
||||
}
|
||||
|
||||
bool ended() const {
|
||||
return _ptr == _end;
|
||||
int read() {
|
||||
if (_ptr < _end)
|
||||
return pgm_read_byte_near(_ptr++);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,12 +14,11 @@ class IteratorReader {
|
||||
explicit IteratorReader(TIterator begin, TIterator end)
|
||||
: _ptr(begin), _end(end) {}
|
||||
|
||||
bool ended() const {
|
||||
return _ptr == _end;
|
||||
}
|
||||
|
||||
char read() {
|
||||
return char(*_ptr++);
|
||||
int read() {
|
||||
if (_ptr < _end)
|
||||
return static_cast<unsigned char>(*_ptr++);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -18,12 +18,8 @@ class StdStreamReader {
|
||||
explicit StdStreamReader(std::istream& stream)
|
||||
: _stream(stream), _current(0) {}
|
||||
|
||||
bool ended() const {
|
||||
return _stream.eof();
|
||||
}
|
||||
|
||||
char read() {
|
||||
return static_cast<char>(_stream.get());
|
||||
int read() {
|
||||
return _stream.get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -28,19 +28,14 @@ class JsonDeserializer {
|
||||
_nestingLimit(nestingLimit),
|
||||
_loaded(false) {}
|
||||
DeserializationError parse(VariantData &variant) {
|
||||
DeserializationError err = skipSpacesAndComments();
|
||||
if (err) return err;
|
||||
DeserializationError err = parseVariant(variant);
|
||||
|
||||
switch (current()) {
|
||||
case '[':
|
||||
return parseArray(variant.toArray());
|
||||
|
||||
case '{':
|
||||
return parseObject(variant.toObject());
|
||||
|
||||
default:
|
||||
return parseValue(variant);
|
||||
if (!err && _current != 0 && !variant.isEnclosed()) {
|
||||
// We don't detect trailing characters earlier, so we need to check now
|
||||
err = DeserializationError::InvalidInput;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -48,10 +43,8 @@ class JsonDeserializer {
|
||||
|
||||
char current() {
|
||||
if (!_loaded) {
|
||||
if (_reader.ended())
|
||||
_current = 0;
|
||||
else
|
||||
_current = _reader.read();
|
||||
int c = _reader.read();
|
||||
_current = static_cast<char>(c > 0 ? c : 0);
|
||||
_loaded = true;
|
||||
}
|
||||
return _current;
|
||||
@ -67,6 +60,26 @@ class JsonDeserializer {
|
||||
return true;
|
||||
}
|
||||
|
||||
DeserializationError parseVariant(VariantData &variant) {
|
||||
DeserializationError err = skipSpacesAndComments();
|
||||
if (err) return err;
|
||||
|
||||
switch (current()) {
|
||||
case '[':
|
||||
return parseArray(variant.toArray());
|
||||
|
||||
case '{':
|
||||
return parseObject(variant.toObject());
|
||||
|
||||
case '\"':
|
||||
case '\'':
|
||||
return parseStringValue(variant);
|
||||
|
||||
default:
|
||||
return parseNumericValue(variant);
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError parseArray(CollectionData &array) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
|
||||
@ -88,7 +101,7 @@ class JsonDeserializer {
|
||||
|
||||
// 1 - Parse value
|
||||
_nestingLimit--;
|
||||
err = parse(*value);
|
||||
err = parseVariant(*value);
|
||||
_nestingLimit++;
|
||||
if (err) return err;
|
||||
|
||||
@ -134,7 +147,7 @@ class JsonDeserializer {
|
||||
|
||||
// Parse value
|
||||
_nestingLimit--;
|
||||
err = parse(*slot->data());
|
||||
err = parseVariant(*slot->data());
|
||||
_nestingLimit++;
|
||||
if (err) return err;
|
||||
|
||||
@ -152,14 +165,6 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError parseValue(VariantData &variant) {
|
||||
if (isQuote(current())) {
|
||||
return parseStringValue(variant);
|
||||
} else {
|
||||
return parseNumericValue(variant);
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError parseKey(const char *&key) {
|
||||
if (isQuote(current())) {
|
||||
return parseQuotedString(key);
|
||||
|
@ -52,14 +52,23 @@ class TextFormatter {
|
||||
|
||||
template <typename T>
|
||||
void writeFloat(T value) {
|
||||
if (isnan(value)) return writeRaw("NaN");
|
||||
if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
||||
|
||||
#if ARDUINOJSON_ENABLE_INFINITY
|
||||
if (value < 0.0) {
|
||||
writeRaw('-');
|
||||
value = -value;
|
||||
}
|
||||
|
||||
if (isinf(value)) return writeRaw("Infinity");
|
||||
#else
|
||||
if (isinf(value)) return writeRaw("null");
|
||||
|
||||
if (value < 0.0) {
|
||||
writeRaw('-');
|
||||
value = -value;
|
||||
}
|
||||
#endif
|
||||
|
||||
FloatParts<T> parts(value);
|
||||
|
||||
|
@ -134,17 +134,10 @@ class MsgPackDeserializer {
|
||||
// Prevent VS warning "assignment operator could not be generated"
|
||||
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
|
||||
|
||||
bool skip(uint8_t n) {
|
||||
while (n--) {
|
||||
if (_reader.ended()) return false;
|
||||
_reader.read();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readByte(uint8_t &value) {
|
||||
if (_reader.ended()) return false;
|
||||
value = static_cast<uint8_t>(_reader.read());
|
||||
int c = _reader.read();
|
||||
if (c < 0) return false;
|
||||
value = static_cast<uint8_t>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@ class MsgPackSerializer {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8>::type visitFloat(T value64)
|
||||
ARDUINOJSON_NO_SANITIZE("float-cast-overflow") {
|
||||
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
|
||||
typename enable_if<sizeof(T) == 8>::type visitFloat(T value64) {
|
||||
float value32 = float(value64);
|
||||
if (value32 == value64) {
|
||||
writeByte(0xCA);
|
||||
|
@ -10,14 +10,19 @@
|
||||
|
||||
#define ARDUINOJSON_DO_CONCAT(A, B) A##B
|
||||
#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_DO_CONCAT(A, B)
|
||||
#define ARDUINOJSON_CONCAT3(A, B, C) \
|
||||
ARDUINOJSON_CONCAT2(A, ARDUINOJSON_CONCAT2(B, C))
|
||||
#define ARDUINOJSON_CONCAT4(A, B, C, D) \
|
||||
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D))
|
||||
#define ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, H) \
|
||||
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \
|
||||
ARDUINOJSON_CONCAT4(E, F, G, H))
|
||||
#define ARDUINOJSON_CONCAT10(A, B, C, D, E, F, G, H, I, J) \
|
||||
ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, ARDUINOJSON_CONCAT3(H, I, J))
|
||||
|
||||
#define ARDUINOJSON_NAMESPACE \
|
||||
ARDUINOJSON_CONCAT8(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \
|
||||
ARDUINOJSON_VERSION_MINOR, ARDUINOJSON_VERSION_REVISION, \
|
||||
_, ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \
|
||||
ARDUINOJSON_DECODE_UNICODE)
|
||||
#define ARDUINOJSON_NAMESPACE \
|
||||
ARDUINOJSON_CONCAT10( \
|
||||
ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \
|
||||
ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \
|
||||
ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \
|
||||
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY)
|
||||
|
@ -72,9 +72,15 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
||||
break;
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_NAN
|
||||
if (*s == 'n' || *s == 'N') return traits::nan();
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_INFINITY
|
||||
if (*s == 'i' || *s == 'I')
|
||||
return is_negative ? -traits::inf() : traits::inf();
|
||||
#endif
|
||||
|
||||
if (!isdigit(*s) && *s != '.') return return_type();
|
||||
|
||||
mantissa_t mantissa = 0;
|
||||
@ -140,6 +146,9 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
||||
}
|
||||
exponent += exponent_offset;
|
||||
|
||||
// we should be at the end of the string, otherwise it's an error
|
||||
if (*s != '\0') return return_type();
|
||||
|
||||
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent);
|
||||
|
||||
return is_negative ? -result : result;
|
||||
|
@ -7,154 +7,237 @@
|
||||
#include "../Variant/VariantRef.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct Comparer;
|
||||
|
||||
template <typename T>
|
||||
struct is_simple_value {
|
||||
static const bool value = is_integral<T>::value ||
|
||||
is_floating_point<T>::value ||
|
||||
is_same<T, bool>::value;
|
||||
struct Comparer<T, typename enable_if<IsString<T>::value>::type> {
|
||||
T rhs;
|
||||
int result;
|
||||
|
||||
explicit Comparer(T value) : rhs(value), result(1) {}
|
||||
|
||||
void visitArray(const CollectionData &) {}
|
||||
void visitObject(const CollectionData &) {}
|
||||
void visitFloat(Float) {}
|
||||
void visitString(const char *lhs) {
|
||||
result = -adaptString(rhs).compare(lhs);
|
||||
}
|
||||
void visitRawJson(const char *, size_t) {}
|
||||
void visitNegativeInteger(UInt) {}
|
||||
void visitPositiveInteger(UInt) {}
|
||||
void visitBoolean(bool) {}
|
||||
void visitNull() {
|
||||
result = adaptString(rhs).compare(NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_signed<T>::value, int>::type sign(const T &value) {
|
||||
return value < 0 ? -1 : value > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_unsigned<T>::value, int>::type sign(const T &value) {
|
||||
return value > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct Comparer<T, typename enable_if<is_integral<T>::value ||
|
||||
is_floating_point<T>::value>::type> {
|
||||
T rhs;
|
||||
int result;
|
||||
|
||||
explicit Comparer(T value) : rhs(value), result(1) {}
|
||||
|
||||
void visitArray(const CollectionData &) {}
|
||||
void visitObject(const CollectionData &) {}
|
||||
void visitFloat(Float lhs) {
|
||||
result = sign(lhs - static_cast<Float>(rhs));
|
||||
}
|
||||
void visitString(const char *) {}
|
||||
void visitRawJson(const char *, size_t) {}
|
||||
void visitNegativeInteger(UInt lhs) {
|
||||
result = -sign(static_cast<T>(lhs) + rhs);
|
||||
}
|
||||
void visitPositiveInteger(UInt lhs) {
|
||||
result = static_cast<T>(lhs) < rhs ? -1 : static_cast<T>(lhs) > rhs ? 1 : 0;
|
||||
}
|
||||
void visitBoolean(bool) {}
|
||||
void visitNull() {}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Comparer<bool, void> {
|
||||
bool rhs;
|
||||
int result;
|
||||
|
||||
explicit Comparer(bool value) : rhs(value), result(1) {}
|
||||
|
||||
void visitArray(const CollectionData &) {}
|
||||
void visitObject(const CollectionData &) {}
|
||||
void visitFloat(Float) {}
|
||||
void visitString(const char *) {}
|
||||
void visitRawJson(const char *, size_t) {}
|
||||
void visitNegativeInteger(UInt) {}
|
||||
void visitPositiveInteger(UInt) {}
|
||||
void visitBoolean(bool lhs) {
|
||||
result = static_cast<int>(lhs - rhs);
|
||||
}
|
||||
void visitNull() {}
|
||||
};
|
||||
|
||||
#if ARDUINOJSON_HAS_NULLPTR
|
||||
template <>
|
||||
struct Comparer<decltype(nullptr), void> {
|
||||
int result;
|
||||
|
||||
explicit Comparer(decltype(nullptr)) : result(1) {}
|
||||
|
||||
void visitArray(const CollectionData &) {}
|
||||
void visitObject(const CollectionData &) {}
|
||||
void visitFloat(Float) {}
|
||||
void visitString(const char *) {}
|
||||
void visitRawJson(const char *, size_t) {}
|
||||
void visitNegativeInteger(UInt) {}
|
||||
void visitPositiveInteger(UInt) {}
|
||||
void visitBoolean(bool) {}
|
||||
void visitNull() {
|
||||
result = 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename TVariant>
|
||||
class VariantComparisons {
|
||||
private:
|
||||
template <typename T>
|
||||
static int compare(TVariant lhs, const T &rhs) {
|
||||
Comparer<T> comparer(rhs);
|
||||
lhs.accept(comparer);
|
||||
return comparer.result;
|
||||
}
|
||||
|
||||
public:
|
||||
// const char* == TVariant
|
||||
// value == TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T *>::value, bool>::type operator==(
|
||||
T *lhs, TVariant rhs) {
|
||||
return adaptString(lhs).equals(rhs.template as<const char *>());
|
||||
friend bool operator==(T *lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) == 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator==(const T &lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) == 0;
|
||||
}
|
||||
|
||||
// std::string == TVariant
|
||||
// TVariant == value
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T>::value, bool>::type operator==(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return adaptString(lhs).equals(rhs.template as<const char *>());
|
||||
friend bool operator==(TVariant lhs, T *rhs) {
|
||||
return compare(lhs, rhs) == 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator==(TVariant lhs, const T &rhs) {
|
||||
return compare(lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
// TVariant == const char*
|
||||
// value != TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T *>::value, bool>::type operator==(
|
||||
TVariant lhs, T *rhs) {
|
||||
return adaptString(rhs).equals(lhs.template as<const char *>());
|
||||
friend bool operator!=(T *lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator!=(const T &lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) != 0;
|
||||
}
|
||||
|
||||
// TVariant == std::string
|
||||
// TVariant != value
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T>::value, bool>::type operator==(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return adaptString(rhs).equals(lhs.template as<const char *>());
|
||||
friend bool operator!=(TVariant lhs, T *rhs) {
|
||||
return compare(lhs, rhs) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator!=(TVariant lhs, const T &rhs) {
|
||||
return compare(lhs, rhs) != 0;
|
||||
}
|
||||
|
||||
// bool/int/float == TVariant
|
||||
// value < TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator==(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return lhs == rhs.template as<T>();
|
||||
friend bool operator<(T *lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) > 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator<(const T &lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) > 0;
|
||||
}
|
||||
|
||||
// TVariant == bool/int/float
|
||||
// TVariant < value
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator==(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return lhs.template as<T>() == rhs;
|
||||
friend bool operator<(TVariant lhs, T *rhs) {
|
||||
return compare(lhs, rhs) < 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator<(TVariant lhs, const T &rhs) {
|
||||
return compare(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
// const char* != TVariant
|
||||
// value <= TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T *>::value, bool>::type operator!=(
|
||||
T *lhs, TVariant rhs) {
|
||||
return !adaptString(lhs).equals(rhs.template as<const char *>());
|
||||
friend bool operator<=(T *lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) >= 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator<=(const T &lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) >= 0;
|
||||
}
|
||||
|
||||
// std::string != TVariant
|
||||
// TVariant <= value
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T>::value, bool>::type operator!=(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return !adaptString(lhs).equals(rhs.template as<const char *>());
|
||||
friend bool operator<=(TVariant lhs, T *rhs) {
|
||||
return compare(lhs, rhs) <= 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator<=(TVariant lhs, const T &rhs) {
|
||||
return compare(lhs, rhs) <= 0;
|
||||
}
|
||||
|
||||
// TVariant != const char*
|
||||
// value > TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T *>::value, bool>::type operator!=(
|
||||
TVariant lhs, T *rhs) {
|
||||
return !adaptString(rhs).equals(lhs.template as<const char *>());
|
||||
friend bool operator>(T *lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) < 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator>(const T &lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) < 0;
|
||||
}
|
||||
|
||||
// TVariant != std::string
|
||||
// TVariant > value
|
||||
template <typename T>
|
||||
friend typename enable_if<IsString<T>::value, bool>::type operator!=(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return !adaptString(rhs).equals(lhs.template as<const char *>());
|
||||
friend bool operator>(TVariant lhs, T *rhs) {
|
||||
return compare(lhs, rhs) > 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator>(TVariant lhs, const T &rhs) {
|
||||
return compare(lhs, rhs) > 0;
|
||||
}
|
||||
|
||||
// bool/int/float != TVariant
|
||||
// value >= TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return lhs != rhs.template as<T>();
|
||||
friend bool operator>=(T *lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) <= 0;
|
||||
}
|
||||
template <typename T>
|
||||
friend bool operator>=(const T &lhs, TVariant rhs) {
|
||||
return compare(rhs, lhs) <= 0;
|
||||
}
|
||||
|
||||
// TVariant != bool/int/float
|
||||
// TVariant >= value
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return lhs.template as<T>() != rhs;
|
||||
friend bool operator>=(TVariant lhs, T *rhs) {
|
||||
return compare(lhs, rhs) >= 0;
|
||||
}
|
||||
|
||||
// bool/int/float < TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return lhs < rhs.template as<T>();
|
||||
}
|
||||
|
||||
// TVariant < bool/int/float
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return lhs.template as<T>() < rhs;
|
||||
}
|
||||
|
||||
// bool/int/float <= TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<=(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return lhs <= rhs.template as<T>();
|
||||
}
|
||||
|
||||
// TVariant <= bool/int/float
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<=(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return lhs.template as<T>() <= rhs;
|
||||
}
|
||||
|
||||
// bool/int/float > TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return lhs > rhs.template as<T>();
|
||||
}
|
||||
|
||||
// TVariant > bool/int/float
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return lhs.template as<T>() > rhs;
|
||||
}
|
||||
|
||||
// bool/int/float >= TVariant
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>=(
|
||||
const T &lhs, TVariant rhs) {
|
||||
return lhs >= rhs.template as<T>();
|
||||
}
|
||||
|
||||
// TVariant >= bool/int/float
|
||||
template <typename T>
|
||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>=(
|
||||
TVariant lhs, const T &rhs) {
|
||||
return lhs.template as<T>() >= rhs;
|
||||
friend bool operator>=(TVariant lhs, const T &rhs) {
|
||||
return compare(lhs, rhs) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -15,8 +15,7 @@ class VariantOr {
|
||||
public:
|
||||
// Returns the default value if the VariantRef is undefined of incompatible
|
||||
template <typename T>
|
||||
typename enable_if<!is_integral<T>::value, T>::type operator|(
|
||||
const T &defaultValue) const {
|
||||
T operator|(const T &defaultValue) const {
|
||||
if (impl()->template is<T>())
|
||||
return impl()->template as<T>();
|
||||
else
|
||||
@ -30,17 +29,6 @@ class VariantOr {
|
||||
return value ? value : defaultValue;
|
||||
}
|
||||
|
||||
// Returns the default value if the VariantRef is undefined of incompatible
|
||||
// Special case for integers: we also accept double
|
||||
template <typename Integer>
|
||||
typename enable_if<is_integral<Integer>::value, Integer>::type operator|(
|
||||
const Integer &defaultValue) const {
|
||||
if (impl()->template is<double>())
|
||||
return impl()->template as<Integer>();
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private:
|
||||
const TImpl *impl() const {
|
||||
return static_cast<const TImpl *>(this);
|
||||
|
22
src/ArduinoJson/Polyfills/safe_strcmp.hpp
Normal file
22
src/ArduinoJson/Polyfills/safe_strcmp.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
inline int8_t safe_strcmp(const char* a, const char* b) {
|
||||
if (a == b) return 0;
|
||||
if (!a) return -1;
|
||||
if (!b) return 1;
|
||||
return static_cast<int8_t>(strcmp(a, b));
|
||||
}
|
||||
|
||||
inline int8_t safe_strncmp(const char* a, const char* b, size_t n) {
|
||||
if (a == b) return 0;
|
||||
if (!a) return -1;
|
||||
if (!b) return 1;
|
||||
return static_cast<int8_t>(strncmp(a, b, n));
|
||||
}
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
@ -14,32 +14,38 @@
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <template <typename> class TSerializer, typename TSource,
|
||||
typename TPrint>
|
||||
typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize(
|
||||
const TSource &source, TPrint &destination) {
|
||||
TSerializer<TPrint> serializer(destination);
|
||||
typename TDestination>
|
||||
size_t doSerialize(const TSource &source, TDestination &destination) {
|
||||
TSerializer<TDestination> serializer(destination);
|
||||
source.accept(serializer);
|
||||
return serializer.bytesWritten();
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
template <template <typename> class TSerializer, typename TSource>
|
||||
size_t serialize(const TSource &source, std::ostream &os) {
|
||||
StreamWriter writer(os);
|
||||
return serialize<TSerializer>(source, writer);
|
||||
size_t serialize(const TSource &source, std::ostream &destination) {
|
||||
StreamWriter writer(destination);
|
||||
return doSerialize<TSerializer>(source, writer);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
template <template <typename> class TSerializer, typename TSource>
|
||||
size_t serialize(const TSource &source, Print &destination) {
|
||||
return doSerialize<TSerializer>(source, destination);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <template <typename> class TSerializer, typename TSource>
|
||||
size_t serialize(const TSource &source, char *buffer, size_t bufferSize) {
|
||||
StaticStringWriter writer(buffer, bufferSize);
|
||||
return serialize<TSerializer>(source, writer);
|
||||
return doSerialize<TSerializer>(source, writer);
|
||||
}
|
||||
|
||||
template <template <typename> class TSerializer, typename TSource, size_t N>
|
||||
size_t serialize(const TSource &source, char (&buffer)[N]) {
|
||||
StaticStringWriter writer(buffer, N);
|
||||
return serialize<TSerializer>(source, writer);
|
||||
return doSerialize<TSerializer>(source, writer);
|
||||
}
|
||||
|
||||
template <template <typename> class TSerializer, typename TSource,
|
||||
@ -47,7 +53,7 @@ template <template <typename> class TSerializer, typename TSource,
|
||||
typename enable_if<IsWriteableString<TString>::value, size_t>::type serialize(
|
||||
const TSource &source, TString &str) {
|
||||
DynamicStringWriter<TString> writer(str);
|
||||
return serialize<TSerializer>(source, writer);
|
||||
return doSerialize<TSerializer>(source, writer);
|
||||
}
|
||||
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <WString.h>
|
||||
#include "../Polyfills/safe_strcmp.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
@ -25,11 +26,14 @@ class ArduinoStringAdapter {
|
||||
return !_str->c_str();
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
int8_t compare(const char* other) 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* me = _str->c_str();
|
||||
return safe_strcmp(me, other);
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
return compare(expected) == 0;
|
||||
}
|
||||
|
||||
const char* data() const {
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <string.h> // strcmp
|
||||
#include "../Polyfills/safe_strcmp.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
@ -13,10 +14,12 @@ class ConstRamStringAdapter {
|
||||
public:
|
||||
ConstRamStringAdapter(const char* str = 0) : _str(str) {}
|
||||
|
||||
int8_t compare(const char* other) const {
|
||||
return safe_strcmp(_str, other);
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
const char* actual = _str;
|
||||
if (!actual || !expected) return actual == expected;
|
||||
return strcmp(actual, expected) == 0;
|
||||
return compare(expected) == 0;
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
|
@ -10,10 +10,15 @@ class FlashStringAdapter {
|
||||
public:
|
||||
FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {}
|
||||
|
||||
int8_t compare(const char* other) const {
|
||||
if (!other && !_str) return 0;
|
||||
if (!_str) return -1;
|
||||
if (!other) return 1;
|
||||
return -strcmp_P(other, reinterpret_cast<const char*>(_str));
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
const char* actual = reinterpret_cast<const char*>(_str);
|
||||
if (!actual || !expected) return actual == expected;
|
||||
return strcmp_P(expected, actual) == 0;
|
||||
return compare(expected) == 0;
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
|
@ -11,10 +11,15 @@ class SizedFlashStringAdapter {
|
||||
SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz)
|
||||
: _str(str), _size(sz) {}
|
||||
|
||||
int8_t compare(const char* other) const {
|
||||
if (!other && !_str) return 0;
|
||||
if (!_str) return -1;
|
||||
if (!other) return 1;
|
||||
return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size);
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
const char* actual = reinterpret_cast<const char*>(_str);
|
||||
if (!actual || !expected) return actual == expected;
|
||||
return strncmp_P(expected, actual, _size) == 0;
|
||||
return compare(expected) == 0;
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
|
@ -12,10 +12,12 @@ class SizedRamStringAdapter {
|
||||
public:
|
||||
SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {}
|
||||
|
||||
int8_t compare(const char* other) const {
|
||||
return safe_strncmp(_str, other, _size) == 0;
|
||||
}
|
||||
|
||||
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;
|
||||
return compare(expected) == 0;
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
|
@ -23,6 +23,11 @@ class StlStringAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
int8_t compare(const char* other) const {
|
||||
if (!other) return 1;
|
||||
return static_cast<int8_t>(_str->compare(other));
|
||||
}
|
||||
|
||||
bool equals(const char* expected) const {
|
||||
if (!expected) return false;
|
||||
return *_str == expected;
|
||||
|
@ -177,6 +177,10 @@ class VariantData {
|
||||
return type() == VALUE_IS_NULL;
|
||||
}
|
||||
|
||||
bool isEnclosed() const {
|
||||
return isCollection() || isString();
|
||||
}
|
||||
|
||||
void remove(size_t index) {
|
||||
if (isArray()) _content.asCollection.remove(index);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ARDUINOJSON_VERSION "6.10.0"
|
||||
#define ARDUINOJSON_VERSION "6.11.0"
|
||||
#define ARDUINOJSON_VERSION_MAJOR 6
|
||||
#define ARDUINOJSON_VERSION_MINOR 10
|
||||
#define ARDUINOJSON_VERSION_MINOR 11
|
||||
#define ARDUINOJSON_VERSION_REVISION 0
|
||||
|
@ -7,8 +7,9 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("Invalid JSON input") {
|
||||
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'",
|
||||
"'\\u000G'", "'\\u000/'", "\\x1234"};
|
||||
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'",
|
||||
"'\\u000/'", "\\x1234", "6a9", "1,",
|
||||
"2]", "3}"};
|
||||
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
|
||||
|
||||
DynamicJsonDocument doc(4096);
|
||||
|
@ -3,6 +3,8 @@
|
||||
// MIT License
|
||||
|
||||
#define ARDUINOJSON_USE_LONG_LONG 0
|
||||
#define ARDUINOJSON_ENABLE_NAN 1
|
||||
#define ARDUINOJSON_ENABLE_INFINITY 1
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <limits.h>
|
||||
|
@ -161,7 +161,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
obj[null] = 666;
|
||||
|
||||
REQUIRE(obj.size() == 1);
|
||||
REQUIRE(obj[null] == 0);
|
||||
REQUIRE(obj[null] == null);
|
||||
}
|
||||
|
||||
SECTION("obj[key].to<JsonArray>()") {
|
||||
|
@ -229,8 +229,13 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("Variants containing linked strings") {
|
||||
variant1.set("0hello" + 1); // make sure they have
|
||||
variant2.set("1hello" + 1); // different addresses
|
||||
// create two identical strings at different addresses
|
||||
char hello1[] = "hello";
|
||||
char hello2[] = "hello";
|
||||
REQUIRE(hello1 != hello2);
|
||||
|
||||
variant1.set(hello1);
|
||||
variant2.set(hello2);
|
||||
variant3.set("world");
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
@ -253,8 +258,13 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
}
|
||||
|
||||
SECTION("Variants containing linked raws") {
|
||||
variant1.set(serialized("0hello" + 1)); // make sure they have
|
||||
variant2.set(serialized("1hello" + 1)); // different addresses
|
||||
// create two identical strings at different addresses
|
||||
char hello1[] = "hello";
|
||||
char hello2[] = "hello";
|
||||
REQUIRE(hello1 != hello2);
|
||||
|
||||
variant1.set(serialized(hello1));
|
||||
variant2.set(serialized(hello2));
|
||||
variant3.set(serialized("world"));
|
||||
|
||||
REQUIRE(variant1 == variant2);
|
||||
@ -327,23 +337,117 @@ TEST_CASE("JsonVariant comparisons") {
|
||||
REQUIRE(variant1 != variant3);
|
||||
REQUIRE_FALSE(variant1 == variant3);
|
||||
}
|
||||
|
||||
// SECTION("VariantsOfDifferentTypes") {
|
||||
// DynamicJsonDocument doc1(4096);
|
||||
// JsonObject obj = doc1.to<JsonObject>();
|
||||
|
||||
// DynamicJsonDocument doc2(4096);
|
||||
// JsonArray arr = doc2.to<JsonArray>();
|
||||
// JsonVariant variants[] = {
|
||||
// true, 42, 666.667, "hello", arr, obj,
|
||||
// };
|
||||
// size_t n = sizeof(variants) / sizeof(variants[0]);
|
||||
|
||||
// for (size_t i = 0; i < n; i++) {
|
||||
// for (size_t j = i + 1; j < n; j++) {
|
||||
// REQUIRE(variants[i] != variants[j]);
|
||||
// REQUIRE_FALSE(variants[i] == variants[j]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
class VariantComparisionFixture {
|
||||
private:
|
||||
StaticJsonDocument<256> doc;
|
||||
JsonVariant variant;
|
||||
|
||||
public:
|
||||
VariantComparisionFixture() : variant(doc.to<JsonVariant>()) {}
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
void setValue(const T& value) {
|
||||
variant.set(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void assertEqualsTo(const T& value) {
|
||||
REQUIRE(variant == value);
|
||||
REQUIRE(value == variant);
|
||||
|
||||
REQUIRE_FALSE(variant != value);
|
||||
REQUIRE_FALSE(value != variant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void assertDiffersFrom(const T& value) {
|
||||
REQUIRE(variant != value);
|
||||
REQUIRE(value != variant);
|
||||
|
||||
REQUIRE_FALSE(variant == value);
|
||||
REQUIRE_FALSE(value == variant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void assertGreaterThan(const T& value) {
|
||||
REQUIRE((variant > value));
|
||||
REQUIRE((variant >= value));
|
||||
REQUIRE(value < variant);
|
||||
REQUIRE(value <= variant);
|
||||
|
||||
REQUIRE_FALSE((variant < value));
|
||||
REQUIRE_FALSE((variant <= value));
|
||||
REQUIRE_FALSE(value > variant);
|
||||
REQUIRE_FALSE(value >= variant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void assertLowerThan(const T& value) {
|
||||
REQUIRE(variant < value);
|
||||
REQUIRE(variant <= value);
|
||||
REQUIRE(value > variant);
|
||||
REQUIRE(value >= variant);
|
||||
|
||||
REQUIRE_FALSE(variant > value);
|
||||
REQUIRE_FALSE(variant >= value);
|
||||
REQUIRE_FALSE(value < variant);
|
||||
REQUIRE_FALSE(value <= variant);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(VariantComparisionFixture,
|
||||
"Compare variant with another type") {
|
||||
SECTION("null") {
|
||||
assertDiffersFrom(3);
|
||||
assertDiffersFrom("world");
|
||||
}
|
||||
|
||||
SECTION("string") {
|
||||
setValue("hello");
|
||||
assertEqualsTo("hello");
|
||||
assertDiffersFrom(3);
|
||||
assertDiffersFrom("world");
|
||||
assertGreaterThan("helln");
|
||||
assertLowerThan("hellp");
|
||||
}
|
||||
|
||||
SECTION("positive integer") {
|
||||
setValue(42);
|
||||
assertEqualsTo(42);
|
||||
assertDiffersFrom(43);
|
||||
assertGreaterThan(41);
|
||||
assertLowerThan(43);
|
||||
assertDiffersFrom("world");
|
||||
}
|
||||
|
||||
SECTION("negative integer") {
|
||||
setValue(-42);
|
||||
assertEqualsTo(-42);
|
||||
assertDiffersFrom(42);
|
||||
assertGreaterThan(-43);
|
||||
assertLowerThan(-41);
|
||||
assertDiffersFrom("world");
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
setValue(42.0);
|
||||
assertEqualsTo(42.0);
|
||||
assertDiffersFrom(42.1);
|
||||
assertGreaterThan(41.0);
|
||||
assertLowerThan(43.0);
|
||||
assertDiffersFrom("42.0");
|
||||
}
|
||||
|
||||
SECTION("true") {
|
||||
setValue(true);
|
||||
assertEqualsTo(true);
|
||||
assertDiffersFrom(false);
|
||||
assertDiffersFrom(1);
|
||||
assertDiffersFrom("true");
|
||||
assertDiffersFrom(1.0);
|
||||
assertGreaterThan(false);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ TEST_CASE("JsonVariant::createNestedObject()") {
|
||||
|
||||
SECTION("promotes to array") {
|
||||
JsonObject obj = variant.createNestedObject();
|
||||
obj["value"] = "42";
|
||||
obj["value"] = 42;
|
||||
|
||||
REQUIRE(variant.is<JsonArray>() == true);
|
||||
REQUIRE(variant[0]["value"] == 42);
|
||||
@ -23,7 +23,7 @@ TEST_CASE("JsonVariant::createNestedObject()") {
|
||||
|
||||
SECTION("works on MemberProxy") {
|
||||
JsonObject obj = variant["items"].createNestedObject();
|
||||
obj["value"] = "42";
|
||||
obj["value"] = 42;
|
||||
|
||||
REQUIRE(variant["items"][0]["value"] == 42);
|
||||
}
|
||||
@ -42,7 +42,7 @@ TEST_CASE("JsonVariant::createNestedArray()") {
|
||||
|
||||
SECTION("works on MemberProxy") {
|
||||
JsonArray arr = variant["items"].createNestedArray();
|
||||
arr.add("42");
|
||||
arr.add(42);
|
||||
|
||||
REQUIRE(variant["items"][0][0] == 42);
|
||||
}
|
||||
@ -54,7 +54,7 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
|
||||
|
||||
SECTION("promotes to object") {
|
||||
JsonObject obj = variant.createNestedObject("weather");
|
||||
obj["temp"] = "42";
|
||||
obj["temp"] = 42;
|
||||
|
||||
REQUIRE(variant.is<JsonObject>() == true);
|
||||
REQUIRE(variant["weather"]["temp"] == 42);
|
||||
@ -62,7 +62,7 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
|
||||
|
||||
SECTION("works on MemberProxy") {
|
||||
JsonObject obj = variant["status"].createNestedObject("weather");
|
||||
obj["temp"] = "42";
|
||||
obj["temp"] = 42;
|
||||
|
||||
REQUIRE(variant["status"]["weather"]["temp"] == 42);
|
||||
}
|
||||
@ -81,7 +81,7 @@ TEST_CASE("JsonVariant::createNestedArray(key)") {
|
||||
|
||||
SECTION("works on MemberProxy") {
|
||||
JsonArray arr = variant["weather"].createNestedArray("temp");
|
||||
arr.add("42");
|
||||
arr.add(42);
|
||||
|
||||
REQUIRE(variant["weather"]["temp"][0] == 42);
|
||||
}
|
||||
|
@ -51,6 +51,12 @@ TEST_CASE("JsonVariant::operator|()") {
|
||||
REQUIRE(result == "default");
|
||||
}
|
||||
|
||||
SECTION("int | uint8_t (out of range)") {
|
||||
variant.set(666);
|
||||
uint8_t result = variant | static_cast<uint8_t>(42);
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
||||
SECTION("int | int") {
|
||||
variant.set(0);
|
||||
int result = variant | 666;
|
||||
@ -58,8 +64,9 @@ TEST_CASE("JsonVariant::operator|()") {
|
||||
}
|
||||
|
||||
SECTION("double | int") {
|
||||
variant.set(42.0);
|
||||
int result = variant | 666;
|
||||
// NOTE: changed the behavior to fix #981
|
||||
variant.set(666.0);
|
||||
int result = variant | 42;
|
||||
REQUIRE(result == 42);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
add_executable(MiscTests
|
||||
conflicts.cpp
|
||||
FloatParts.cpp
|
||||
StreamReader.cpp
|
||||
StringAdapters.cpp
|
||||
StringWriter.cpp
|
||||
TypeTraits.cpp
|
||||
unsigned_char.cpp
|
||||
@ -13,3 +15,24 @@ add_executable(MiscTests
|
||||
|
||||
target_link_libraries(MiscTests catch)
|
||||
add_test(Misc MiscTests)
|
||||
|
||||
|
||||
add_executable(Issue978
|
||||
Issue978.cpp
|
||||
)
|
||||
set_target_properties(Issue978
|
||||
PROPERTIES
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
)
|
||||
add_test(
|
||||
NAME
|
||||
Issue978
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} --build . --target Issue978 --config $<CONFIGURATION>
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
set_tests_properties(Issue978
|
||||
PROPERTIES
|
||||
WILL_FAIL TRUE)
|
||||
|
13
test/Misc/Issue978.cpp
Normal file
13
test/Misc/Issue978.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
struct Stream {};
|
||||
|
||||
int main() {
|
||||
Stream* stream = 0;
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, stream);
|
||||
}
|
33
test/Misc/StreamReader.cpp
Normal file
33
test/Misc/StreamReader.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ARDUINOJSON_NAMESPACE;
|
||||
|
||||
TEST_CASE("StdStreamReader") {
|
||||
std::istringstream src("\x01\xFF");
|
||||
StdStreamReader reader(src);
|
||||
|
||||
REQUIRE(reader.read() == 0x01);
|
||||
REQUIRE(reader.read() == 0xFF);
|
||||
REQUIRE(reader.read() == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("SafeCharPointerReader") {
|
||||
SafeCharPointerReader reader("\x01\xFF", 2);
|
||||
|
||||
REQUIRE(reader.read() == 0x01);
|
||||
REQUIRE(reader.read() == 0xFF);
|
||||
REQUIRE(reader.read() == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("UnsafeCharPointerReader") {
|
||||
UnsafeCharPointerReader reader("\x01\xFF");
|
||||
|
||||
REQUIRE(reader.read() == 0x01);
|
||||
REQUIRE(reader.read() == 0xFF);
|
||||
REQUIRE(reader.read() == 0);
|
||||
}
|
45
test/Misc/StringAdapters.cpp
Normal file
45
test/Misc/StringAdapters.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ARDUINOJSON_NAMESPACE;
|
||||
|
||||
TEST_CASE("ConstRamStringAdapter") {
|
||||
SECTION("null") {
|
||||
ConstRamStringAdapter adapter(NULL);
|
||||
|
||||
REQUIRE(adapter.compare("bravo") < 0);
|
||||
REQUIRE(adapter.compare(NULL) == 0);
|
||||
|
||||
REQUIRE(adapter.equals(NULL));
|
||||
REQUIRE_FALSE(adapter.equals("charlie"));
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
ConstRamStringAdapter adapter("bravo");
|
||||
|
||||
REQUIRE(adapter.compare(NULL) > 0);
|
||||
REQUIRE(adapter.compare("alpha") > 0);
|
||||
REQUIRE(adapter.compare("bravo") == 0);
|
||||
REQUIRE(adapter.compare("charlie") < 0);
|
||||
|
||||
REQUIRE(adapter.equals("bravo"));
|
||||
REQUIRE_FALSE(adapter.equals("charlie"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StlString") {
|
||||
std::string str("bravo");
|
||||
StlStringAdapter adapter(str);
|
||||
|
||||
REQUIRE(adapter.compare(NULL) > 0);
|
||||
REQUIRE(adapter.compare("alpha") > 0);
|
||||
REQUIRE(adapter.compare("bravo") == 0);
|
||||
REQUIRE(adapter.compare("charlie") < 0);
|
||||
|
||||
REQUIRE(adapter.equals("bravo"));
|
||||
REQUIRE_FALSE(adapter.equals("charlie"));
|
||||
}
|
@ -6,8 +6,13 @@
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
add_executable(MixedConfigurationTests
|
||||
cpp11.cpp
|
||||
decode_unicode_0.cpp
|
||||
decode_unicode_1.cpp
|
||||
enable_infinity_0.cpp
|
||||
enable_infinity_1.cpp
|
||||
enable_nan_0.cpp
|
||||
enable_nan_1.cpp
|
||||
use_double_0.cpp
|
||||
use_double_1.cpp
|
||||
use_long_long_0.cpp
|
||||
|
31
test/MixedConfiguration/cpp11.cpp
Normal file
31
test/MixedConfiguration/cpp11.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
TEST_CASE("nullptr") {
|
||||
DynamicJsonDocument doc(4096);
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("JsonVariant == nullptr") {
|
||||
REQUIRE((variant == nullptr));
|
||||
REQUIRE_FALSE((variant != nullptr));
|
||||
}
|
||||
|
||||
SECTION("JsonVariant != nullptr") {
|
||||
variant.set(42);
|
||||
|
||||
REQUIRE_FALSE((variant == nullptr));
|
||||
REQUIRE((variant != nullptr));
|
||||
}
|
||||
|
||||
SECTION("JsonVariant.set(nullptr)") {
|
||||
variant.set(42);
|
||||
variant.set(nullptr);
|
||||
|
||||
REQUIRE(variant.isNull());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
35
test/MixedConfiguration/enable_infinity_0.cpp
Normal file
35
test/MixedConfiguration/enable_infinity_0.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#define ARDUINOJSON_ENABLE_INFINITY 0
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
static void assertParseFails(const char* json) {
|
||||
DynamicJsonDocument doc(4096);
|
||||
auto err = deserializeJson(doc, json);
|
||||
|
||||
REQUIRE(err == DeserializationError::InvalidInput);
|
||||
}
|
||||
|
||||
static void assertJsonEquals(const JsonDocument& doc,
|
||||
std::string expectedJson) {
|
||||
std::string actualJson;
|
||||
serializeJson(doc, actualJson);
|
||||
REQUIRE(actualJson == expectedJson);
|
||||
}
|
||||
|
||||
TEST_CASE("ARDUINOJSON_ENABLE_INFINITY == 0") {
|
||||
SECTION("serializeJson()") {
|
||||
DynamicJsonDocument doc(4096);
|
||||
doc.add(std::numeric_limits<double>::infinity());
|
||||
doc.add(-std::numeric_limits<double>::infinity());
|
||||
|
||||
assertJsonEquals(doc, "[null,null]");
|
||||
}
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
assertParseFails("{\"X\":Infinity}");
|
||||
assertParseFails("{\"X\":-Infinity}");
|
||||
assertParseFails("{\"X\":+Infinity}");
|
||||
}
|
||||
}
|
38
test/MixedConfiguration/enable_infinity_1.cpp
Normal file
38
test/MixedConfiguration/enable_infinity_1.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#define ARDUINOJSON_ENABLE_INFINITY 1
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
namespace my {
|
||||
using ARDUINOJSON_NAMESPACE::isinf;
|
||||
} // namespace my
|
||||
|
||||
TEST_CASE("ARDUINOJSON_ENABLE_INFINITY == 1") {
|
||||
DynamicJsonDocument doc(4096);
|
||||
|
||||
SECTION("serializeJson()") {
|
||||
doc.add(std::numeric_limits<double>::infinity());
|
||||
doc.add(-std::numeric_limits<double>::infinity());
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
|
||||
REQUIRE(json == "[Infinity,-Infinity]");
|
||||
}
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
auto err = deserializeJson(doc, "[Infinity,-Infinity,+Infinity]");
|
||||
float a = doc[0];
|
||||
float b = doc[1];
|
||||
float c = doc[2];
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(my::isinf(a));
|
||||
REQUIRE(a > 0);
|
||||
REQUIRE(my::isinf(b));
|
||||
REQUIRE(b < 0);
|
||||
REQUIRE(my::isinf(c));
|
||||
REQUIRE(c > 0);
|
||||
}
|
||||
}
|
25
test/MixedConfiguration/enable_nan_0.cpp
Normal file
25
test/MixedConfiguration/enable_nan_0.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#define ARDUINOJSON_ENABLE_NAN 0
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
TEST_CASE("ARDUINOJSON_ENABLE_NAN == 0") {
|
||||
DynamicJsonDocument doc(4096);
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
|
||||
SECTION("serializeJson()") {
|
||||
root["X"] = std::numeric_limits<double>::signaling_NaN();
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
|
||||
REQUIRE(json == "{\"X\":null}");
|
||||
}
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
auto err = deserializeJson(doc, "{\"X\":NaN}");
|
||||
|
||||
REQUIRE(err == DeserializationError::InvalidInput);
|
||||
}
|
||||
}
|
31
test/MixedConfiguration/enable_nan_1.cpp
Normal file
31
test/MixedConfiguration/enable_nan_1.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#define ARDUINOJSON_ENABLE_NAN 1
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
namespace my {
|
||||
using ARDUINOJSON_NAMESPACE::isnan;
|
||||
} // namespace my
|
||||
|
||||
TEST_CASE("ARDUINOJSON_ENABLE_NAN == 1") {
|
||||
DynamicJsonDocument doc(4096);
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
|
||||
SECTION("serializeJson()") {
|
||||
root["X"] = std::numeric_limits<double>::signaling_NaN();
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
|
||||
REQUIRE(json == "{\"X\":NaN}");
|
||||
}
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
auto err = deserializeJson(doc, "{\"X\":NaN}");
|
||||
float x = doc["X"];
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(my::isnan(x));
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
// MIT License
|
||||
|
||||
#define ARDUINOJSON_USE_DOUBLE 0
|
||||
#define ARDUINOJSON_ENABLE_NAN 1
|
||||
#define ARDUINOJSON_ENABLE_INFINITY 1
|
||||
|
||||
#include <ArduinoJson/Numbers/parseFloat.hpp>
|
||||
#include <catch.hpp>
|
||||
|
@ -16,3 +16,9 @@ TEST_CASE("Test uint32_t overflow") {
|
||||
REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER));
|
||||
REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT));
|
||||
}
|
||||
|
||||
TEST_CASE("Invalid value") {
|
||||
ParsedNumber<float, uint32_t> result = parseNumber<float, uint32_t>("6a3");
|
||||
|
||||
REQUIRE(result.type() == uint8_t(VALUE_IS_NULL));
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#define ARDUINOJSON_ENABLE_NAN 1
|
||||
#define ARDUINOJSON_ENABLE_INFINITY 1
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
#include <ArduinoJson/Serialization/DynamicStringWriter.hpp>
|
||||
|
||||
|
Reference in New Issue
Block a user