diff --git a/CHANGELOG.md b/CHANGELOG.md index 378f1914..153621a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ HEAD * 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 `DeserializationError::EmptyInput` which tells if the input was empty * Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368) v6.16.1 (2020-08-04) diff --git a/extras/tests/JsonDeserializer/DeserializationError.cpp b/extras/tests/JsonDeserializer/DeserializationError.cpp index a04f25a1..332d06c4 100644 --- a/extras/tests/JsonDeserializer/DeserializationError.cpp +++ b/extras/tests/JsonDeserializer/DeserializationError.cpp @@ -30,20 +30,22 @@ void testBoolification(DeserializationError error, bool expected) { TEST_CASE("DeserializationError") { SECTION("c_str()") { TEST_STRINGIFICATION(Ok); - TEST_STRINGIFICATION(TooDeep); - TEST_STRINGIFICATION(NoMemory); - TEST_STRINGIFICATION(InvalidInput); + TEST_STRINGIFICATION(EmptyInput); TEST_STRINGIFICATION(IncompleteInput); + TEST_STRINGIFICATION(InvalidInput); + TEST_STRINGIFICATION(NoMemory); TEST_STRINGIFICATION(NotSupported); + TEST_STRINGIFICATION(TooDeep); } SECTION("as boolean") { TEST_BOOLIFICATION(Ok, false); - TEST_BOOLIFICATION(TooDeep, true); - TEST_BOOLIFICATION(NoMemory, true); - TEST_BOOLIFICATION(InvalidInput, true); + TEST_BOOLIFICATION(EmptyInput, true); TEST_BOOLIFICATION(IncompleteInput, true); + TEST_BOOLIFICATION(InvalidInput, true); + TEST_BOOLIFICATION(NoMemory, true); TEST_BOOLIFICATION(NotSupported, true); + TEST_BOOLIFICATION(TooDeep, true); } SECTION("ostream DeserializationError") { @@ -58,13 +60,6 @@ TEST_CASE("DeserializationError") { REQUIRE(s.str() == "InvalidInput"); } - SECTION("out of range") { - int code = 666; - DeserializationError err( - *reinterpret_cast(&code)); - REQUIRE(err.c_str() == std::string("???")); - } - SECTION("switch") { DeserializationError err = DeserializationError::InvalidInput; switch (err.code()) { diff --git a/extras/tests/JsonDeserializer/misc.cpp b/extras/tests/JsonDeserializer/misc.cpp index 0fe0e941..1d0cf2d0 100644 --- a/extras/tests/JsonDeserializer/misc.cpp +++ b/extras/tests/JsonDeserializer/misc.cpp @@ -27,7 +27,13 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { SECTION("Empty input") { DeserializationError err = deserializeJson(doc, ""); - REQUIRE(err == DeserializationError::IncompleteInput); + REQUIRE(err == DeserializationError::EmptyInput); + } + + SECTION("Only spaces") { + DeserializationError err = deserializeJson(doc, " \t\n\r"); + + REQUIRE(err == DeserializationError::EmptyInput); } SECTION("issue #628") { diff --git a/extras/tests/MixedConfiguration/enable_comments_1.cpp b/extras/tests/MixedConfiguration/enable_comments_1.cpp index 7e59bb03..5d223e52 100644 --- a/extras/tests/MixedConfiguration/enable_comments_1.cpp +++ b/extras/tests/MixedConfiguration/enable_comments_1.cpp @@ -373,16 +373,22 @@ TEST_CASE("Comments in objects") { TEST_CASE("Comments alone") { DynamicJsonDocument doc(2048); - SECTION("Just a trailing comment") { + SECTION("Just a trailing comment with no line break") { DeserializationError err = deserializeJson(doc, "// comment"); REQUIRE(err == DeserializationError::IncompleteInput); } + SECTION("Just a trailing comment with no a break") { + DeserializationError err = deserializeJson(doc, "// comment\n"); + + REQUIRE(err == DeserializationError::EmptyInput); + } + SECTION("Just a block comment") { DeserializationError err = deserializeJson(doc, "/*comment*/"); - REQUIRE(err == DeserializationError::IncompleteInput); + REQUIRE(err == DeserializationError::EmptyInput); } SECTION("Just a slash") { diff --git a/extras/tests/MsgPackDeserializer/CMakeLists.txt b/extras/tests/MsgPackDeserializer/CMakeLists.txt index f3f52f08..5052842d 100644 --- a/extras/tests/MsgPackDeserializer/CMakeLists.txt +++ b/extras/tests/MsgPackDeserializer/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(MsgPackDeserializerTests doubleToFloat.cpp incompleteInput.cpp input_types.cpp + misc.cpp nestingLimit.cpp notSupported.cpp ) diff --git a/extras/tests/MsgPackDeserializer/misc.cpp b/extras/tests/MsgPackDeserializer/misc.cpp new file mode 100644 index 00000000..0035c02f --- /dev/null +++ b/extras/tests/MsgPackDeserializer/misc.cpp @@ -0,0 +1,24 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +TEST_CASE("deserializeMsgPack() returns EmptyInput") { + StaticJsonDocument<100> doc; + + SECTION("from sized buffer") { + DeserializationError err = deserializeMsgPack(doc, "", 0); + + REQUIRE(err == DeserializationError::EmptyInput); + } + + SECTION("from stream") { + std::istringstream input(""); + + DeserializationError err = deserializeMsgPack(doc, input); + + REQUIRE(err == DeserializationError::EmptyInput); + } +} diff --git a/src/ArduinoJson/Deserialization/DeserializationError.hpp b/src/ArduinoJson/Deserialization/DeserializationError.hpp index 9ffd0de9..33cce207 100644 --- a/src/ArduinoJson/Deserialization/DeserializationError.hpp +++ b/src/ArduinoJson/Deserialization/DeserializationError.hpp @@ -20,6 +20,7 @@ class DeserializationError { public: enum Code { Ok, + EmptyInput, IncompleteInput, InvalidInput, NoMemory, @@ -77,22 +78,12 @@ class DeserializationError { } const char* c_str() const { - switch (_code) { - case Ok: - return "Ok"; - case TooDeep: - return "TooDeep"; - case NoMemory: - return "NoMemory"; - case InvalidInput: - return "InvalidInput"; - case IncompleteInput: - return "IncompleteInput"; - case NotSupported: - return "NotSupported"; - default: - return "???"; - } + static const char* messages[] = { + "Ok", "EmptyInput", "IncompleteInput", "InvalidInput", + "NoMemory", "NotSupported", "TooDeep"}; + ARDUINOJSON_ASSERT(static_cast(_code) < + sizeof(messages) / sizeof(messages[0])); + return messages[_code]; } private: diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index 29e1a836..81eb40a0 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -23,6 +23,7 @@ class JsonDeserializer { JsonDeserializer(MemoryPool &pool, TReader reader, TStringStorage stringStorage) : _stringStorage(stringStorage), + _foundSomething(false), _latch(reader), _pool(&pool), _error(DeserializationError::Ok) {} @@ -34,7 +35,7 @@ class JsonDeserializer { if (!_error && _latch.last() != 0 && !variant.isEnclosed()) { // We don't detect trailing characters earlier, so we need to check now - _error = DeserializationError::InvalidInput; + return DeserializationError::InvalidInput; } return _error; @@ -559,7 +560,8 @@ class JsonDeserializer { switch (current()) { // end of string case '\0': - _error = DeserializationError::IncompleteInput; + _error = _foundSomething ? DeserializationError::IncompleteInput + : DeserializationError::EmptyInput; return false; // spaces @@ -619,12 +621,14 @@ class JsonDeserializer { #endif default: + _foundSomething = true; return true; } } } TStringStorage _stringStorage; + bool _foundSomething; Latch _latch; MemoryPool *_pool; char _buffer[64]; // using a member instead of a local variable because it diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index 6802798f..4365a4dc 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -21,22 +21,23 @@ class MsgPackDeserializer { : _pool(&pool), _reader(reader), _stringStorage(stringStorage), - _error(DeserializationError::Ok) {} + _error(DeserializationError::Ok), + _foundSomething(false) {} // TODO: add support for filter DeserializationError parse(VariantData &variant, AllowAllFilter, NestingLimit nestingLimit) { parseVariant(variant, nestingLimit); - return _error; + return _foundSomething ? _error : DeserializationError::EmptyInput; } private: bool parseVariant(VariantData &variant, NestingLimit nestingLimit) { uint8_t code; - if (!readByte(code)) { - _error = DeserializationError::IncompleteInput; + if (!readByte(code)) return false; - } + + _foundSomething = true; if ((code & 0x80) == 0) { variant.setUnsignedInteger(code); @@ -345,6 +346,7 @@ class MsgPackDeserializer { TReader _reader; TStringStorage _stringStorage; DeserializationError _error; + bool _foundSomething; }; template