Merge branch 'master' into 6.x

This commit is contained in:
Benoit Blanchon
2018-06-04 17:44:10 +02:00
12 changed files with 104 additions and 14 deletions

View File

@ -1,11 +1,6 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
HEAD
----
* Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693)
* Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu)
* Added `DynamicJsonDocument` and `StaticJsonDocument` * Added `DynamicJsonDocument` and `StaticJsonDocument`
* Added `deserializeJson()` * Added `deserializeJson()`
* Added `serializeJson()` and `serializeJsonPretty()` * Added `serializeJson()` and `serializeJsonPretty()`
@ -64,6 +59,14 @@ HEAD
> serializeJson(doc, Serial); > serializeJson(doc, Serial);
> ``` > ```
v5.13.2
-------
* Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693)
* Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu)
* Fixed null values that could be pass to `strcmp()` (PR #745 from Mike Karlesky)
* Added macros `ARDUINOJSON_VERSION`, `ARDUINOJSON_VERSION_MAJOR`...
v5.13.1 v5.13.1
------- -------

View File

@ -4,6 +4,8 @@
#pragma once #pragma once
#include "ArduinoJson/version.hpp"
#include "ArduinoJson/DynamicJsonDocument.hpp" #include "ArduinoJson/DynamicJsonDocument.hpp"
#include "ArduinoJson/Json/JsonDeserializer.hpp" #include "ArduinoJson/Json/JsonDeserializer.hpp"
#include "ArduinoJson/Json/JsonSerializer.hpp" #include "ArduinoJson/Json/JsonSerializer.hpp"

View File

@ -256,15 +256,21 @@ class JsonObject : public Internals::ReferenceType,
template <typename TStringRef, typename TValueRef> template <typename TStringRef, typename TValueRef>
bool set_impl(TStringRef key, TValueRef value) { bool set_impl(TStringRef key, TValueRef value) {
// ignore null key
if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
// search a matching key
iterator it = findKey<TStringRef>(key); iterator it = findKey<TStringRef>(key);
if (it == end()) { if (it == end()) {
// add the key
it = Internals::List<JsonPair>::add(); it = Internals::List<JsonPair>::add();
if (it == end()) return false; if (it == end()) return false;
bool key_ok = bool key_ok =
Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key); Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key);
if (!key_ok) return false; if (!key_ok) return false;
} }
// save the value
return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value); return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value);
} }

View File

@ -129,7 +129,8 @@ class JsonVariantComparisons {
if (is<JsonObject>() && right.template is<JsonObject>()) if (is<JsonObject>() && right.template is<JsonObject>())
return as<JsonObject>() == right.template as<JsonObject>(); return as<JsonObject>() == right.template as<JsonObject>();
if (is<char *>() && right.template is<char *>()) if (is<char *>() && right.template is<char *>())
return strcmp(as<char *>(), right.template as<char *>()) == 0; return StringTraits<const char *>::equals(as<char *>(),
right.template as<char *>());
return false; return false;
} }

View File

@ -10,7 +10,9 @@ namespace Internals {
template <typename TChar> template <typename TChar>
struct CharPointerTraits { struct CharPointerTraits {
static bool equals(const TChar* str, const char* expected) { static bool equals(const TChar* str, const char* expected) {
return strcmp(reinterpret_cast<const char*>(str), expected) == 0; const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
} }
static bool is_null(const TChar* str) { static bool is_null(const TChar* str) {

View File

@ -11,7 +11,9 @@ namespace Internals {
template <> template <>
struct StringTraits<const __FlashStringHelper*, void> { struct StringTraits<const __FlashStringHelper*, void> {
static bool equals(const __FlashStringHelper* str, const char* expected) { static bool equals(const __FlashStringHelper* str, const char* expected) {
return strcmp_P(expected, (const char*)str) == 0; const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp_P(expected, actual) == 0;
} }
static bool is_null(const __FlashStringHelper* str) { static bool is_null(const __FlashStringHelper* str) {
@ -33,7 +35,7 @@ struct StringTraits<const __FlashStringHelper*, void> {
static const bool has_equals = true; static const bool has_equals = true;
static const bool should_duplicate = true; static const bool should_duplicate = true;
}; };
} } // namespace Internals
} } // namespace ArduinoJson
#endif #endif

View File

@ -36,7 +36,10 @@ struct StdStringTraits {
} }
static bool equals(const TString& str, const char* expected) { static bool equals(const TString& str, const char* expected) {
return 0 == strcmp(str.c_str(), expected); // Arduino's String::c_str() can return NULL
const char* actual = str.c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
} }
static void append(TString& str, char c) { static void append(TString& str, char c) {
@ -64,7 +67,7 @@ struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
template <> template <>
struct StringTraits<std::string, void> : StdStringTraits<std::string> {}; struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
#endif #endif
} } // namespace Internals
} } // namespace ArduinoJson
#endif #endif

View File

@ -0,0 +1,10 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#define ARDUINOJSON_VERSION "5.13.2"
#define ARDUINOJSON_VERSION_MAJOR 5
#define ARDUINOJSON_VERSION_MINOR 13
#define ARDUINOJSON_VERSION_REVISION 2

View File

@ -152,4 +152,15 @@ TEST_CASE("JsonObject::operator[]") {
const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12; const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12;
REQUIRE(expectedSize <= doc.memoryUsage()); REQUIRE(expectedSize <= doc.memoryUsage());
} }
SECTION("should ignore null key") {
// object must have a value to make a call to strcmp()
obj["dummy"] = 42;
const char* null = 0;
obj[null] = 666;
REQUIRE(obj.size() == 1);
REQUIRE(obj[null] == 0);
}
} }

