Added DeserializationError::EmptyInput

This commit is contained in:
Benoit Blanchon
2020-09-13 10:27:29 +02:00
parent 8993a093e9
commit c907ca6e5d
9 changed files with 69 additions and 39 deletions

View File

@ -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)
* Added `DeserializationError::EmptyInput` which tells if the input was empty
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368) * 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)

View File

@ -30,20 +30,22 @@ void testBoolification(DeserializationError error, bool expected) {
TEST_CASE("DeserializationError") { TEST_CASE("DeserializationError") {
SECTION("c_str()") { SECTION("c_str()") {
TEST_STRINGIFICATION(Ok); TEST_STRINGIFICATION(Ok);
TEST_STRINGIFICATION(TooDeep); TEST_STRINGIFICATION(EmptyInput);
TEST_STRINGIFICATION(NoMemory);
TEST_STRINGIFICATION(InvalidInput);
TEST_STRINGIFICATION(IncompleteInput); TEST_STRINGIFICATION(IncompleteInput);
TEST_STRINGIFICATION(InvalidInput);
TEST_STRINGIFICATION(NoMemory);
TEST_STRINGIFICATION(NotSupported); TEST_STRINGIFICATION(NotSupported);
TEST_STRINGIFICATION(TooDeep);
} }
SECTION("as boolean") { SECTION("as boolean") {
TEST_BOOLIFICATION(Ok, false); TEST_BOOLIFICATION(Ok, false);
TEST_BOOLIFICATION(TooDeep, true); TEST_BOOLIFICATION(EmptyInput, true);
TEST_BOOLIFICATION(NoMemory, true);
TEST_BOOLIFICATION(InvalidInput, true);
TEST_BOOLIFICATION(IncompleteInput, true); TEST_BOOLIFICATION(IncompleteInput, true);
TEST_BOOLIFICATION(InvalidInput, true);
TEST_BOOLIFICATION(NoMemory, true);
TEST_BOOLIFICATION(NotSupported, true); TEST_BOOLIFICATION(NotSupported, true);
TEST_BOOLIFICATION(TooDeep, true);
} }
SECTION("ostream DeserializationError") { SECTION("ostream DeserializationError") {
@ -58,13 +60,6 @@ TEST_CASE("DeserializationError") {
REQUIRE(s.str() == "InvalidInput"); REQUIRE(s.str() == "InvalidInput");
} }
SECTION("out of range") {
int code = 666;
DeserializationError err(
*reinterpret_cast<DeserializationError::Code*>(&code));
REQUIRE(err.c_str() == std::string("???"));
}
SECTION("switch") { SECTION("switch") {
DeserializationError err = DeserializationError::InvalidInput; DeserializationError err = DeserializationError::InvalidInput;
switch (err.code()) { switch (err.code()) {

View File

@ -27,7 +27,13 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
SECTION("Empty input") { SECTION("Empty input") {
DeserializationError err = deserializeJson(doc, ""); 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") { SECTION("issue #628") {

View File

@ -373,16 +373,22 @@ TEST_CASE("Comments in objects") {
TEST_CASE("Comments alone") { TEST_CASE("Comments alone") {
DynamicJsonDocument doc(2048); DynamicJsonDocument doc(2048);
SECTION("Just a trailing comment") { SECTION("Just a trailing comment with no line break") {
DeserializationError err = deserializeJson(doc, "// comment"); DeserializationError err = deserializeJson(doc, "// comment");
REQUIRE(err == DeserializationError::IncompleteInput); 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") { SECTION("Just a block comment") {
DeserializationError err = deserializeJson(doc, "/*comment*/"); DeserializationError err = deserializeJson(doc, "/*comment*/");
REQUIRE(err == DeserializationError::IncompleteInput); REQUIRE(err == DeserializationError::EmptyInput);
} }
SECTION("Just a slash") { SECTION("Just a slash") {

View File

@ -10,6 +10,7 @@ add_executable(MsgPackDeserializerTests
doubleToFloat.cpp doubleToFloat.cpp
incompleteInput.cpp incompleteInput.cpp
input_types.cpp input_types.cpp
misc.cpp
nestingLimit.cpp nestingLimit.cpp
notSupported.cpp notSupported.cpp
) )

View File

@ -0,0 +1,24 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
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);
}
}

View File

@ -20,6 +20,7 @@ class DeserializationError {
public: public:
enum Code { enum Code {
Ok, Ok,
EmptyInput,
IncompleteInput, IncompleteInput,
InvalidInput, InvalidInput,
NoMemory, NoMemory,
@ -77,22 +78,12 @@ class DeserializationError {
} }
const char* c_str() const { const char* c_str() const {
switch (_code) { static const char* messages[] = {
case Ok: "Ok", "EmptyInput", "IncompleteInput", "InvalidInput",
return "Ok"; "NoMemory", "NotSupported", "TooDeep"};
case TooDeep: ARDUINOJSON_ASSERT(static_cast<size_t>(_code) <
return "TooDeep"; sizeof(messages) / sizeof(messages[0]));
case NoMemory: return messages[_code];
return "NoMemory";
case InvalidInput:
return "InvalidInput";
case IncompleteInput:
return "IncompleteInput";
case NotSupported:
return "NotSupported";
default:
return "???";
}
} }
private: private:

View File

@ -23,6 +23,7 @@ class JsonDeserializer {
JsonDeserializer(MemoryPool &pool, TReader reader, JsonDeserializer(MemoryPool &pool, TReader reader,
TStringStorage stringStorage) TStringStorage stringStorage)
: _stringStorage(stringStorage), : _stringStorage(stringStorage),
_foundSomething(false),
_latch(reader), _latch(reader),
_pool(&pool), _pool(&pool),
_error(DeserializationError::Ok) {} _error(DeserializationError::Ok) {}
@ -34,7 +35,7 @@ class JsonDeserializer {
if (!_error && _latch.last() != 0 && !variant.isEnclosed()) { if (!_error && _latch.last() != 0 && !variant.isEnclosed()) {
// We don't detect trailing characters earlier, so we need to check now // We don't detect trailing characters earlier, so we need to check now
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
} }
return _error; return _error;
@ -559,7 +560,8 @@ class JsonDeserializer {
switch (current()) { switch (current()) {
// end of string // end of string
case '\0': case '\0':
_error = DeserializationError::IncompleteInput; _error = _foundSomething ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput;
return false; return false;
// spaces // spaces
@ -619,12 +621,14 @@ class JsonDeserializer {
#endif #endif
default: default:
_foundSomething = true;
return true; return true;
} }
} }
} }
TStringStorage _stringStorage; TStringStorage _stringStorage;
bool _foundSomething;
Latch<TReader> _latch; Latch<TReader> _latch;
MemoryPool *_pool; MemoryPool *_pool;
char _buffer[64]; // using a member instead of a local variable because it char _buffer[64]; // using a member instead of a local variable because it

View File

@ -21,22 +21,23 @@ class MsgPackDeserializer {
: _pool(&pool), : _pool(&pool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_error(DeserializationError::Ok) {} _error(DeserializationError::Ok),
_foundSomething(false) {}
// TODO: add support for filter // TODO: add support for filter
DeserializationError parse(VariantData &variant, AllowAllFilter, DeserializationError parse(VariantData &variant, AllowAllFilter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
parseVariant(variant, nestingLimit); parseVariant(variant, nestingLimit);
return _error; return _foundSomething ? _error : DeserializationError::EmptyInput;
} }
private: private:
bool parseVariant(VariantData &variant, NestingLimit nestingLimit) { bool parseVariant(VariantData &variant, NestingLimit nestingLimit) {
uint8_t code; uint8_t code;
if (!readByte(code)) { if (!readByte(code))
_error = DeserializationError::IncompleteInput;
return false; return false;
}
_foundSomething = true;
if ((code & 0x80) == 0) { if ((code & 0x80) == 0) {
variant.setUnsignedInteger(code); variant.setUnsignedInteger(code);
@ -345,6 +346,7 @@ class MsgPackDeserializer {
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
DeserializationError _error; DeserializationError _error;
bool _foundSomething;
}; };
template <typename TInput> template <typename TInput>