forked from bblanchon/ArduinoJson
Removed implicit conversion in comparison operators (issue #998)
This commit is contained in:
@ -9,6 +9,8 @@ HEAD
|
|||||||
* Made `deserializeJson()` more picky about trailing characters (issue #980)
|
* 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_NAN` (default=0) to enable NaN in JSON (issue #973)
|
||||||
* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
|
* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
|
||||||
|
* Removed implicit conversion in comparison operators (issue #998)
|
||||||
|
* Added lexicographical comparison for `JsonVariant`
|
||||||
|
|
||||||
> ### BREAKING CHANGES
|
> ### BREAKING CHANGES
|
||||||
>
|
>
|
||||||
|
@ -7,154 +7,216 @@
|
|||||||
#include "../Variant/VariantRef.hpp"
|
#include "../Variant/VariantRef.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct Comparer;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_simple_value {
|
struct Comparer<T, typename enable_if<IsString<T>::value>::type> {
|
||||||
static const bool value = is_integral<T>::value ||
|
T rhs;
|
||||||
is_floating_point<T>::value ||
|
int result;
|
||||||
is_same<T, bool>::value;
|
|
||||||
|
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() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TVariant>
|
template <typename TVariant>
|
||||||
class VariantComparisons {
|
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:
|
public:
|
||||||
// const char* == TVariant
|
// value == TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T *>::value, bool>::type operator==(
|
friend bool operator==(T *lhs, TVariant rhs) {
|
||||||
T *lhs, TVariant rhs) {
|
return compare(rhs, lhs) == 0;
|
||||||
return adaptString(lhs).equals(rhs.template as<const char *>());
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator==(const T &lhs, TVariant rhs) {
|
||||||
|
return compare(rhs, lhs) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::string == TVariant
|
// TVariant == value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T>::value, bool>::type operator==(
|
friend bool operator==(TVariant lhs, T *rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(lhs, rhs) == 0;
|
||||||
return adaptString(lhs).equals(rhs.template as<const char *>());
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator==(TVariant lhs, const T &rhs) {
|
||||||
|
return compare(lhs, rhs) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant == const char*
|
// value != TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T *>::value, bool>::type operator==(
|
friend bool operator!=(T *lhs, TVariant rhs) {
|
||||||
TVariant lhs, T *rhs) {
|
return compare(rhs, lhs) != 0;
|
||||||
return adaptString(rhs).equals(lhs.template as<const char *>());
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator!=(const T &lhs, TVariant rhs) {
|
||||||
|
return compare(rhs, lhs) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant == std::string
|
// TVariant != value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T>::value, bool>::type operator==(
|
friend bool operator!=(TVariant lhs, T *rhs) {
|
||||||
TVariant lhs, const T &rhs) {
|
return compare(lhs, rhs) != 0;
|
||||||
return adaptString(rhs).equals(lhs.template as<const char *>());
|
}
|
||||||
|
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>
|
template <typename T>
|
||||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator==(
|
friend bool operator<(T *lhs, TVariant rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(rhs, lhs) > 0;
|
||||||
return lhs == rhs.template as<T>();
|
}
|
||||||
|
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>
|
template <typename T>
|
||||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator==(
|
friend bool operator<(TVariant lhs, T *rhs) {
|
||||||
TVariant lhs, const T &rhs) {
|
return compare(lhs, rhs) < 0;
|
||||||
return lhs.template as<T>() == rhs;
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator<(TVariant lhs, const T &rhs) {
|
||||||
|
return compare(lhs, rhs) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char* != TVariant
|
// value <= TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T *>::value, bool>::type operator!=(
|
friend bool operator<=(T *lhs, TVariant rhs) {
|
||||||
T *lhs, TVariant rhs) {
|
return compare(rhs, lhs) >= 0;
|
||||||
return !adaptString(lhs).equals(rhs.template as<const char *>());
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator<=(const T &lhs, TVariant rhs) {
|
||||||
|
return compare(rhs, lhs) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::string != TVariant
|
// TVariant <= value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T>::value, bool>::type operator!=(
|
friend bool operator<=(TVariant lhs, T *rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(lhs, rhs) <= 0;
|
||||||
return !adaptString(lhs).equals(rhs.template as<const char *>());
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator<=(TVariant lhs, const T &rhs) {
|
||||||
|
return compare(lhs, rhs) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant != const char*
|
// value > TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T *>::value, bool>::type operator!=(
|
friend bool operator>(T *lhs, TVariant rhs) {
|
||||||
TVariant lhs, T *rhs) {
|
return compare(rhs, lhs) < 0;
|
||||||
return !adaptString(rhs).equals(lhs.template as<const char *>());
|
}
|
||||||
|
template <typename T>
|
||||||
|
friend bool operator>(const T &lhs, TVariant rhs) {
|
||||||
|
return compare(rhs, lhs) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant != std::string
|
// TVariant > value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<IsString<T>::value, bool>::type operator!=(
|
friend bool operator>(TVariant lhs, T *rhs) {
|
||||||
TVariant lhs, const T &rhs) {
|
return compare(lhs, rhs) > 0;
|
||||||
return !adaptString(rhs).equals(lhs.template as<const char *>());
|
}
|
||||||
|
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>
|
template <typename T>
|
||||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=(
|
friend bool operator>=(T *lhs, TVariant rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(rhs, lhs) <= 0;
|
||||||
return lhs != rhs.template as<T>();
|
}
|
||||||
|
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>
|
template <typename T>
|
||||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=(
|
friend bool operator>=(TVariant lhs, T *rhs) {
|
||||||
TVariant lhs, const T &rhs) {
|
return compare(lhs, rhs) >= 0;
|
||||||
return lhs.template as<T>() != rhs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool/int/float < TVariant
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<(
|
friend bool operator>=(TVariant lhs, const T &rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(lhs, rhs) >= 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <WString.h>
|
#include <WString.h>
|
||||||
|
#include "../Polyfills/safe_strcmp.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
@ -25,11 +26,14 @@ class ArduinoStringAdapter {
|
|||||||
return !_str->c_str();
|
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
|
// Arduino's String::c_str() can return NULL
|
||||||
const char* actual = _str->c_str();
|
const char* me = _str->c_str();
|
||||||
if (!actual || !expected) return actual == expected;
|
return safe_strcmp(me, other);
|
||||||
return 0 == strcmp(actual, expected);
|
}
|
||||||
|
|
||||||
|
bool equals(const char* expected) const {
|
||||||
|
return compare(expected) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* data() const {
|
const char* data() const {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <stddef.h> // size_t
|
#include <stddef.h> // size_t
|
||||||
#include <string.h> // strcmp
|
#include <string.h> // strcmp
|
||||||
|
#include "../Polyfills/safe_strcmp.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
@ -13,10 +14,12 @@ class ConstRamStringAdapter {
|
|||||||
public:
|
public:
|
||||||
ConstRamStringAdapter(const char* str = 0) : _str(str) {}
|
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 {
|
bool equals(const char* expected) const {
|
||||||
const char* actual = _str;
|
return compare(expected) == 0;
|
||||||
if (!actual || !expected) return actual == expected;
|
|
||||||
return strcmp(actual, expected) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -10,10 +10,15 @@ class FlashStringAdapter {
|
|||||||
public:
|
public:
|
||||||
FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {}
|
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 {
|
bool equals(const char* expected) const {
|
||||||
const char* actual = reinterpret_cast<const char*>(_str);
|
return compare(expected) == 0;
|
||||||
if (!actual || !expected) return actual == expected;
|
|
||||||
return strcmp_P(expected, actual) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -11,10 +11,15 @@ class SizedFlashStringAdapter {
|
|||||||
SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz)
|
SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz)
|
||||||
: _str(str), _size(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 {
|
bool equals(const char* expected) const {
|
||||||
const char* actual = reinterpret_cast<const char*>(_str);
|
return compare(expected) == 0;
|
||||||
if (!actual || !expected) return actual == expected;
|
|
||||||
return strncmp_P(expected, actual, _size) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -12,10 +12,12 @@ class SizedRamStringAdapter {
|
|||||||
public:
|
public:
|
||||||
SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {}
|
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 {
|
bool equals(const char* expected) const {
|
||||||
const char* actual = reinterpret_cast<const char*>(_str);
|
return compare(expected) == 0;
|
||||||
if (!actual || !expected) return actual == expected;
|
|
||||||
return strcmp(actual, expected) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -23,6 +23,11 @@ class StlStringAdapter {
|
|||||||
return false;
|
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 {
|
bool equals(const char* expected) const {
|
||||||
if (!expected) return false;
|
if (!expected) return false;
|
||||||
return *_str == expected;
|
return *_str == expected;
|
||||||
|
@ -161,7 +161,7 @@ TEST_CASE("JsonObject::operator[]") {
|
|||||||
obj[null] = 666;
|
obj[null] = 666;
|
||||||
|
|
||||||
REQUIRE(obj.size() == 1);
|
REQUIRE(obj.size() == 1);
|
||||||
REQUIRE(obj[null] == 0);
|
REQUIRE(obj[null] == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("obj[key].to<JsonArray>()") {
|
SECTION("obj[key].to<JsonArray>()") {
|
||||||
|
@ -337,23 +337,117 @@ TEST_CASE("JsonVariant comparisons") {
|
|||||||
REQUIRE(variant1 != variant3);
|
REQUIRE(variant1 != variant3);
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
REQUIRE_FALSE(variant1 == variant3);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// SECTION("VariantsOfDifferentTypes") {
|
|
||||||
// DynamicJsonDocument doc1(4096);
|
class VariantComparisionFixture {
|
||||||
// JsonObject obj = doc1.to<JsonObject>();
|
private:
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
// DynamicJsonDocument doc2(4096);
|
JsonVariant variant;
|
||||||
// JsonArray arr = doc2.to<JsonArray>();
|
|
||||||
// JsonVariant variants[] = {
|
public:
|
||||||
// true, 42, 666.667, "hello", arr, obj,
|
VariantComparisionFixture() : variant(doc.to<JsonVariant>()) {}
|
||||||
// };
|
|
||||||
// size_t n = sizeof(variants) / sizeof(variants[0]);
|
protected:
|
||||||
|
template <typename T>
|
||||||
// for (size_t i = 0; i < n; i++) {
|
void setValue(const T& value) {
|
||||||
// for (size_t j = i + 1; j < n; j++) {
|
variant.set(value);
|
||||||
// REQUIRE(variants[i] != variants[j]);
|
}
|
||||||
// REQUIRE_FALSE(variants[i] == variants[j]);
|
|
||||||
// }
|
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") {
|
SECTION("promotes to array") {
|
||||||
JsonObject obj = variant.createNestedObject();
|
JsonObject obj = variant.createNestedObject();
|
||||||
obj["value"] = "42";
|
obj["value"] = 42;
|
||||||
|
|
||||||
REQUIRE(variant.is<JsonArray>() == true);
|
REQUIRE(variant.is<JsonArray>() == true);
|
||||||
REQUIRE(variant[0]["value"] == 42);
|
REQUIRE(variant[0]["value"] == 42);
|
||||||
@ -23,7 +23,7 @@ TEST_CASE("JsonVariant::createNestedObject()") {
|
|||||||
|
|
||||||
SECTION("works on MemberProxy") {
|
SECTION("works on MemberProxy") {
|
||||||
JsonObject obj = variant["items"].createNestedObject();
|
JsonObject obj = variant["items"].createNestedObject();
|
||||||
obj["value"] = "42";
|
obj["value"] = 42;
|
||||||
|
|
||||||
REQUIRE(variant["items"][0]["value"] == 42);
|
REQUIRE(variant["items"][0]["value"] == 42);
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ TEST_CASE("JsonVariant::createNestedArray()") {
|
|||||||
|
|
||||||
SECTION("works on MemberProxy") {
|
SECTION("works on MemberProxy") {
|
||||||
JsonArray arr = variant["items"].createNestedArray();
|
JsonArray arr = variant["items"].createNestedArray();
|
||||||
arr.add("42");
|
arr.add(42);
|
||||||
|
|
||||||
REQUIRE(variant["items"][0][0] == 42);
|
REQUIRE(variant["items"][0][0] == 42);
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
|
|||||||
|
|
||||||
SECTION("promotes to object") {
|
SECTION("promotes to object") {
|
||||||
JsonObject obj = variant.createNestedObject("weather");
|
JsonObject obj = variant.createNestedObject("weather");
|
||||||
obj["temp"] = "42";
|
obj["temp"] = 42;
|
||||||
|
|
||||||
REQUIRE(variant.is<JsonObject>() == true);
|
REQUIRE(variant.is<JsonObject>() == true);
|
||||||
REQUIRE(variant["weather"]["temp"] == 42);
|
REQUIRE(variant["weather"]["temp"] == 42);
|
||||||
@ -62,7 +62,7 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
|
|||||||
|
|
||||||
SECTION("works on MemberProxy") {
|
SECTION("works on MemberProxy") {
|
||||||
JsonObject obj = variant["status"].createNestedObject("weather");
|
JsonObject obj = variant["status"].createNestedObject("weather");
|
||||||
obj["temp"] = "42";
|
obj["temp"] = 42;
|
||||||
|
|
||||||
REQUIRE(variant["status"]["weather"]["temp"] == 42);
|
REQUIRE(variant["status"]["weather"]["temp"] == 42);
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ TEST_CASE("JsonVariant::createNestedArray(key)") {
|
|||||||
|
|
||||||
SECTION("works on MemberProxy") {
|
SECTION("works on MemberProxy") {
|
||||||
JsonArray arr = variant["weather"].createNestedArray("temp");
|
JsonArray arr = variant["weather"].createNestedArray("temp");
|
||||||
arr.add("42");
|
arr.add(42);
|
||||||
|
|
||||||
REQUIRE(variant["weather"]["temp"][0] == 42);
|
REQUIRE(variant["weather"]["temp"][0] == 42);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ add_executable(MiscTests
|
|||||||
conflicts.cpp
|
conflicts.cpp
|
||||||
FloatParts.cpp
|
FloatParts.cpp
|
||||||
StreamReader.cpp
|
StreamReader.cpp
|
||||||
|
StringAdapters.cpp
|
||||||
StringWriter.cpp
|
StringWriter.cpp
|
||||||
TypeTraits.cpp
|
TypeTraits.cpp
|
||||||
unsigned_char.cpp
|
unsigned_char.cpp
|
||||||
|
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"));
|
||||||
|
}
|
Reference in New Issue
Block a user