From 62624a74436cc6d7f70a2697a093dad71ec56f3c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 20 Aug 2026 03:02:43 +0200 Subject: [PATCH] Fix shadowed locals and guard the exception-dependent tests Two problems in the tests added for the bulk scanners, both found by CI: - the inner `const json j` in the counted-iterator diagnostics shadowed the one declared at test-case scope, which -Wshadow rejects on GCC and clang and C4456 rejects on MSVC under /WX; rename them - the new parity checks parse deliberately invalid input, which calls std::abort() rather than throwing when JSON_NOEXCEPTION is defined, so they would have crashed the no-exception build; guard them the way the other tests do json::accept() does not abort, so the UTF-8 range assertions stay compiled without exceptions and keep covering validate_one_utf8() there. Signed-off-by: Niels Lohmann --- tests/src/unit-class_lexer.cpp | 13 ++++++++++++- tests/src/unit-user_defined_input.cpp | 25 ++++++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/tests/src/unit-class_lexer.cpp b/tests/src/unit-class_lexer.cpp index a7b7bf927..fb24f7335 100644 --- a/tests/src/unit-class_lexer.cpp +++ b/tests/src/unit-class_lexer.cpp @@ -300,6 +300,8 @@ TEST_CASE("lexer number fast path") } } +#if !defined(JSON_NOEXCEPTION) + // these sections parse invalid input, which aborts when exceptions are off SECTION("exhaustive grammar parity with the streaming path") { // The JSON number grammar is encoded twice: once as the scan_number() @@ -415,6 +417,7 @@ TEST_CASE("lexer number fast path") "[json.exception.parse_error.101] parse error at line 1, column 3: " "syntax error while parsing array - unexpected number literal; expected ']'"); } +#endif } TEST_CASE("lexer string fast path") @@ -432,8 +435,10 @@ TEST_CASE("lexer string fast path") return result; }; +#if !defined(JSON_NOEXCEPTION) // the full outcome of parsing @a doc: the parsed value, or the exact error - // message, so a mismatch in either is caught + // message, so a mismatch in either is caught. Only usable with exceptions + // on: parsing invalid input aborts when they are off. const auto outcome = [](const std::string & doc, bool streaming) { try @@ -455,11 +460,13 @@ TEST_CASE("lexer string fast path") return std::string(e.what()); } }; +#endif // once at the start of the string, once past the first 8-byte SWAR word, so // the bulk scanner sees each case with and without a run behind it const std::vector offsets{0, 9}; +#if !defined(JSON_NOEXCEPTION) SECTION("exhaustive contiguous vs streaming parity") { // ordinary ASCII, both specials, a control byte, characters that make @@ -533,7 +540,9 @@ TEST_CASE("lexer string fast path") CAPTURE(mismatches); CHECK(mismatches.empty()); } +#endif + // json::accept() never throws, so the ranges stay covered without exceptions SECTION("UTF-8 ranges are accepted and rejected as documented") { // The bulk validator must accept exactly what the byte-at-a-time @@ -577,7 +586,9 @@ TEST_CASE("lexer string fast path") CAPTURE(offset); const std::string doc = "[\"" + std::string(offset, 'a') + test_case.sequence + "\"]"; CHECK(json::accept(doc) == test_case.valid); +#if !defined(JSON_NOEXCEPTION) CHECK(outcome(doc, false) == outcome(doc, true)); +#endif } } } diff --git a/tests/src/unit-user_defined_input.cpp b/tests/src/unit-user_defined_input.cpp index 614c20515..48083e3cc 100644 --- a/tests/src/unit-user_defined_input.cpp +++ b/tests/src/unit-user_defined_input.cpp @@ -254,9 +254,11 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths") // parsing through the pointer adapter must give exactly the same result CHECK(j == json::parse(json_str)); +#if !defined(JSON_NOEXCEPTION) // Diagnostics that quote the offending token are reconstructed from the // already-consumed input (supports_seek), a path a sized sentinel only - // reaches now; check a few that include the "last read" text. + // reaches now; check a few that include the "last read" text. Parsing + // invalid input aborts when exceptions are off, hence the guard. for (const char* doc : {"1\nx", "truX", "[tru]", "\"abc", "[\"\\ud834\"]", "[\"a\x01""b\"]", "[\"\xc3\x28\"]", "[1e]", "[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX" @@ -269,8 +271,8 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths") std::string string_message; try { - const json j = json::parse(it, std::default_sentinel); - static_cast(j); + const json counted_result = json::parse(it, std::default_sentinel); + static_cast(counted_result); } catch (const json::parse_error& e) { @@ -278,8 +280,8 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths") } try { - const json j = json::parse(text); - static_cast(j); + const json string_result = json::parse(text); + static_cast(string_result); } catch (const json::parse_error& e) { @@ -296,8 +298,8 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths") std::string string_what; try { - const json j = json::parse(bad_first, std::default_sentinel); - static_cast(j); + const json counted_result = json::parse(bad_first, std::default_sentinel); + static_cast(counted_result); } catch (const json::parse_error& e) { @@ -305,8 +307,8 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths") } try { - const json j = json::parse(bad); - static_cast(j); + const json string_result = json::parse(bad); + static_cast(string_result); } catch (const json::parse_error& e) { @@ -314,8 +316,12 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths") } CHECK_FALSE(counted_what.empty()); CHECK(counted_what == string_what); +#endif } +#if !defined(JSON_NOEXCEPTION) +// several cases below are truncated on purpose, and parsing invalid input +// aborts when exceptions are off TEST_CASE("std::counted_iterator bulk scanning stops at the counted end") { // The count, not the size of the underlying buffer, is the end of the @@ -376,5 +382,6 @@ TEST_CASE("std::counted_iterator bulk scanning stops at the counted end") } } #endif +#endif } // namespace