View File

@ -5,6 +5,8 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <catch.hpp> #include <catch.hpp>
static const char* null = 0;
template <typename T> template <typename T>
void checkEquals(JsonVariant a, T b) { void checkEquals(JsonVariant a, T b) {
REQUIRE(b == a); REQUIRE(b == a);
@ -96,38 +98,69 @@ TEST_CASE("JsonVariant comparisons") {
checkComparisons<unsigned short>(122, 123, 124); checkComparisons<unsigned short>(122, 123, 124);
} }
SECTION("null") {
JsonVariant variant = null;
REQUIRE(variant == variant);
REQUIRE_FALSE(variant != variant);
REQUIRE(variant == null);
REQUIRE_FALSE(variant != null);
REQUIRE(variant != "null");
REQUIRE_FALSE(variant == "null");
}
SECTION("StringLiteral") { SECTION("StringLiteral") {
DynamicJsonDocument doc; DynamicJsonDocument doc;
deserializeJson(doc, "\"hello\""); deserializeJson(doc, "\"hello\"");
JsonVariant variant = doc.as<JsonVariant>(); JsonVariant variant = doc.as<JsonVariant>();
REQUIRE(variant == variant);
REQUIRE_FALSE(variant != variant);
REQUIRE(variant == "hello"); REQUIRE(variant == "hello");
REQUIRE_FALSE(variant != "hello"); REQUIRE_FALSE(variant != "hello");
REQUIRE(variant != "world"); REQUIRE(variant != "world");
REQUIRE_FALSE(variant == "world"); REQUIRE_FALSE(variant == "world");
REQUIRE(variant != null);
REQUIRE_FALSE(variant == null);
REQUIRE("hello" == variant); REQUIRE("hello" == variant);
REQUIRE_FALSE("hello" != variant); REQUIRE_FALSE("hello" != variant);
REQUIRE("world" != variant); REQUIRE("world" != variant);
REQUIRE_FALSE("world" == variant); REQUIRE_FALSE("world" == variant);
REQUIRE(null != variant);
REQUIRE_FALSE(null == variant);
} }
SECTION("String") { SECTION("String") {
JsonVariant variant = "hello"; JsonVariant variant = "hello";
REQUIRE(variant == variant);
REQUIRE_FALSE(variant != variant);
REQUIRE(variant == std::string("hello")); REQUIRE(variant == std::string("hello"));
REQUIRE_FALSE(variant != std::string("hello")); REQUIRE_FALSE(variant != std::string("hello"));
REQUIRE(variant != std::string("world")); REQUIRE(variant != std::string("world"));
REQUIRE_FALSE(variant == std::string("world")); REQUIRE_FALSE(variant == std::string("world"));
REQUIRE(variant != null);
REQUIRE_FALSE(variant == null);
REQUIRE(std::string("hello") == variant); REQUIRE(std::string("hello") == variant);
REQUIRE_FALSE(std::string("hello") != variant); REQUIRE_FALSE(std::string("hello") != variant);
REQUIRE(std::string("world") != variant); REQUIRE(std::string("world") != variant);
REQUIRE_FALSE(std::string("world") == variant); REQUIRE_FALSE(std::string("world") == variant);
REQUIRE(null != variant);
REQUIRE_FALSE(null == variant);
} }
SECTION("IntegerInVariant") { SECTION("IntegerInVariant") {

View File

@ -8,6 +8,7 @@ add_executable(MiscTests
StringTraits.cpp StringTraits.cpp
TypeTraits.cpp TypeTraits.cpp
unsigned_char.cpp unsigned_char.cpp
version.cpp
vla.cpp vla.cpp
) )

16
test/Misc/version.cpp Normal file
View File

@ -0,0 +1,16 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/version.hpp>
#include <catch.hpp>
#include <sstream>
TEST_CASE("ARDUINOJSON_VERSION") {
std::stringstream version;
version << ARDUINOJSON_VERSION_MAJOR << "." << ARDUINOJSON_VERSION_MINOR
<< "." << ARDUINOJSON_VERSION_REVISION;
REQUIRE(version.str() == ARDUINOJSON_VERSION);
}