mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-16 03:52:16 +02:00
Fixed result of JsonVariant::set((char*)0)
(fixes #1368)
This commit is contained in:
@ -6,6 +6,7 @@ HEAD
|
|||||||
|
|
||||||
* Added a build failure when nullptr is defined as a macro (issue #1355)
|
* Added a build failure when nullptr is defined as a macro (issue #1355)
|
||||||
* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358)
|
* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358)
|
||||||
|
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
|
||||||
|
|
||||||
v6.16.1 (2020-08-04)
|
v6.16.1 (2020-08-04)
|
||||||
-------
|
-------
|
||||||
|
@ -7,115 +7,150 @@
|
|||||||
|
|
||||||
enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 };
|
enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 };
|
||||||
|
|
||||||
TEST_CASE("JsonVariant and strings") {
|
TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||||
DynamicJsonDocument doc(4096);
|
DynamicJsonDocument doc(4096);
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
JsonVariant variant = doc.to<JsonVariant>();
|
||||||
|
|
||||||
SECTION("stores const char* by reference") {
|
SECTION("const char*") {
|
||||||
char str[16];
|
char str[16];
|
||||||
|
|
||||||
strcpy(str, "hello");
|
strcpy(str, "hello");
|
||||||
variant.set(static_cast<const char *>(str));
|
bool result = variant.set(static_cast<const char *>(str));
|
||||||
strcpy(str, "world");
|
strcpy(str, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "world");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "world"); // stores by pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores char* by copy") {
|
SECTION("(const char*)0") {
|
||||||
char str[16];
|
bool result = variant.set(static_cast<const char *>(0));
|
||||||
|
|
||||||
strcpy(str, "hello");
|
REQUIRE(result == true);
|
||||||
variant.set(str);
|
REQUIRE(variant.isNull());
|
||||||
strcpy(str, "world");
|
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores unsigned char* by copy") {
|
SECTION("char*") {
|
||||||
char str[16];
|
char str[16];
|
||||||
|
|
||||||
strcpy(str, "hello");
|
strcpy(str, "hello");
|
||||||
variant.set(reinterpret_cast<unsigned char *>(str));
|
bool result = variant.set(str);
|
||||||
strcpy(str, "world");
|
strcpy(str, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "hello"); // stores by copy
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores signed char* by copy") {
|
SECTION("(char*)0") {
|
||||||
|
bool result = variant.set(static_cast<char *>(0));
|
||||||
|
|
||||||
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("unsigned char*") {
|
||||||
char str[16];
|
char str[16];
|
||||||
|
|
||||||
strcpy(str, "hello");
|
strcpy(str, "hello");
|
||||||
variant.set(reinterpret_cast<signed char *>(str));
|
bool result = variant.set(reinterpret_cast<unsigned char *>(str));
|
||||||
strcpy(str, "world");
|
strcpy(str, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "hello"); // stores by copy
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("signed char*") {
|
||||||
|
char str[16];
|
||||||
|
|
||||||
|
strcpy(str, "hello");
|
||||||
|
bool result = variant.set(reinterpret_cast<signed char *>(str));
|
||||||
|
strcpy(str, "world");
|
||||||
|
|
||||||
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "hello"); // stores by copy
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||||
SECTION("stores VLA by copy") {
|
SECTION("VLA") {
|
||||||
int n = 16;
|
int n = 16;
|
||||||
char str[n];
|
char str[n];
|
||||||
|
|
||||||
strcpy(str, "hello");
|
strcpy(str, "hello");
|
||||||
variant.set(str);
|
bool result = variant.set(str);
|
||||||
strcpy(str, "world");
|
strcpy(str, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "hello"); // stores by copy
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SECTION("stores std::string by copy") {
|
SECTION("std::string") {
|
||||||
std::string str;
|
std::string str;
|
||||||
|
|
||||||
str = "hello";
|
str = "hello";
|
||||||
variant.set(str);
|
bool result = variant.set(str);
|
||||||
str.replace(0, 5, "world");
|
str.replace(0, 5, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "hello"); // stores by copy
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores static JsonString by reference") {
|
SECTION("static JsonString") {
|
||||||
char str[16];
|
char str[16];
|
||||||
|
|
||||||
strcpy(str, "hello");
|
strcpy(str, "hello");
|
||||||
variant.set(JsonString(str, true));
|
bool result = variant.set(JsonString(str, true));
|
||||||
strcpy(str, "world");
|
strcpy(str, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "world");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "world"); // stores by pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores non-static JsonString by copy") {
|
SECTION("non-static JsonString") {
|
||||||
char str[16];
|
char str[16];
|
||||||
|
|
||||||
strcpy(str, "hello");
|
strcpy(str, "hello");
|
||||||
variant.set(JsonString(str, false));
|
bool result = variant.set(JsonString(str, false));
|
||||||
strcpy(str, "world");
|
strcpy(str, "world");
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
REQUIRE(result == true);
|
||||||
|
REQUIRE(variant == "hello"); // stores by copy
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores an enum as an integer") {
|
SECTION("enum") {
|
||||||
ErrorCode code = ERROR_10;
|
ErrorCode code = ERROR_10;
|
||||||
|
|
||||||
variant.set(code);
|
bool result = variant.set(code);
|
||||||
|
|
||||||
|
REQUIRE(result == true);
|
||||||
REQUIRE(variant.is<int>() == true);
|
REQUIRE(variant.is<int>() == true);
|
||||||
REQUIRE(variant.as<int>() == 10);
|
REQUIRE(variant.as<int>() == 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("JsonVariant with not enough memory") {
|
TEST_CASE("JsonVariant::set() with not enough memory") {
|
||||||
StaticJsonDocument<1> doc;
|
StaticJsonDocument<1> doc;
|
||||||
|
|
||||||
JsonVariant v = doc.to<JsonVariant>();
|
JsonVariant v = doc.to<JsonVariant>();
|
||||||
|
|
||||||
SECTION("std::string") {
|
SECTION("std::string") {
|
||||||
v.set(std::string("hello world!!"));
|
bool result = v.set(std::string("hello world!!"));
|
||||||
|
|
||||||
|
REQUIRE(result == false);
|
||||||
REQUIRE(v.isNull());
|
REQUIRE(v.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Serialized<std::string>") {
|
SECTION("Serialized<std::string>") {
|
||||||
v.set(serialized(std::string("hello world!!")));
|
bool result = v.set(serialized(std::string("hello world!!")));
|
||||||
|
|
||||||
|
REQUIRE(result == false);
|
||||||
|
REQUIRE(v.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("char*") {
|
||||||
|
char s[] = "hello world!!";
|
||||||
|
bool result = v.set(s);
|
||||||
|
|
||||||
|
REQUIRE(result == false);
|
||||||
REQUIRE(v.isNull());
|
REQUIRE(v.isNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,8 +347,7 @@ class JsonDeserializer {
|
|||||||
if (!parseQuotedString())
|
if (!parseQuotedString())
|
||||||
return false;
|
return false;
|
||||||
const char *value = _stringStorage.save();
|
const char *value = _stringStorage.save();
|
||||||
variant.setString(make_not_null(value),
|
variant.setStringPointer(value, typename TStringStorage::storage_policy());
|
||||||
typename TStringStorage::storage_policy());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,8 +233,7 @@ class MsgPackDeserializer {
|
|||||||
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
||||||
if (!readString(s, n))
|
if (!readString(s, n))
|
||||||
return false;
|
return false;
|
||||||
variant.setString(make_not_null(s),
|
variant.setStringPointer(s, typename TStringStorage::storage_policy());
|
||||||
typename TStringStorage::storage_policy());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
// ArduinoJson - arduinojson.org
|
|
||||||
// Copyright Benoit Blanchon 2014-2020
|
|
||||||
// MIT License
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ArduinoJson/Namespace.hpp>
|
|
||||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class not_null {
|
|
||||||
public:
|
|
||||||
explicit not_null(T ptr) : _ptr(ptr) {
|
|
||||||
ARDUINOJSON_ASSERT(ptr != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
T get() const {
|
|
||||||
ARDUINOJSON_ASSERT(_ptr != NULL);
|
|
||||||
return _ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T _ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
not_null<T> make_not_null(T ptr) {
|
|
||||||
ARDUINOJSON_ASSERT(ptr != NULL);
|
|
||||||
return not_null<T>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
|
@ -7,7 +7,6 @@
|
|||||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||||
#include <ArduinoJson/Misc/SerializedValue.hpp>
|
#include <ArduinoJson/Misc/SerializedValue.hpp>
|
||||||
#include <ArduinoJson/Numbers/convertNumber.hpp>
|
#include <ArduinoJson/Numbers/convertNumber.hpp>
|
||||||
#include <ArduinoJson/Polyfills/gsl/not_null.hpp>
|
|
||||||
#include <ArduinoJson/Strings/RamStringAdapter.hpp>
|
#include <ArduinoJson/Strings/RamStringAdapter.hpp>
|
||||||
#include <ArduinoJson/Variant/VariantContent.hpp>
|
#include <ArduinoJson/Variant/VariantContent.hpp>
|
||||||
|
|
||||||
@ -245,25 +244,14 @@ class VariantData {
|
|||||||
setType(VALUE_IS_NULL);
|
setType(VALUE_IS_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setString(not_null<const char *> s, storage_policies::store_by_copy) {
|
void setStringPointer(const char *s, storage_policies::store_by_copy) {
|
||||||
setType(VALUE_IS_OWNED_STRING);
|
setType(VALUE_IS_OWNED_STRING);
|
||||||
_content.asString = s.get();
|
_content.asString = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setString(not_null<const char *> s, storage_policies::store_by_address) {
|
void setStringPointer(const char *s, storage_policies::store_by_address) {
|
||||||
setType(VALUE_IS_LINKED_STRING);
|
setType(VALUE_IS_LINKED_STRING);
|
||||||
_content.asString = s.get();
|
_content.asString = s;
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TStoragePolicy>
|
|
||||||
bool setString(const char *s, TStoragePolicy storage_policy) {
|
|
||||||
if (s) {
|
|
||||||
setString(make_not_null(s), storage_policy);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
setType(VALUE_IS_NULL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
@ -283,14 +271,27 @@ class VariantData {
|
|||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline bool setString(TAdaptedString value, MemoryPool *,
|
inline bool setString(TAdaptedString value, MemoryPool *,
|
||||||
storage_policies::store_by_address) {
|
storage_policies::store_by_address) {
|
||||||
return setString(value.data(), storage_policies::store_by_address());
|
if (value.isNull())
|
||||||
|
setNull();
|
||||||
|
else
|
||||||
|
setStringPointer(value.data(), storage_policies::store_by_address());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline bool setString(TAdaptedString value, MemoryPool *pool,
|
inline bool setString(TAdaptedString value, MemoryPool *pool,
|
||||||
storage_policies::store_by_copy) {
|
storage_policies::store_by_copy) {
|
||||||
return setString(pool->saveString(value),
|
if (value.isNull()) {
|
||||||
storage_policies::store_by_copy());
|
setNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const char *copy = pool->saveString(value);
|
||||||
|
if (!copy) {
|
||||||
|
setNull();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setStringPointer(copy, storage_policies::store_by_copy());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionData &toArray() {
|
CollectionData &toArray() {
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include <stdint.h> // int8_t, int16_t
|
#include <stdint.h> // int8_t, int16_t
|
||||||
|
|
||||||
#include <ArduinoJson/Polyfills/gsl/not_null.hpp>
|
|
||||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||||
#include <ArduinoJson/Variant/VariantContent.hpp>
|
#include <ArduinoJson/Variant/VariantContent.hpp>
|
||||||
|
Reference in New Issue
Block a user