From 04fe7e1a27645b09c7e924fb513e022d169baf97 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Mon, 13 Jan 2020 18:16:02 +0100 Subject: [PATCH] Added ARDUINOJSON_ENABLE_COMMENTS to enable support for comments --- CHANGELOG.md | 13 + extras/tests/JsonDeserializer/array.cpp | 149 ------- extras/tests/JsonDeserializer/input_types.cpp | 4 +- extras/tests/JsonDeserializer/misc.cpp | 32 -- extras/tests/JsonDeserializer/object.cpp | 206 --------- .../tests/MixedConfiguration/CMakeLists.txt | 2 + .../MixedConfiguration/enable_comments_0.cpp | 54 +++ .../MixedConfiguration/enable_comments_1.cpp | 405 ++++++++++++++++++ src/ArduinoJson/Configuration.hpp | 5 + src/ArduinoJson/Json/JsonDeserializer.hpp | 2 + src/ArduinoJson/Namespace.hpp | 9 +- 11 files changed, 488 insertions(+), 393 deletions(-) create mode 100644 extras/tests/MixedConfiguration/enable_comments_0.cpp create mode 100644 extras/tests/MixedConfiguration/enable_comments_1.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index e2056f8f..3dfe35a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,24 @@ HEAD * Added `BasicJsonDocument::shrinkToFit()` * Added support of `uint8_t` for `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` (issue #1142) +* Added `ARDUINOJSON_ENABLE_COMMENTS` to enable support for comments (defaults to 0) * Auto enable support for `std::string` and `std::stream` on modern compilers (issue #1156) (No need to define `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_STD_STREAM` anymore) * Improved decoding of UTF-16 surrogate pairs (PR #1157 by @kaysievers) (ArduinoJson now produces standard UTF-8 instead of CESU-8) +> ### BREAKING CHANGES +> +> #### Comments +> +> Support for comments in input is now optional and disabled by default. +> +> If you need support for comments, you must defined `ARDUINOJSON_ENABLE_COMMENTS` to `1`; otherwise, you'll receive `InvalidInput` errors. +> +> ```c++ +> #define ARDUINOJSON_ENABLE_COMMENTS 1 +> #include +> ``` v6.13.0 (2019-11-01) ------- diff --git a/extras/tests/JsonDeserializer/array.cpp b/extras/tests/JsonDeserializer/array.cpp index 9f730827..a3b0a146 100644 --- a/extras/tests/JsonDeserializer/array.cpp +++ b/extras/tests/JsonDeserializer/array.cpp @@ -170,155 +170,6 @@ TEST_CASE("deserialize JSON array") { } } - SECTION("Block comments") { - SECTION("Before opening bracket") { - DeserializationError err = - deserializeJson(doc, "/*COMMENT*/ [\"hello\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("After opening bracket") { - DeserializationError err = - deserializeJson(doc, "[/*COMMENT*/ \"hello\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("Before closing bracket") { - DeserializationError err = deserializeJson(doc, "[\"hello\"/*COMMENT*/]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("After closing bracket") { - DeserializationError err = deserializeJson(doc, "[\"hello\"]/*COMMENT*/"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("Before comma") { - DeserializationError err = - deserializeJson(doc, "[\"hello\"/*COMMENT*/,\"world\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(2 == arr.size()); - REQUIRE(arr[0] == "hello"); - REQUIRE(arr[1] == "world"); - } - - SECTION("After comma") { - DeserializationError err = - deserializeJson(doc, "[\"hello\",/*COMMENT*/ \"world\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(2 == arr.size()); - REQUIRE(arr[0] == "hello"); - REQUIRE(arr[1] == "world"); - } - - SECTION("/*/") { - DeserializationError err = deserializeJson(doc, "[/*/\n]"); - REQUIRE(err == DeserializationError::IncompleteInput); - } - - SECTION("Unfinished comment") { - DeserializationError err = deserializeJson(doc, "[/*COMMENT]"); - REQUIRE(err == DeserializationError::IncompleteInput); - } - - SECTION("Final slash missing") { - DeserializationError err = deserializeJson(doc, "[/*COMMENT*]"); - REQUIRE(err == DeserializationError::IncompleteInput); - } - } - - SECTION("Trailing comments") { - SECTION("Before opening bracket") { - DeserializationError err = - deserializeJson(doc, "//COMMENT\n\t[\"hello\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("After opening bracket") { - DeserializationError err = deserializeJson(doc, "[//COMMENT\n\"hello\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("Before closing bracket") { - DeserializationError err = - deserializeJson(doc, "[\"hello\"//COMMENT\r\n]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("After closing bracket") { - DeserializationError err = deserializeJson(doc, "[\"hello\"]//COMMENT\n"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(1 == arr.size()); - REQUIRE(arr[0] == "hello"); - } - - SECTION("Before comma") { - DeserializationError err = - deserializeJson(doc, "[\"hello\"//COMMENT\n,\"world\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(2 == arr.size()); - REQUIRE(arr[0] == "hello"); - REQUIRE(arr[1] == "world"); - } - - SECTION("After comma") { - DeserializationError err = - deserializeJson(doc, "[\"hello\",//COMMENT\n\"world\"]"); - JsonArray arr = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(2 == arr.size()); - REQUIRE(arr[0] == "hello"); - REQUIRE(arr[1] == "world"); - } - - SECTION("Invalid comment") { - DeserializationError err = deserializeJson(doc, "[/COMMENT\n]"); - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("End document with comment") { - DeserializationError err = deserializeJson(doc, "[//COMMENT"); - REQUIRE(err == DeserializationError::IncompleteInput); - } - } - SECTION("Premature null-terminator") { SECTION("After opening bracket") { DeserializationError err = deserializeJson(doc, "["); diff --git a/extras/tests/JsonDeserializer/input_types.cpp b/extras/tests/JsonDeserializer/input_types.cpp index 7209e387..17294f24 100644 --- a/extras/tests/JsonDeserializer/input_types.cpp +++ b/extras/tests/JsonDeserializer/input_types.cpp @@ -41,7 +41,7 @@ TEST_CASE("deserializeJson(std::istream&)") { DynamicJsonDocument doc(4096); SECTION("array") { - std::istringstream json(" [ 42 /* comment */ ] "); + std::istringstream json(" [ 42 ] "); DeserializationError err = deserializeJson(doc, json); JsonArray arr = doc.as(); @@ -52,7 +52,7 @@ TEST_CASE("deserializeJson(std::istream&)") { } SECTION("object") { - std::istringstream json(" { hello : 'world' // comment\n }"); + std::istringstream json(" { hello : 'world' }"); DeserializationError err = deserializeJson(doc, json); JsonObject obj = doc.as(); diff --git a/extras/tests/JsonDeserializer/misc.cpp b/extras/tests/JsonDeserializer/misc.cpp index d44cac14..0fe0e941 100644 --- a/extras/tests/JsonDeserializer/misc.cpp +++ b/extras/tests/JsonDeserializer/misc.cpp @@ -61,26 +61,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { } } - SECTION("Comments") { - SECTION("Just a trailing comment") { - DeserializationError err = deserializeJson(doc, "// comment"); - - REQUIRE(err == DeserializationError::IncompleteInput); - } - - SECTION("Just a block comment") { - DeserializationError err = deserializeJson(doc, "/*comment*/"); - - REQUIRE(err == DeserializationError::IncompleteInput); - } - - SECTION("Just a slash") { - DeserializationError err = deserializeJson(doc, "/"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - } - SECTION("Premature null-terminator") { SECTION("In escape sequence") { DeserializationError err = deserializeJson(doc, "\"\\"); @@ -88,12 +68,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { REQUIRE(err == DeserializationError::IncompleteInput); } - SECTION("In block comment") { - DeserializationError err = deserializeJson(doc, "/* comment"); - - REQUIRE(err == DeserializationError::IncompleteInput); - } - SECTION("In double quoted string") { DeserializationError err = deserializeJson(doc, "\"hello"); @@ -114,12 +88,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { REQUIRE(err == DeserializationError::IncompleteInput); } - SECTION("In block comment") { - DeserializationError err = deserializeJson(doc, "/* comment */", 10); - - REQUIRE(err == DeserializationError::IncompleteInput); - } - SECTION("In double quoted string") { DeserializationError err = deserializeJson(doc, "\"hello\"", 6); diff --git a/extras/tests/JsonDeserializer/object.cpp b/extras/tests/JsonDeserializer/object.cpp index 4afc7ac4..d6981d41 100644 --- a/extras/tests/JsonDeserializer/object.cpp +++ b/extras/tests/JsonDeserializer/object.cpp @@ -281,212 +281,6 @@ TEST_CASE("deserialize JSON object") { } } - SECTION("Block comments") { - SECTION("Before opening brace") { - DeserializationError err = - deserializeJson(doc, "/*COMMENT*/ {\"hello\":\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("After opening brace") { - DeserializationError err = - deserializeJson(doc, "{/*COMMENT*/\"hello\":\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before colon") { - DeserializationError err = - deserializeJson(doc, "{\"hello\"/*COMMENT*/:\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("After colon") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":/*COMMENT*/\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before closing brace") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":\"world\"/*COMMENT*/}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("After closing brace") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":\"world\"}/*COMMENT*/"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before comma") { - DeserializationError err = deserializeJson( - doc, "{\"hello\":\"world\"/*COMMENT*/,\"answer\":42}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - REQUIRE(obj["answer"] == 42); - } - - SECTION("After comma") { - DeserializationError err = deserializeJson( - doc, "{\"hello\":\"world\",/*COMMENT*/\"answer\":42}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - REQUIRE(obj["answer"] == 42); - } - } - - SECTION("Trailing comments") { - SECTION("Before opening brace") { - DeserializationError err = - deserializeJson(doc, "//COMMENT\n {\"hello\":\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("After opening brace") { - DeserializationError err = - deserializeJson(doc, "{//COMMENT\n\"hello\":\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before colon") { - DeserializationError err = - deserializeJson(doc, "{\"hello\"//COMMENT\n:\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("After colon") { - DeserializationError err = - deserializeJson(doc, "{\"hello\"://COMMENT\n\"world\"}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before closing brace") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":\"world\"//COMMENT\n}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("After closing brace") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":\"world\"}//COMMENT\n"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before comma") { - DeserializationError err = deserializeJson( - doc, "{\"hello\":\"world\"//COMMENT\n,\"answer\":42}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - REQUIRE(obj["answer"] == 42); - } - - SECTION("After comma") { - DeserializationError err = deserializeJson( - doc, "{\"hello\":\"world\",//COMMENT\n\"answer\":42}"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - REQUIRE(obj["answer"] == 42); - } - } - - SECTION("Dangling slash") { - SECTION("Before opening brace") { - DeserializationError err = deserializeJson(doc, "/{\"hello\":\"world\"}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("After opening brace") { - DeserializationError err = deserializeJson(doc, "{/\"hello\":\"world\"}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("Before colon") { - DeserializationError err = deserializeJson(doc, "{\"hello\"/:\"world\"}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("After colon") { - DeserializationError err = deserializeJson(doc, "{\"hello\":/\"world\"}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("Before closing brace") { - DeserializationError err = deserializeJson(doc, "{\"hello\":\"world\"/}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("After closing brace") { - DeserializationError err = deserializeJson(doc, "{\"hello\":\"world\"}/"); - JsonObject obj = doc.as(); - - REQUIRE(err == DeserializationError::Ok); - REQUIRE(obj["hello"] == "world"); - } - - SECTION("Before comma") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":\"world\"/,\"answer\":42}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - - SECTION("After comma") { - DeserializationError err = - deserializeJson(doc, "{\"hello\":\"world\",/\"answer\":42}"); - - REQUIRE(err == DeserializationError::InvalidInput); - } - } - SECTION("Should clear the JsonObject") { deserializeJson(doc, "{\"hello\":\"world\"}"); deserializeJson(doc, "{}"); diff --git a/extras/tests/MixedConfiguration/CMakeLists.txt b/extras/tests/MixedConfiguration/CMakeLists.txt index 62f31d94..c3a4a3c5 100644 --- a/extras/tests/MixedConfiguration/CMakeLists.txt +++ b/extras/tests/MixedConfiguration/CMakeLists.txt @@ -18,6 +18,8 @@ add_executable(MixedConfigurationTests use_long_long_0.cpp use_long_long_1.cpp enable_progmem_1.cpp + enable_comments_1.cpp + enable_comments_0.cpp ) target_link_libraries(MixedConfigurationTests catch) diff --git a/extras/tests/MixedConfiguration/enable_comments_0.cpp b/extras/tests/MixedConfiguration/enable_comments_0.cpp new file mode 100644 index 00000000..8e98c7a2 --- /dev/null +++ b/extras/tests/MixedConfiguration/enable_comments_0.cpp @@ -0,0 +1,54 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#define ARDUINOJSON_ENABLE_COMMENTS 0 +#include + +#include + +TEST_CASE("Comments should produce InvalidInput") { + DynamicJsonDocument doc(2048); + + const char* testCases[] = { + "/*COMMENT*/ [\"hello\"]", + "[/*COMMENT*/ \"hello\"]", + "[\"hello\"/*COMMENT*/]", + "[\"hello\"/*COMMENT*/,\"world\"]", + "[\"hello\",/*COMMENT*/ \"world\"]", + "[/*/\n]", + "[/*COMMENT]", + "[/*COMMENT*]", + "//COMMENT\n\t[\"hello\"]", + "[//COMMENT\n\"hello\"]", + "[\"hello\"//COMMENT\r\n]", + "[\"hello\"//COMMENT\n,\"world\"]", + "[\"hello\",//COMMENT\n\"world\"]", + "[/COMMENT\n]", + "[//COMMENT", + "/*COMMENT*/ {\"hello\":\"world\"}", + "{/*COMMENT*/\"hello\":\"world\"}", + "{\"hello\"/*COMMENT*/:\"world\"}", + "{\"hello\":/*COMMENT*/\"world\"}", + "{\"hello\":\"world\"/*COMMENT*/}", + "//COMMENT\n {\"hello\":\"world\"}", + "{//COMMENT\n\"hello\":\"world\"}", + "{\"hello\"//COMMENT\n:\"world\"}", + "{\"hello\"://COMMENT\n\"world\"}", + "{\"hello\":\"world\"//COMMENT\n}", + "/{\"hello\":\"world\"}", + "{/\"hello\":\"world\"}", + "{\"hello\"/:\"world\"}", + "{\"hello\":/\"world\"}", + "{\"hello\":\"world\"/}", + "{\"hello\":\"world\"/,\"answer\":42}", + "{\"hello\":\"world\",/\"answer\":42}", + }; + const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); + + for (size_t i = 0; i < testCount; i++) { + const char* input = testCases[i]; + CAPTURE(input); + REQUIRE(deserializeJson(doc, input) == DeserializationError::InvalidInput); + } +} diff --git a/extras/tests/MixedConfiguration/enable_comments_1.cpp b/extras/tests/MixedConfiguration/enable_comments_1.cpp new file mode 100644 index 00000000..7e59bb03 --- /dev/null +++ b/extras/tests/MixedConfiguration/enable_comments_1.cpp @@ -0,0 +1,405 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#define ARDUINOJSON_ENABLE_COMMENTS 1 +#include + +#include + +TEST_CASE("Comments in arrays") { + DynamicJsonDocument doc(2048); + + SECTION("Block comments") { + SECTION("Before opening bracket") { + DeserializationError err = + deserializeJson(doc, "/*COMMENT*/ [\"hello\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("After opening bracket") { + DeserializationError err = + deserializeJson(doc, "[/*COMMENT*/ \"hello\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("Before closing bracket") { + DeserializationError err = deserializeJson(doc, "[\"hello\"/*COMMENT*/]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("After closing bracket") { + DeserializationError err = deserializeJson(doc, "[\"hello\"]/*COMMENT*/"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("Before comma") { + DeserializationError err = + deserializeJson(doc, "[\"hello\"/*COMMENT*/,\"world\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(2 == arr.size()); + REQUIRE(arr[0] == "hello"); + REQUIRE(arr[1] == "world"); + } + + SECTION("After comma") { + DeserializationError err = + deserializeJson(doc, "[\"hello\",/*COMMENT*/ \"world\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(2 == arr.size()); + REQUIRE(arr[0] == "hello"); + REQUIRE(arr[1] == "world"); + } + + SECTION("/*/") { + DeserializationError err = deserializeJson(doc, "[/*/\n]"); + REQUIRE(err == DeserializationError::IncompleteInput); + } + + SECTION("Unfinished comment") { + DeserializationError err = deserializeJson(doc, "[/*COMMENT]"); + REQUIRE(err == DeserializationError::IncompleteInput); + } + + SECTION("Final slash missing") { + DeserializationError err = deserializeJson(doc, "[/*COMMENT*]"); + REQUIRE(err == DeserializationError::IncompleteInput); + } + } + + SECTION("Trailing comments") { + SECTION("Before opening bracket") { + DeserializationError err = + deserializeJson(doc, "//COMMENT\n\t[\"hello\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("After opening bracket") { + DeserializationError err = deserializeJson(doc, "[//COMMENT\n\"hello\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("Before closing bracket") { + DeserializationError err = + deserializeJson(doc, "[\"hello\"//COMMENT\r\n]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("After closing bracket") { + DeserializationError err = deserializeJson(doc, "[\"hello\"]//COMMENT\n"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(1 == arr.size()); + REQUIRE(arr[0] == "hello"); + } + + SECTION("Before comma") { + DeserializationError err = + deserializeJson(doc, "[\"hello\"//COMMENT\n,\"world\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(2 == arr.size()); + REQUIRE(arr[0] == "hello"); + REQUIRE(arr[1] == "world"); + } + + SECTION("After comma") { + DeserializationError err = + deserializeJson(doc, "[\"hello\",//COMMENT\n\"world\"]"); + JsonArray arr = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(2 == arr.size()); + REQUIRE(arr[0] == "hello"); + REQUIRE(arr[1] == "world"); + } + + SECTION("Invalid comment") { + DeserializationError err = deserializeJson(doc, "[/COMMENT\n]"); + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("End document with comment") { + DeserializationError err = deserializeJson(doc, "[//COMMENT"); + REQUIRE(err == DeserializationError::IncompleteInput); + } + } +} + +TEST_CASE("Comments in objects") { + DynamicJsonDocument doc(2048); + + SECTION("Block comments") { + SECTION("Before opening brace") { + DeserializationError err = + deserializeJson(doc, "/*COMMENT*/ {\"hello\":\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("After opening brace") { + DeserializationError err = + deserializeJson(doc, "{/*COMMENT*/\"hello\":\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before colon") { + DeserializationError err = + deserializeJson(doc, "{\"hello\"/*COMMENT*/:\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("After colon") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":/*COMMENT*/\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before closing brace") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":\"world\"/*COMMENT*/}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("After closing brace") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":\"world\"}/*COMMENT*/"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before comma") { + DeserializationError err = deserializeJson( + doc, "{\"hello\":\"world\"/*COMMENT*/,\"answer\":42}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + REQUIRE(obj["answer"] == 42); + } + + SECTION("After comma") { + DeserializationError err = deserializeJson( + doc, "{\"hello\":\"world\",/*COMMENT*/\"answer\":42}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + REQUIRE(obj["answer"] == 42); + } + } + + SECTION("Trailing comments") { + SECTION("Before opening brace") { + DeserializationError err = + deserializeJson(doc, "//COMMENT\n {\"hello\":\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("After opening brace") { + DeserializationError err = + deserializeJson(doc, "{//COMMENT\n\"hello\":\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before colon") { + DeserializationError err = + deserializeJson(doc, "{\"hello\"//COMMENT\n:\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("After colon") { + DeserializationError err = + deserializeJson(doc, "{\"hello\"://COMMENT\n\"world\"}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before closing brace") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":\"world\"//COMMENT\n}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("After closing brace") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":\"world\"}//COMMENT\n"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before comma") { + DeserializationError err = deserializeJson( + doc, "{\"hello\":\"world\"//COMMENT\n,\"answer\":42}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + REQUIRE(obj["answer"] == 42); + } + + SECTION("After comma") { + DeserializationError err = deserializeJson( + doc, "{\"hello\":\"world\",//COMMENT\n\"answer\":42}"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + REQUIRE(obj["answer"] == 42); + } + } + + SECTION("Dangling slash") { + SECTION("Before opening brace") { + DeserializationError err = deserializeJson(doc, "/{\"hello\":\"world\"}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("After opening brace") { + DeserializationError err = deserializeJson(doc, "{/\"hello\":\"world\"}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("Before colon") { + DeserializationError err = deserializeJson(doc, "{\"hello\"/:\"world\"}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("After colon") { + DeserializationError err = deserializeJson(doc, "{\"hello\":/\"world\"}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("Before closing brace") { + DeserializationError err = deserializeJson(doc, "{\"hello\":\"world\"/}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("After closing brace") { + DeserializationError err = deserializeJson(doc, "{\"hello\":\"world\"}/"); + JsonObject obj = doc.as(); + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(obj["hello"] == "world"); + } + + SECTION("Before comma") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":\"world\"/,\"answer\":42}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("After comma") { + DeserializationError err = + deserializeJson(doc, "{\"hello\":\"world\",/\"answer\":42}"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + } +} + +TEST_CASE("Comments alone") { + DynamicJsonDocument doc(2048); + + SECTION("Just a trailing comment") { + DeserializationError err = deserializeJson(doc, "// comment"); + + REQUIRE(err == DeserializationError::IncompleteInput); + } + + SECTION("Just a block comment") { + DeserializationError err = deserializeJson(doc, "/*comment*/"); + + REQUIRE(err == DeserializationError::IncompleteInput); + } + + SECTION("Just a slash") { + DeserializationError err = deserializeJson(doc, "/"); + + REQUIRE(err == DeserializationError::InvalidInput); + } + + SECTION("Premature terminator") { + DeserializationError err = deserializeJson(doc, "/* comment"); + + REQUIRE(err == DeserializationError::IncompleteInput); + } + + SECTION("Premature end on sized input") { + DeserializationError err = deserializeJson(doc, "/* comment */", 10); + + REQUIRE(err == DeserializationError::IncompleteInput); + } +} diff --git a/src/ArduinoJson/Configuration.hpp b/src/ArduinoJson/Configuration.hpp index 0e60a106..b99d25ab 100644 --- a/src/ArduinoJson/Configuration.hpp +++ b/src/ArduinoJson/Configuration.hpp @@ -165,6 +165,11 @@ #define ARDUINOJSON_DECODE_UNICODE 0 #endif +// Ignore comments in input +#ifndef ARDUINOJSON_ENABLE_COMMENTS +#define ARDUINOJSON_ENABLE_COMMENTS 0 +#endif + // Support NaN in JSON #ifndef ARDUINOJSON_ENABLE_NAN #define ARDUINOJSON_ENABLE_NAN 0 diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index de0f594c..52124111 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -357,6 +357,7 @@ class JsonDeserializer { move(); continue; +#if ARDUINOJSON_ENABLE_COMMENTS // comments case '/': move(); // skip '/' @@ -394,6 +395,7 @@ class JsonDeserializer { return DeserializationError::InvalidInput; } break; +#endif default: return DeserializationError::Ok; diff --git a/src/ArduinoJson/Namespace.hpp b/src/ArduinoJson/Namespace.hpp index b7a42e84..37c9f87b 100644 --- a/src/ArduinoJson/Namespace.hpp +++ b/src/ArduinoJson/Namespace.hpp @@ -14,13 +14,14 @@ #define ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, H) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \ ARDUINOJSON_CONCAT4(E, F, G, H)) -#define ARDUINOJSON_CONCAT11(A, B, C, D, E, F, G, H, I, J, K) \ - ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, ARDUINOJSON_CONCAT4(H, I, J, K)) +#define ARDUINOJSON_CONCAT12(A, B, C, D, E, F, G, H, I, J, K, L) \ + ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, \ + ARDUINOJSON_CONCAT4(H, I, J, ARDUINOJSON_CONCAT2(K, L))) #define ARDUINOJSON_NAMESPACE \ - ARDUINOJSON_CONCAT11( \ + ARDUINOJSON_CONCAT12( \ ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \ ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \ ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \ ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ - ARDUINOJSON_ENABLE_PROGMEM) + ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_ENABLE_COMMENTS)