Added support for non zero-terminated strings (fixes #704)

This commit is contained in:
Benoit Blanchon
2018-05-14 17:12:59 +02:00
parent 4c9c047ddf
commit ccb54136a2
54 changed files with 2234 additions and 1401 deletions

View File

@ -10,6 +10,8 @@ add_executable(JsonDeserializerTests
deserializeJsonValue.cpp
JsonError.cpp
nestingLimit.cpp
std_istream.cpp
std_string.cpp
)
target_link_libraries(JsonDeserializerTests catch)

View File

@ -25,6 +25,7 @@ TEST_CASE("JsonError") {
TEST_STRINGIFICATION(TooDeep);
TEST_STRINGIFICATION(NoMemory);
TEST_STRINGIFICATION(InvalidInput);
TEST_STRINGIFICATION(IncompleteInput);
}
SECTION("as boolean") {
@ -32,6 +33,7 @@ TEST_CASE("JsonError") {
TEST_BOOLIFICATION(TooDeep, true);
TEST_BOOLIFICATION(NoMemory, true);
TEST_BOOLIFICATION(InvalidInput, true);
TEST_BOOLIFICATION(IncompleteInput, true);
}
SECTION("ostream") {

View File

@ -164,13 +164,13 @@ TEST_CASE("deserialize JSON array") {
SECTION("Closing single quotes missing") {
JsonError err = deserializeJson(doc, "[\"]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Closing double quotes missing") {
JsonError err = deserializeJson(doc, "[\']");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
}
@ -233,21 +233,21 @@ TEST_CASE("deserialize JSON array") {
SECTION("/*/") {
JsonError err = deserializeJson(doc, "[/*/\n]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Unfinished comment") {
JsonError err = deserializeJson(doc, "[/*COMMENT]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Final slash missing") {
JsonError err = deserializeJson(doc, "[/*COMMENT*]");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Line comments") {
SECTION("Trailing comments") {
SECTION("Before opening bracket") {
JsonError err = deserializeJson(doc, "//COMMENT\n\t[\"hello\"]");
JsonArray& arr = doc.as<JsonArray>();
@ -311,39 +311,53 @@ TEST_CASE("deserialize JSON array") {
SECTION("End document with comment") {
JsonError err = deserializeJson(doc, "[//COMMENT");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Premature null-terminator") {
SECTION("After opening bracket") {
JsonError err = deserializeJson(doc, "[");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After value") {
JsonError err = deserializeJson(doc, "[1");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After comma") {
JsonError err = deserializeJson(doc, "[1,");
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Premature end of input") {
const char* input = "[1,2]";
SECTION("After opening bracket") {
JsonError err = deserializeJson(doc, input, 1);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After value") {
JsonError err = deserializeJson(doc, input, 2);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After comma") {
JsonError err = deserializeJson(doc, input, 3);
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Misc") {
SECTION("Garbage") {
JsonError err = deserializeJson(doc, "%*$£¤");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("The opening bracket is missing") {
JsonError err = deserializeJson(doc, "]");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("The closing bracket is missing") {
JsonError err = deserializeJson(doc, "[");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Escape sequences") {
JsonError err =
deserializeJson(doc, "[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]");
JsonArray& arr = doc.as<JsonArray>();
REQUIRE(err == JsonError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(arr[0] == "1\"2\\3/4\b5\f6\n7\r8\t9");
}
SECTION("Nested objects") {
char jsonString[] =
" [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] ";

View File

@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok);
REQUIRE(err == JsonError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithOneValue") {
@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok);
REQUIRE(err == JsonError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithNestedObject") {
@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
REQUIRE(err == JsonError::Ok);
}
SECTION("CharPtrNull") {
StaticJsonDocument<100> doc;
JsonError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err != JsonError::Ok);
}
SECTION("ConstCharPtrNull") {
StaticJsonDocument<100> doc;
JsonError err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err != JsonError::Ok);
}
SECTION("CopyStringNotSpaces") {
StaticJsonDocument<100> doc;

View File

@ -212,19 +212,39 @@ TEST_CASE("deserialize JSON object") {
}
}
SECTION("Misc") {
SECTION("The opening brace is missing") {
JsonError err = deserializeJson(doc, "}");
SECTION("Premature null terminator") {
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("The closing brace is missing") {
SECTION("After key") {
JsonError err = deserializeJson(doc, "{\"hello\"");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\":");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After value") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"");
REQUIRE(err == JsonError::InvalidInput);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("After comma") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\",");
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Misc") {
SECTION("A quoted key without value") {
JsonError err = deserializeJson(doc, "{\"key\"}");
@ -250,6 +270,200 @@ TEST_CASE("deserialize JSON object") {
}
}
SECTION("Block comments") {
SECTION("Before opening brace") {
JsonError err = deserializeJson(doc, "/*COMMENT*/ {\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{/*COMMENT*/\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before colon") {
JsonError err = deserializeJson(doc, "{\"hello\"/*COMMENT*/:\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\":/*COMMENT*/\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"/*COMMENT*/}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}/*COMMENT*/");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\"/*COMMENT*/,\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
SECTION("After comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\",/*COMMENT*/\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
}
SECTION("Trailing comments") {
SECTION("Before opening brace") {
JsonError err = deserializeJson(doc, "//COMMENT\n {\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{//COMMENT\n\"hello\":\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before colon") {
JsonError err = deserializeJson(doc, "{\"hello\"//COMMENT\n:\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\"://COMMENT\n\"world\"}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"//COMMENT\n}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("After closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}//COMMENT\n");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\"//COMMENT\n,\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
SECTION("After comma") {
JsonError err = deserializeJson(
doc, "{\"hello\":\"world\",//COMMENT\n\"answer\":42}");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
REQUIRE(obj["answer"] == 42);
}
}
SECTION("Dangling slash") {
SECTION("Before opening brace") {
JsonError err = deserializeJson(doc, "/{\"hello\":\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After opening brace") {
JsonError err = deserializeJson(doc, "{/\"hello\":\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Before colon") {
JsonError err = deserializeJson(doc, "{\"hello\"/:\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After colon") {
JsonError err = deserializeJson(doc, "{\"hello\":/\"world\"}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Before closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"/}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After closing brace") {
JsonError err = deserializeJson(doc, "{\"hello\":\"world\"}/");
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(obj["hello"] == "world");
}
SECTION("Before comma") {
JsonError err =
deserializeJson(doc, "{\"hello\":\"world\"/,\"answer\":42}");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("After comma") {
JsonError err =
deserializeJson(doc, "{\"hello\":\"world\",/\"answer\":42}");
REQUIRE(err == JsonError::InvalidInput);
}
}
SECTION("Should clear the JsonObject") {
deserializeJson(doc, "{\"hello\":\"world\"}");
deserializeJson(doc, "{}");

View File

@ -21,7 +21,7 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") {
JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok);
REQUIRE(err == JsonError::NoMemory);
}
SECTION("BufferOfTheRightSizeForObjectWithOneValue") {
@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") {
JsonError err = deserializeJson(doc, input);
REQUIRE(err != JsonError::Ok);
REQUIRE(err == JsonError::NoMemory);
}
SECTION("BufferOfTheRightSizeForObjectWithNestedObject") {
@ -51,22 +51,6 @@ TEST_CASE("deserialize JSON object with StaticJsonDocument") {
REQUIRE(err == JsonError::Ok);
}
SECTION("CharPtrNull") {
StaticJsonDocument<100> doc;
JsonError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err != JsonError::Ok);
}
SECTION("ConstCharPtrNull") {
StaticJsonDocument<100> doc;
JsonError err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err != JsonError::Ok);
}
SECTION("Should clear the JsonObject") {
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
char input[] = "{\"hello\":\"world\"}";

View File

@ -10,18 +10,16 @@ using namespace Catch::Matchers;
TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
DynamicJsonDocument doc;
SECTION("EmptyObject") {
JsonError err = deserializeJson(doc, "{}");
SECTION("null char*") {
JsonError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.is<JsonObject>());
REQUIRE(err != JsonError::Ok);
}
SECTION("EmptyArray") {
JsonError err = deserializeJson(doc, "[]");
SECTION("null const char*") {
JsonError err = deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.is<JsonArray>());
REQUIRE(err != JsonError::Ok);
}
SECTION("Integer") {
@ -58,6 +56,14 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE_THAT(doc.as<char*>(), Equals("hello world"));
}
SECTION("Escape sequences") {
JsonError err =
deserializeJson(doc, "\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.as<std::string>() == "1\"2\\3/4\b5\f6\n7\r8\t9");
}
SECTION("True") {
JsonError err = deserializeJson(doc, "true");
@ -74,25 +80,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.as<bool>() == false);
}
SECTION("OpenBrace") {
JsonError err = deserializeJson(doc, "{");
REQUIRE(err != JsonError::Ok);
}
SECTION("Incomplete string") {
JsonError err = deserializeJson(doc, "\"hello");
REQUIRE(err == JsonError::Ok);
REQUIRE(doc.is<char*>());
REQUIRE_THAT(doc.as<char*>(), Equals("hello"));
}
SECTION("Unterminated escape sequence") {
JsonError err = deserializeJson(doc, "\"\\\0\"");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Should clear the JsonVariant") {
deserializeJson(doc, "[1,2,3]");
deserializeJson(doc, "{}");
@ -100,4 +87,86 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0));
}
SECTION("Empty input") {
JsonError err = deserializeJson(doc, "");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Just a trailing comment") {
JsonError err = deserializeJson(doc, "// comment");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Just a block comment") {
JsonError err = deserializeJson(doc, "/*comment*/");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("Just a slash") {
JsonError err = deserializeJson(doc, "/");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Garbage") {
JsonError err = deserializeJson(doc, "%*$£¤");
REQUIRE(err == JsonError::InvalidInput);
}
SECTION("Premature null-terminator") {
SECTION("In escape sequence") {
JsonError err = deserializeJson(doc, "\"\\");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In block comment") {
JsonError err = deserializeJson(doc, "/* comment");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In double quoted string") {
JsonError err = deserializeJson(doc, "\"hello");
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In single quoted string") {
JsonError err = deserializeJson(doc, "'hello");
REQUIRE(err == JsonError::IncompleteInput);
}
}
SECTION("Premature end of input") {
SECTION("In escape sequence") {
JsonError err = deserializeJson(doc, "\"\\n\"", 2);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In block comment") {
JsonError err = deserializeJson(doc, "/* comment */", 10);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In double quoted string") {
JsonError err = deserializeJson(doc, "\"hello\"", 6);
REQUIRE(err == JsonError::IncompleteInput);
}
SECTION("In single quoted string") {
JsonError err = deserializeJson(doc, "'hello'", 6);
REQUIRE(err == JsonError::IncompleteInput);
}
}
}

View File

@ -0,0 +1,73 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include <sstream>
TEST_CASE("deserializeJson(std::istream&)") {
DynamicJsonDocument doc;
SECTION("array") {
std::istringstream json(" [ 42 /* comment */ ] ");
JsonError err = deserializeJson(doc, json);
JsonArray& arr = doc.as<JsonArray>();
REQUIRE(err == JsonError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(42 == arr[0]);
}
SECTION("object") {
std::istringstream json(" { hello : world // comment\n }");
JsonError err = deserializeJson(doc, json);
JsonObject& obj = doc.as<JsonObject>();
REQUIRE(err == JsonError::Ok);
REQUIRE(1 == obj.size());
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("Should not read after the closing brace of an empty object") {
std::istringstream json("{}123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing brace") {
std::istringstream json("{\"hello\":\"world\"}123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing bracket of an empty array") {
std::istringstream json("[]123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing bracket") {
std::istringstream json("[\"hello\",\"world\"]123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing quote") {
std::istringstream json("\"hello\"123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
}

View File

@ -0,0 +1,35 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc;
SECTION("should accept const string") {
const std::string input("[42]");
JsonError err = deserializeJson(doc, input);
REQUIRE(err == JsonError::Ok);
}
SECTION("should accept temporary string") {
JsonError err = deserializeJson(doc, std::string("[42]"));
REQUIRE(err == JsonError::Ok);
}
SECTION("should duplicate content") {
std::string input("[\"hello\"]");
JsonError err = deserializeJson(doc, input);
input[2] = 'X'; // alter the string tomake sure we made a copy
JsonArray &array = doc.as<JsonArray>();
REQUIRE(err == JsonError::Ok);
REQUIRE(std::string("hello") == array[0]);
}
}