forked from bblanchon/ArduinoJson
RawJson()
accepts any kind of string and obeys to duplication rules
This commit is contained in:
14
CHANGELOG.md
14
CHANGELOG.md
@ -5,17 +5,19 @@ HEAD
|
|||||||
----
|
----
|
||||||
|
|
||||||
* Changed the rules of string duplication (issue #658)
|
* Changed the rules of string duplication (issue #658)
|
||||||
|
* `RawJson()` accepts any kind of string and obeys to the same rules for duplication
|
||||||
* Changed the return type of `strdup()` to `const char*` to prevent double duplication
|
* Changed the return type of `strdup()` to `const char*` to prevent double duplication
|
||||||
* Marked `strdup()` as deprecated
|
* Marked `strdup()` as deprecated
|
||||||
|
|
||||||
> ### New rules for string duplication
|
> ### New rules for string duplication
|
||||||
>
|
>
|
||||||
> | type | duplication |
|
> | type | duplication |
|
||||||
> |:-------------|:------------|
|
> |:---------------------------|:------------|
|
||||||
> | const char* | no |
|
> | const char* | no |
|
||||||
> | char* | ~~no~~ yes |
|
> | char* | ~~no~~ yes |
|
||||||
> | String | yes |
|
> | String | yes |
|
||||||
> | std::string | yes |
|
> | std::string | yes |
|
||||||
|
> | const __FlashStringHelper* | yes |
|
||||||
>
|
>
|
||||||
> These new rules make `JsonBuffer::strdup()` useless.
|
> These new rules make `JsonBuffer::strdup()` useless.
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ void setup() {
|
|||||||
// JsonBuffer.
|
// JsonBuffer.
|
||||||
root["sensor"] = F("gps");
|
root["sensor"] = F("gps");
|
||||||
|
|
||||||
|
// It works with RawJson too:
|
||||||
|
root["sensor"] = RawJson(F("\"gps\""));
|
||||||
|
|
||||||
// You can compare the content of a JsonVariant to a Flash String
|
// You can compare the content of a JsonVariant to a Flash String
|
||||||
if (root["sensor"] == F("gps")) {
|
if (root["sensor"] == F("gps")) {
|
||||||
// ...
|
// ...
|
||||||
|
@ -40,6 +40,9 @@ void setup() {
|
|||||||
// WARNING: the content of the String will be duplicated in the JsonBuffer.
|
// WARNING: the content of the String will be duplicated in the JsonBuffer.
|
||||||
root["sensor"] = sensor;
|
root["sensor"] = sensor;
|
||||||
|
|
||||||
|
// It works with RawJson too:
|
||||||
|
root["sensor"] = RawJson(sensor);
|
||||||
|
|
||||||
// You can also concatenate strings
|
// You can also concatenate strings
|
||||||
// WARNING: the content of the String will be duplicated in the JsonBuffer.
|
// WARNING: the content of the String will be duplicated in the JsonBuffer.
|
||||||
root[String("sen") + "sor"] = String("gp") + "s";
|
root[String("sen") + "sor"] = String("gp") + "s";
|
||||||
|
@ -23,11 +23,29 @@ struct ValueSaver {
|
|||||||
|
|
||||||
template <typename Source>
|
template <typename Source>
|
||||||
struct ValueSaver<Source, typename TypeTraits::EnableIf<
|
struct ValueSaver<Source, typename TypeTraits::EnableIf<
|
||||||
TypeTraits::IsString<Source>::value>::type> {
|
StringTraits<Source>::should_duplicate>::type> {
|
||||||
template <typename Destination>
|
template <typename Destination>
|
||||||
static bool save(JsonBuffer* buffer, Destination& destination,
|
static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
|
||||||
Source source) {
|
if (!StringTraits<Source>::is_null(source)) {
|
||||||
return StringTraits<Source>::save(source, destination, buffer);
|
typename StringTraits<Source>::duplicate_t dup =
|
||||||
|
StringTraits<Source>::duplicate(source, buffer);
|
||||||
|
if (!dup) return false;
|
||||||
|
dest = dup;
|
||||||
|
} else {
|
||||||
|
dest = reinterpret_cast<const char*>(0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// const char*, const signed char*, const unsigned char*
|
||||||
|
template <typename Char>
|
||||||
|
struct ValueSaver<Char*, typename TypeTraits::EnableIf<
|
||||||
|
!StringTraits<Char*>::should_duplicate>::type> {
|
||||||
|
template <typename Destination>
|
||||||
|
static bool save(JsonBuffer*, Destination& dest, Char* source) {
|
||||||
|
dest = reinterpret_cast<const char*>(source);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class JsonObjectSubscript
|
|||||||
// operator=(TValue);
|
// operator=(TValue);
|
||||||
// TValue = char*, const char*, const FlashStringHelper*
|
// TValue = char*, const char*, const FlashStringHelper*
|
||||||
template <typename TValue>
|
template <typename TValue>
|
||||||
FORCE_INLINE this_type& operator=(const TValue* src) {
|
FORCE_INLINE this_type& operator=(TValue* src) {
|
||||||
_object.set(_key, src);
|
_object.set(_key, src);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a JsonVariant containing an unparsed string
|
// Create a JsonVariant containing an unparsed string
|
||||||
JsonVariant(RawJson value) {
|
JsonVariant(Internals::RawJsonString<const char *> value) {
|
||||||
_type = Internals::JSON_UNPARSED;
|
_type = Internals::JSON_UNPARSED;
|
||||||
_content.asString = value;
|
_content.asString = value;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ class JsonVariantComparisons {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
typename TypeTraits::EnableIf<TypeTraits::IsString<TString>::value,
|
typename TypeTraits::EnableIf<Internals::StringTraits<TString>::has_equals,
|
||||||
bool>::type
|
bool>::type
|
||||||
equals(const TString &comparand) const {
|
equals(const TString &comparand) const {
|
||||||
const char *value = as<const char *>();
|
const char *value = as<const char *>();
|
||||||
@ -112,9 +112,10 @@ class JsonVariantComparisons {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TComparand>
|
template <typename TComparand>
|
||||||
typename TypeTraits::EnableIf<!TypeTraits::IsVariant<TComparand>::value &&
|
typename TypeTraits::EnableIf<
|
||||||
!TypeTraits::IsString<TComparand>::value,
|
!TypeTraits::IsVariant<TComparand>::value &&
|
||||||
bool>::type
|
!Internals::StringTraits<TComparand>::has_equals,
|
||||||
|
bool>::type
|
||||||
equals(const TComparand &comparand) const {
|
equals(const TComparand &comparand) const {
|
||||||
return as<TComparand>() == comparand;
|
return as<TComparand>() == comparand;
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,41 @@
|
|||||||
|
|
||||||
namespace ArduinoJson {
|
namespace ArduinoJson {
|
||||||
|
|
||||||
|
namespace Internals {
|
||||||
// A special type of data that can be used to insert pregenerated JSON portions.
|
// A special type of data that can be used to insert pregenerated JSON portions.
|
||||||
class RawJson {
|
template <typename T>
|
||||||
|
class RawJsonString {
|
||||||
public:
|
public:
|
||||||
explicit RawJson(const char* str) : _str(str) {}
|
explicit RawJsonString(T str) : _str(str) {}
|
||||||
operator const char*() const {
|
operator T() const {
|
||||||
return _str;
|
return _str;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* _str;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,8 +29,7 @@ template <typename T>
|
|||||||
class JsonPrintable {
|
class JsonPrintable {
|
||||||
public:
|
public:
|
||||||
template <typename Print>
|
template <typename Print>
|
||||||
typename TypeTraits::EnableIf<!TypeTraits::IsString<Print>::value,
|
typename TypeTraits::EnableIf<!StringTraits<Print>::has_append, size_t>::type
|
||||||
size_t>::type
|
|
||||||
printTo(Print &print) const {
|
printTo(Print &print) const {
|
||||||
JsonWriter<Print> writer(print);
|
JsonWriter<Print> writer(print);
|
||||||
JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer);
|
JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer);
|
||||||
@ -79,8 +78,7 @@ class JsonPrintable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Print>
|
template <typename Print>
|
||||||
typename TypeTraits::EnableIf<!TypeTraits::IsString<Print>::value,
|
typename TypeTraits::EnableIf<!StringTraits<Print>::has_append, size_t>::type
|
||||||
size_t>::type
|
|
||||||
prettyPrintTo(Print &print) const {
|
prettyPrintTo(Print &print) const {
|
||||||
IndentedPrint<Print> indentedPrint(print);
|
IndentedPrint<Print> indentedPrint(print);
|
||||||
return prettyPrintTo(indentedPrint);
|
return prettyPrintTo(indentedPrint);
|
||||||
|
@ -43,6 +43,9 @@ struct ArduinoStreamTraits {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const bool has_append = false;
|
||||||
|
static const bool has_equals = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TStream>
|
template <typename TStream>
|
||||||
|
@ -33,58 +33,31 @@ struct CharPointerTraits {
|
|||||||
return strcmp(reinterpret_cast<const char*>(str), expected) == 0;
|
return strcmp(reinterpret_cast<const char*>(str), expected) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove
|
static bool is_null(const TChar* str) {
|
||||||
|
return !str;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef const char* duplicate_t;
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
static char* duplicate(const TChar* str, Buffer* buffer) {
|
static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
|
||||||
if (!str) return NULL;
|
if (!str) return NULL;
|
||||||
size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
|
size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
|
||||||
void* dup = buffer->alloc(size);
|
void* dup = buffer->alloc(size);
|
||||||
if (dup != NULL) memcpy(dup, str, size);
|
if (dup != NULL) memcpy(dup, str, size);
|
||||||
return static_cast<char*>(dup);
|
return static_cast<duplicate_t>(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const bool has_append = false;
|
static const bool has_append = false;
|
||||||
static const bool has_equals = true;
|
static const bool has_equals = true;
|
||||||
};
|
static const bool should_duplicate = !TypeTraits::IsConst<TChar>::value;
|
||||||
|
|
||||||
// const char*, const unsigned char*, const signed char*
|
|
||||||
template <typename TChar>
|
|
||||||
struct StringTraits<TChar*, typename TypeTraits::EnableIf<
|
|
||||||
TypeTraits::IsChar<TChar>::value &&
|
|
||||||
TypeTraits::IsConst<TChar>::value>::type>
|
|
||||||
: CharPointerTraits<TChar> {
|
|
||||||
// Just save the pointer
|
|
||||||
template <typename Buffer, typename Destination>
|
|
||||||
static typename TypeTraits::EnableIf<TypeTraits::IsConst<TChar>::value,
|
|
||||||
bool>::type
|
|
||||||
save(const TChar* source, Destination& dest, Buffer*) {
|
|
||||||
dest = reinterpret_cast<const char*>(source);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// char*, unsigned char*, signed char*
|
// char*, unsigned char*, signed char*
|
||||||
|
// const char*, const unsigned char*, const signed char*
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
struct StringTraits<TChar*, typename TypeTraits::EnableIf<
|
struct StringTraits<TChar*, typename TypeTraits::EnableIf<
|
||||||
TypeTraits::IsChar<TChar>::value &&
|
TypeTraits::IsChar<TChar>::value>::type>
|
||||||
!TypeTraits::IsConst<TChar>::value>::type>
|
: CharPointerTraits<TChar> {};
|
||||||
: CharPointerTraits<TChar> {
|
|
||||||
// Make a copy of the string
|
|
||||||
template <typename Buffer, typename Destination>
|
|
||||||
static typename TypeTraits::EnableIf<!TypeTraits::IsConst<TChar>::value,
|
|
||||||
bool>::type
|
|
||||||
save(const TChar* source, Destination& dest, Buffer* buffer) {
|
|
||||||
if (source) {
|
|
||||||
size_t size = strlen(reinterpret_cast<const char*>(source)) + 1;
|
|
||||||
void* dup = buffer->alloc(size);
|
|
||||||
if (!dup) return false;
|
|
||||||
memcpy(dup, source, size);
|
|
||||||
dest = reinterpret_cast<const char*>(dup);
|
|
||||||
} else {
|
|
||||||
dest = reinterpret_cast<const char*>(source);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,32 +34,24 @@ struct StringTraits<const __FlashStringHelper*, void> {
|
|||||||
return strcmp_P(expected, (const char*)str) == 0;
|
return strcmp_P(expected, (const char*)str) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove
|
static bool is_null(const __FlashStringHelper* str) {
|
||||||
|
return !str;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef const char* duplicate_t;
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
static char* duplicate(const __FlashStringHelper* str, Buffer* buffer) {
|
static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
|
||||||
if (!str) return NULL;
|
if (!str) return NULL;
|
||||||
size_t size = strlen_P((const char*)str) + 1;
|
size_t size = strlen_P((const char*)str) + 1;
|
||||||
void* dup = buffer->alloc(size);
|
void* dup = buffer->alloc(size);
|
||||||
if (dup != NULL) memcpy_P(dup, (const char*)str, size);
|
if (dup != NULL) memcpy_P(dup, (const char*)str, size);
|
||||||
return static_cast<char*>(dup);
|
return static_cast<duplicate_t>(dup);
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Buffer, typename Destination>
|
|
||||||
static bool save(const __FlashStringHelper* source, Destination& dest,
|
|
||||||
Buffer* buffer) {
|
|
||||||
if (source) {
|
|
||||||
size_t size = strlen_P((const char*)source) + 1;
|
|
||||||
void* dup = buffer->alloc(size);
|
|
||||||
if (dup != NULL) memcpy_P(dup, (const char*)source, size);
|
|
||||||
dest = reinterpret_cast<const char*>(dup);
|
|
||||||
} else {
|
|
||||||
dest = reinterpret_cast<const char*>(source);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const bool has_append = false;
|
static const bool has_append = false;
|
||||||
static const bool has_equals = true;
|
static const bool has_equals = true;
|
||||||
|
static const bool should_duplicate = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,9 @@ struct StdStreamTraits {
|
|||||||
return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
|
return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const bool has_append = false;
|
||||||
|
static const bool has_equals = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TStream>
|
template <typename TStream>
|
||||||
|
@ -19,29 +19,20 @@ namespace Internals {
|
|||||||
|
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
struct StdStringTraits {
|
struct StdStringTraits {
|
||||||
// TODO: remove
|
typedef const char* duplicate_t;
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
static char* duplicate(const TString& str, Buffer* buffer) {
|
static duplicate_t duplicate(const TString& str, Buffer* buffer) {
|
||||||
if (!str.c_str()) return NULL; // <- Arduino string can return NULL
|
if (!str.c_str()) return NULL; // <- Arduino string can return NULL
|
||||||
size_t size = str.length() + 1;
|
size_t size = str.length() + 1;
|
||||||
void* dup = buffer->alloc(size);
|
void* dup = buffer->alloc(size);
|
||||||
if (dup != NULL) memcpy(dup, str.c_str(), size);
|
if (dup != NULL) memcpy(dup, str.c_str(), size);
|
||||||
return static_cast<char*>(dup);
|
return static_cast<duplicate_t>(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Buffer, typename Destination>
|
static bool is_null(const TString& str) {
|
||||||
static bool save(const TString& str, Destination& dest, Buffer* buffer) {
|
|
||||||
// Arduino's String::c_str() can return NULL
|
// Arduino's String::c_str() can return NULL
|
||||||
if (str.c_str()) {
|
return !str.c_str();
|
||||||
size_t size = str.length() + 1;
|
|
||||||
void* dup = buffer->alloc(size);
|
|
||||||
if (!dup) return false;
|
|
||||||
memcpy(dup, str.c_str(), size);
|
|
||||||
dest = reinterpret_cast<const char*>(dup);
|
|
||||||
} else {
|
|
||||||
dest = str.c_str();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Reader : CharPointerTraits<char>::Reader {
|
struct Reader : CharPointerTraits<char>::Reader {
|
||||||
@ -62,6 +53,7 @@ struct StdStringTraits {
|
|||||||
|
|
||||||
static const bool has_append = true;
|
static const bool has_append = true;
|
||||||
static const bool has_equals = true;
|
static const bool has_equals = true;
|
||||||
|
static const bool should_duplicate = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
|
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||||
|
@ -16,7 +16,10 @@ namespace ArduinoJson {
|
|||||||
namespace Internals {
|
namespace Internals {
|
||||||
|
|
||||||
template <typename TString, typename Enable = void>
|
template <typename TString, typename Enable = void>
|
||||||
struct StringTraits {};
|
struct StringTraits {
|
||||||
|
static const bool has_append = false;
|
||||||
|
static const bool has_equals = false;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
struct StringTraits<const TString, void> : StringTraits<TString> {};
|
struct StringTraits<const TString, void> : StringTraits<TString> {};
|
||||||
@ -31,18 +34,3 @@ struct StringTraits<TString&, void> : StringTraits<TString> {};
|
|||||||
#include "FlashString.hpp"
|
#include "FlashString.hpp"
|
||||||
#include "StdStream.hpp"
|
#include "StdStream.hpp"
|
||||||
#include "StdString.hpp"
|
#include "StdString.hpp"
|
||||||
|
|
||||||
namespace ArduinoJson {
|
|
||||||
namespace TypeTraits {
|
|
||||||
template <typename T, typename Enable = void>
|
|
||||||
struct IsString {
|
|
||||||
static const bool value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct IsString<T, typename TypeTraits::EnableIf<
|
|
||||||
Internals::StringTraits<T>::has_equals>::type> {
|
|
||||||
static const bool value = Internals::StringTraits<T>::has_equals;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -84,7 +84,7 @@ TEST_CASE("JsonArray::add()") {
|
|||||||
REQUIRE(expectedSize == _jsonBuffer.size());
|
REQUIRE(expectedSize == _jsonBuffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should duplicate char*") {
|
SECTION("should duplicate char*") {
|
||||||
_array.add(const_cast<char*>("world"));
|
_array.add(const_cast<char*>("world"));
|
||||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||||
REQUIRE(expectedSize == _jsonBuffer.size());
|
REQUIRE(expectedSize == _jsonBuffer.size());
|
||||||
@ -95,4 +95,16 @@ TEST_CASE("JsonArray::add()") {
|
|||||||
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
|
||||||
REQUIRE(expectedSize == _jsonBuffer.size());
|
REQUIRE(expectedSize == _jsonBuffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("should not duplicate RawJson(const char*)") {
|
||||||
|
_array.add(RawJson("{}"));
|
||||||
|
const size_t expectedSize = JSON_ARRAY_SIZE(1);
|
||||||
|
REQUIRE(expectedSize == _jsonBuffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("should duplicate RawJson(char*)") {
|
||||||
|
_array.add(RawJson(const_cast<char*>("{}")));
|
||||||
|
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
|
||||||
|
REQUIRE(expectedSize == _jsonBuffer.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
static void check(JsonArray &array, std::string expected) {
|
static void check(JsonArray &array, std::string expected) {
|
||||||
std::string actual;
|
std::string actual;
|
||||||
size_t actualLen = array.printTo(actual);
|
size_t actualLen = array.printTo(actual);
|
||||||
size_t measuredLen = array.measureLength();
|
|
||||||
CHECK(actualLen == expected.size());
|
|
||||||
CHECK(measuredLen == expected.size());
|
|
||||||
REQUIRE(expected == actual);
|
REQUIRE(expected == actual);
|
||||||
|
REQUIRE(actualLen == expected.size());
|
||||||
|
size_t measuredLen = array.measureLength();
|
||||||
|
REQUIRE(measuredLen == expected.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("JsonArray::printTo()") {
|
TEST_CASE("JsonArray::printTo()") {
|
||||||
@ -67,12 +67,22 @@ TEST_CASE("JsonArray::printTo()") {
|
|||||||
check(array, "[1,2]");
|
check(array, "[1,2]");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("RawJson") {
|
SECTION("RawJson(const char*)") {
|
||||||
array.add(RawJson("{\"key\":\"value\"}"));
|
array.add(RawJson("{\"key\":\"value\"}"));
|
||||||
|
|
||||||
check(array, "[{\"key\":\"value\"}]");
|
check(array, "[{\"key\":\"value\"}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("RawJson(char*)") {
|
||||||
|
DynamicJsonBuffer jb2;
|
||||||
|
JsonArray &arr = jb2.createArray();
|
||||||
|
|
||||||
|
char tmp[] = "{\"key\":\"value\"}";
|
||||||
|
arr.add(RawJson(tmp));
|
||||||
|
|
||||||
|
check(arr, "[{\"key\":\"value\"}]");
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("OneIntegerOverCapacity") {
|
SECTION("OneIntegerOverCapacity") {
|
||||||
array.add(1);
|
array.add(1);
|
||||||
array.add(2);
|
array.add(2);
|
||||||
|
@ -8,6 +8,7 @@ add_executable(MiscTests
|
|||||||
std_stream.cpp
|
std_stream.cpp
|
||||||
std_string.cpp
|
std_string.cpp
|
||||||
StringBuilder.cpp
|
StringBuilder.cpp
|
||||||
|
StringTraits.cpp
|
||||||
TypeTraits.cpp
|
TypeTraits.cpp
|
||||||
unsigned_char.cpp
|
unsigned_char.cpp
|
||||||
vla.cpp
|
vla.cpp
|
||||||
|
22
test/Misc/StringTraits.cpp
Normal file
22
test/Misc/StringTraits.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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*> >());
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using namespace ArduinoJson::TypeTraits;
|
using namespace ArduinoJson::TypeTraits;
|
||||||
|
|
||||||
@ -31,12 +30,6 @@ TEST_CASE("TypeTraits") {
|
|||||||
REQUIRE(static_cast<bool>(IsVariant<JsonVariant>::value));
|
REQUIRE(static_cast<bool>(IsVariant<JsonVariant>::value));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("IsString") {
|
|
||||||
REQUIRE((IsString<const char*>::value));
|
|
||||||
REQUIRE((IsString<std::string>::value));
|
|
||||||
REQUIRE_FALSE((IsString<double>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("IsConst") {
|
SECTION("IsConst") {
|
||||||
REQUIRE_FALSE((IsConst<char>::value));
|
REQUIRE_FALSE((IsConst<char>::value));
|
||||||
REQUIRE((IsConst<const char>::value));
|
REQUIRE((IsConst<const char>::value));
|
||||||
|
Reference in New Issue
Block a user