Added support for custom converters (closes #687)

This commit is contained in:
Benoit Blanchon
2021-03-20 14:52:47 +01:00
parent 53d6f0d492
commit d7f5b56ca4
29 changed files with 554 additions and 470 deletions

View File

@ -9,6 +9,7 @@ add_executable(JsonVariantTests
compare.cpp
containsKey.cpp
copy.cpp
converters.cpp
createNested.cpp
is.cpp
isnull.cpp

View File

@ -0,0 +1,144 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
namespace {
struct Date {
int day;
int month;
int year;
};
bool convertToJson(JsonVariant variant, const Date& date) {
variant["day"] = date.day;
variant["month"] = date.month;
variant["year"] = date.year;
return true;
}
void convertFromJson(Date& date, JsonVariantConst variant) {
date.day = variant["day"];
date.month = variant["month"];
date.year = variant["year"];
}
bool canConvertFromJson(Date&, JsonVariantConst variant) {
return variant["day"].is<int>() && variant["month"].is<int>() &&
variant["year"].is<int>();
}
} // namespace
TEST_CASE("Custom converter with overloading") {
DynamicJsonDocument doc(4096);
SECTION("convert JSON to Date") {
doc["date"]["day"] = 2;
doc["date"]["month"] = 3;
doc["date"]["year"] = 2021;
Date date = doc["date"];
REQUIRE(date.day == 2);
REQUIRE(date.month == 3);
REQUIRE(date.year == 2021);
}
SECTION("is<Date>() returns true") {
doc["date"]["day"] = 2;
doc["date"]["month"] = 3;
doc["date"]["year"] = 2021;
REQUIRE(doc["date"].is<Date>());
}
SECTION("is<Date>() returns false") {
doc["date"]["day"] = 2;
doc["date"]["month"] = 3;
doc["date"]["year"] = "2021";
REQUIRE(doc["date"].is<Date>() == false);
}
SECTION("convert Date to JSON") {
Date date = {19, 3, 2021};
doc["date"] = date;
REQUIRE(doc["date"]["day"] == 19);
REQUIRE(doc["date"]["month"] == 3);
REQUIRE(doc["date"]["year"] == 2021);
}
}
class Complex {
public:
explicit Complex(double r, double i) : _real(r), _imag(i) {}
double real() const {
return _real;
}
double imag() const {
return _imag;
}
private:
double _real, _imag;
};
namespace ARDUINOJSON_NAMESPACE {
template <>
struct Converter<Complex> {
static bool toJson(VariantRef variant, const Complex& value) {
variant["real"] = value.real();
variant["imag"] = value.imag();
return true;
}
static Complex fromJson(VariantConstRef variant) {
return Complex(variant["real"], variant["imag"]);
}
static bool checkJson(VariantConstRef variant) {
return variant["real"].is<double>() && variant["imag"].is<double>();
}
};
} // namespace ARDUINOJSON_NAMESPACE
TEST_CASE("Custom converter with specialization") {
DynamicJsonDocument doc(4096);
SECTION("convert JSON to Complex") {
doc["value"]["real"] = 2;
doc["value"]["imag"] = 3;
Complex value = doc["value"];
REQUIRE(value.real() == 2);
REQUIRE(value.imag() == 3);
}
SECTION("is<Complex>() returns true") {
doc["value"]["real"] = 2;
doc["value"]["imag"] = 3;
REQUIRE(doc["value"].is<Complex>());
}
SECTION("is<Complex>() returns false") {
doc["value"]["real"] = 2;
doc["value"]["imag"] = "3";
REQUIRE(doc["value"].is<Complex>() == false);
}
SECTION("convert value to JSON") {
doc["value"] = Complex(19, 3);
REQUIRE(doc["value"]["real"] == 19);
REQUIRE(doc["value"]["imag"] == 3);
}
}

View File

@ -19,7 +19,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariant>() == false);
CHECK(variant.is<JsonVariantConst>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<float>() == false);
@ -32,7 +32,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<float>() == false);
@ -47,7 +47,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<float>() == false);
@ -62,7 +62,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<float>() == false);
@ -83,7 +83,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<bool>() == false);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<std::string>() == false);
}
@ -97,7 +97,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<bool>() == false);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<MYENUM2>() == false);
@ -106,7 +106,7 @@ TEST_CASE("JsonVariant::is<T>()") {
SECTION("const char*") {
variant.set("4.2");
CHECK(variant.is<char *>() == true);
CHECK(variant.is<const char *>() == true);
CHECK(variant.is<const char *>() == true);
CHECK(variant.is<std::string>() == true);
CHECK(variant.is<JsonVariant>() == true);
@ -132,7 +132,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == false);
}
@ -148,7 +148,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<char *>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == false);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
@ -170,7 +170,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonVariantConst>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<float>() == false);
@ -183,7 +183,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<float>() == false);
@ -198,7 +198,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<float>() == false);
@ -213,7 +213,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<float>() == false);
@ -234,7 +234,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<std::string>() == false);
}
@ -248,7 +248,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
@ -257,7 +257,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
SECTION("const char*") {
variant.set("4.2");
CHECK(cvariant.is<char *>() == true);
CHECK(cvariant.is<const char *>() == true);
CHECK(cvariant.is<const char *>() == true);
CHECK(cvariant.is<std::string>() == true);
CHECK(cvariant.is<double>() == false);
@ -282,7 +282,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
@ -298,7 +298,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<char *>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
}

View File

@ -47,8 +47,8 @@ TEST_CASE("JsonVariant undefined") {
REQUIRE(variant.is<unsigned>() == false);
}
SECTION("char*") {
REQUIRE(variant.is<char*>() == false);
SECTION("const char*") {
REQUIRE(variant.is<const char*>() == false);
}
SECTION("double") {

View File

@ -3,7 +3,7 @@
// MIT License
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#include <ArduinoJson/Deserialization/Reader.hpp>
#include <ArduinoJson.hpp>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;

View File

@ -6,8 +6,7 @@
#define ARDUINOJSON_ENABLE_NAN 1
#define ARDUINOJSON_ENABLE_INFINITY 1
#include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Variant/VariantImpl.hpp>
#include <ArduinoJson.hpp>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;

View File

@ -6,8 +6,7 @@
#define ARDUINOJSON_ENABLE_NAN 1
#define ARDUINOJSON_ENABLE_INFINITY 1
#include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Variant/VariantImpl.hpp>
#include <ArduinoJson.hpp>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;

View File

@ -3,8 +3,7 @@
// MIT License
#include <stdint.h>
#include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Variant/VariantImpl.hpp>
#include <ArduinoJson.hpp>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;

View File

@ -2,9 +2,7 @@
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson/Numbers/Integer.hpp>
#include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Variant/VariantImpl.hpp>
#include <ArduinoJson.hpp>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;