diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 90cf5670..a803d5cc 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -2,10 +2,10 @@ Thanks for using ArduinoJson :-) Before opening an issue, please make sure you've read these: -https://github.com/bblanchon/ArduinoJson/wiki/FAQ +https://bblanchon.github.io/ArduinoJson/faq/ https://github.com/bblanchon/ArduinoJson/wiki/Avoiding-pitfalls Next, make sure you provide all the relevant information: platform, code snippet, and error messages. Please be concise! ---> \ No newline at end of file +--> diff --git a/CHANGELOG.md b/CHANGELOG.md index f90f60f9..0649c8fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ HEAD ---- * Fixed an access violation in `DynamicJsonBuffer` when memory allocation fails (issue #433) +* Added operators `==` and `!=` for two `JsonVariant`s (issue #436) v5.8.2 ------ diff --git a/include/ArduinoJson/Data/JsonVariantComparer.hpp b/include/ArduinoJson/Data/JsonVariantComparer.hpp new file mode 100644 index 00000000..9a198253 --- /dev/null +++ b/include/ArduinoJson/Data/JsonVariantComparer.hpp @@ -0,0 +1,69 @@ +// Copyright Benoit Blanchon 2014-2017 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../JsonVariantBase.hpp" +#include "../StringTraits/StringTraits.hpp" +#include "../TypeTraits/EnableIf.hpp" + +namespace ArduinoJson { +namespace Internals { +template +struct JsonVariantComparer {}; + +template +struct JsonVariantComparer< + TString, + typename TypeTraits::EnableIf::value>::type> { + template + static bool equals(const JsonVariantBase &variant, + const TString &comparand) { + const char *value = variant.template as(); + return Internals::StringTraits::equals(comparand, value); + } +}; + +template +struct JsonVariantComparer< + TComparand, typename TypeTraits::EnableIf< + !TypeTraits::IsVariant::value && + !TypeTraits::IsString::value>::type> { + template + static bool equals(const JsonVariantBase &variant, + const TComparand &comparand) { + return variant.template as() == comparand; + } +}; + +template +struct JsonVariantComparer::value>::type> { + template + static bool equals(const JsonVariantBase &left, + const TVariant2 &right) { + if (left.template is() && right.template is()) + return left.template as() == right.template as(); + if (left.template is() && right.template is()) + return left.template as() == + right.template as(); + if (left.template is() && right.template is()) + return left.template as() == right.template as(); + if (left.template is() && right.template is()) + return left.template as() == right.template as(); + if (left.template is() && right.template is()) + return left.template as() == right.template as(); + if (left.template is() && right.template is()) + return strcmp(left.template as(), right.template as()) == + 0; + + return false; + } +}; +} +} diff --git a/include/ArduinoJson/JsonVariantBase.hpp b/include/ArduinoJson/JsonVariantBase.hpp index b2024894..8961a3f4 100644 --- a/include/ArduinoJson/JsonVariantBase.hpp +++ b/include/ArduinoJson/JsonVariantBase.hpp @@ -63,6 +63,11 @@ class JsonVariantBase : public Internals::JsonPrintable { return impl()->template as(); } + template + FORCE_INLINE bool is() const { + return impl()->template is(); + } + // Mimics an array or an object. // Returns the size of the array or object if the variant has that type. // Returns 0 if the variant is neither an array nor an object @@ -126,4 +131,9 @@ class JsonVariantBase : public Internals::JsonPrintable { return static_cast(this); } }; + +namespace TypeTraits { +template +struct IsVariant : IsBaseOf, T> {}; +} } diff --git a/include/ArduinoJson/JsonVariantComparisons.hpp b/include/ArduinoJson/JsonVariantComparisons.hpp index 590670e3..9e8b9fff 100644 --- a/include/ArduinoJson/JsonVariantComparisons.hpp +++ b/include/ArduinoJson/JsonVariantComparisons.hpp @@ -7,100 +7,82 @@ #pragma once -#include "JsonVariantBase.hpp" -#include "StringTraits/StringTraits.hpp" -#include "TypeTraits/EnableIf.hpp" +#include "Data/JsonVariantComparer.hpp" namespace ArduinoJson { -template -struct JsonVariantComparer { - static bool equals(const TVariant &variant, const TComparand &comparand) { - return variant.template as() == comparand; - } -}; - -template -struct JsonVariantComparer< - TVariant, TString, typename TypeTraits::EnableIf::has_equals>::type> { - static bool equals(const TVariant &variant, const TString &comparand) { - const char *value = variant.template as(); - return Internals::StringTraits::equals(comparand, value); - } -}; - -template -inline bool operator==(const JsonVariantBase &variant, +template +inline bool operator==(const JsonVariantBase &variant, TComparand comparand) { - typedef JsonVariantBase TVariant; - return JsonVariantComparer::equals(variant, comparand); + return Internals::JsonVariantComparer::equals(variant, comparand); } -template -inline bool operator==(TComparand comparand, - const JsonVariantBase &variant) { - typedef JsonVariantBase TVariant; - return JsonVariantComparer::equals(variant, comparand); +template +inline typename TypeTraits::EnableIf::value, + bool>::type +operator==(TComparand comparand, const JsonVariantBase &variant) { + return Internals::JsonVariantComparer::equals(variant, comparand); } -template -inline bool operator!=(const JsonVariantBase &variant, +template +inline bool operator!=(const JsonVariantBase &variant, TComparand comparand) { - typedef JsonVariantBase TVariant; - return !JsonVariantComparer::equals(variant, comparand); + return !Internals::JsonVariantComparer::equals(variant, + comparand); } -template -inline bool operator!=(TComparand comparand, - const JsonVariantBase &variant) { - typedef JsonVariantBase TVariant; - return !JsonVariantComparer::equals(variant, comparand); +template +inline typename TypeTraits::EnableIf::value, + bool>::type +operator!=(TComparand comparand, const JsonVariantBase &variant) { + return !Internals::JsonVariantComparer::equals(variant, + comparand); } -template -inline bool operator<=(const JsonVariantBase &left, TComparand right) { +template +inline bool operator<=(const JsonVariantBase &left, + TComparand right) { return left.template as() <= right; } -template +template inline bool operator<=(TComparand comparand, - const JsonVariantBase &variant) { + const JsonVariantBase &variant) { return comparand <= variant.template as(); } -template -inline bool operator>=(const JsonVariantBase &variant, +template +inline bool operator>=(const JsonVariantBase &variant, TComparand comparand) { return variant.template as() >= comparand; } -template +template inline bool operator>=(TComparand comparand, - const JsonVariantBase &variant) { + const JsonVariantBase &variant) { return comparand >= variant.template as(); } -template -inline bool operator<(const JsonVariantBase &varian, +template +inline bool operator<(const JsonVariantBase &varian, TComparand comparand) { return varian.template as() < comparand; } -template +template inline bool operator<(TComparand comparand, - const JsonVariantBase &variant) { + const JsonVariantBase &variant) { return comparand < variant.template as(); } -template -inline bool operator>(const JsonVariantBase &variant, +template +inline bool operator>(const JsonVariantBase &variant, TComparand comparand) { return variant.template as() > comparand; } -template +template inline bool operator>(TComparand comparand, - const JsonVariantBase &variant) { + const JsonVariantBase &variant) { return comparand > variant.template as(); } } diff --git a/include/ArduinoJson/StringTraits/StdString.hpp b/include/ArduinoJson/StringTraits/StdString.hpp index 78ec5967..e9b54df9 100644 --- a/include/ArduinoJson/StringTraits/StdString.hpp +++ b/include/ArduinoJson/StringTraits/StdString.hpp @@ -34,7 +34,7 @@ struct StdStringTraits { }; static bool equals(const TString& str, const char* expected) { - return str == expected; + return 0 == strcmp(str.c_str(), expected); } static void append(TString& str, char c) { diff --git a/include/ArduinoJson/StringTraits/StringTraits.hpp b/include/ArduinoJson/StringTraits/StringTraits.hpp index 3f0b63f2..0e128e94 100644 --- a/include/ArduinoJson/StringTraits/StringTraits.hpp +++ b/include/ArduinoJson/StringTraits/StringTraits.hpp @@ -40,3 +40,18 @@ struct StringTraits : StringTraits {}; #if ARDUINOJSON_ENABLE_PROGMEM #include "FlashString.hpp" #endif + +namespace ArduinoJson { +namespace TypeTraits { +template +struct IsString { + static const bool value = false; +}; + +template +struct IsString::has_equals>::type> { + static const bool value = Internals::StringTraits::has_equals; +}; +} +} diff --git a/test/JsonVariant_Comparison_Tests.cpp b/test/JsonVariant_Comparison_Tests.cpp index 9623c84c..67614a1a 100644 --- a/test/JsonVariant_Comparison_Tests.cpp +++ b/test/JsonVariant_Comparison_Tests.cpp @@ -126,3 +126,103 @@ TEST_F(JsonVariant_Comparison_Tests, String) { ASSERT_TRUE(std::string("world") != variant); ASSERT_FALSE(std::string("world") == variant); } + +TEST_F(JsonVariant_Comparison_Tests, IntegerInVariant) { + JsonVariant variant1 = 42; + JsonVariant variant2 = 42; + JsonVariant variant3 = 666; + + ASSERT_TRUE(variant1 == variant2); + ASSERT_FALSE(variant1 != variant2); + + ASSERT_TRUE(variant1 != variant3); + ASSERT_FALSE(variant1 == variant3); +} + +TEST_F(JsonVariant_Comparison_Tests, StringInVariant) { + JsonVariant variant1 = "0hello" + 1; // make sure they have + JsonVariant variant2 = "1hello" + 1; // different addresses + JsonVariant variant3 = "world"; + + ASSERT_TRUE(variant1 == variant2); + ASSERT_FALSE(variant1 != variant2); + + ASSERT_TRUE(variant1 != variant3); + ASSERT_FALSE(variant1 == variant3); +} + +TEST_F(JsonVariant_Comparison_Tests, DoubleInVariant) { + JsonVariant variant1 = 42.0; + JsonVariant variant2 = 42.0; + JsonVariant variant3 = 666.0; + + ASSERT_TRUE(variant1 == variant2); + ASSERT_FALSE(variant1 != variant2); + + ASSERT_TRUE(variant1 != variant3); + ASSERT_FALSE(variant1 == variant3); +} + +TEST_F(JsonVariant_Comparison_Tests, BoolInVariant) { + JsonVariant variant1 = true; + JsonVariant variant2 = true; + JsonVariant variant3 = false; + + ASSERT_TRUE(variant1 == variant2); + ASSERT_FALSE(variant1 != variant2); + + ASSERT_TRUE(variant1 != variant3); + ASSERT_FALSE(variant1 == variant3); +} + +TEST_F(JsonVariant_Comparison_Tests, ArrayInVariant) { + DynamicJsonBuffer jsonBuffer; + JsonArray& array1 = jsonBuffer.createArray(); + JsonArray& array2 = jsonBuffer.createArray(); + + JsonVariant variant1 = array1; + JsonVariant variant2 = array1; + JsonVariant variant3 = array2; + + ASSERT_TRUE(variant1 == variant2); + ASSERT_FALSE(variant1 != variant2); + + ASSERT_TRUE(variant1 != variant3); + ASSERT_FALSE(variant1 == variant3); +} + +TEST_F(JsonVariant_Comparison_Tests, ObjectInVariant) { + DynamicJsonBuffer jsonBuffer; + JsonObject& obj1 = jsonBuffer.createObject(); + JsonObject& obj2 = jsonBuffer.createObject(); + + JsonVariant variant1 = obj1; + JsonVariant variant2 = obj1; + JsonVariant variant3 = obj2; + + ASSERT_TRUE(variant1 == variant2); + ASSERT_FALSE(variant1 != variant2); + + ASSERT_TRUE(variant1 != variant3); + ASSERT_FALSE(variant1 == variant3); +} + +TEST_F(JsonVariant_Comparison_Tests, VariantsOfDifferentTypes) { + DynamicJsonBuffer jsonBuffer; + JsonVariant variants[] = { + true, + 42, + 666.667, + "hello", + jsonBuffer.createArray(), + jsonBuffer.createObject(), + }; + size_t n = sizeof(variants) / sizeof(variants[0]); + + for (size_t i = 0; i < n; i++) { + for (size_t j = i + 1; j < n; j++) { + ASSERT_TRUE(variants[i] != variants[j]); + ASSERT_FALSE(variants[i] == variants[j]); + } + } +} diff --git a/test/TypeTraits_Tests.cpp b/test/TypeTraits_Tests.cpp index 12a320da..0618ba27 100644 --- a/test/TypeTraits_Tests.cpp +++ b/test/TypeTraits_Tests.cpp @@ -11,13 +11,26 @@ using namespace ArduinoJson::TypeTraits; -TEST(StdStream, IsBaseOf) { +TEST(TypeTraits, IsBaseOf) { ASSERT_FALSE((IsBaseOf::value)); ASSERT_TRUE((IsBaseOf::value)); + ASSERT_TRUE((IsBaseOf >, + JsonObjectSubscript >::value)); } -TEST(StdStream, IsArray) { +TEST(TypeTraits, IsArray) { ASSERT_FALSE((IsArray::value)); ASSERT_TRUE((IsArray::value)); ASSERT_TRUE((IsArray::value)); } + +TEST(TypeTraits, IsVariant) { + ASSERT_TRUE((IsVariant >::value)); + ASSERT_TRUE((IsVariant::value)); +} + +TEST(TypeTraits, IsString) { + ASSERT_TRUE((IsString::value)); + ASSERT_TRUE((IsString::value)); + ASSERT_FALSE((IsString::value)); +}