mirror of
https://github.com/nlohmann/json.git
synced 2026-09-11 10:48:01 +00:00
tests/src/unit-class_parser_diagnostic_positions.cpp and tests/src/unit-diagnostic-positions-only.cpp were maintained as near-copies of unit-class_parser.cpp and unit-diagnostic-positions.cpp respectively, and had drifted: trailing-comma handling, the #5342 filter-array/filter-value sections, and the cross-input-adapter diagnostics test were never ported to the positions-enabled copy. Fold the position-specific assertions into the base files, guarded by file a second time with the relevant macro set via CMake COMPILE_DEFINITIONS (mirroring the existing test-comparison_legacy pattern) instead of maintaining a separate source file. This removes the duplication and, as a side effect, closes the coverage gaps above since the full test file now compiles under JSON_DIAGNOSTIC_POSITIONS=1 as well. Fixes #5417 Signed-off-by: Niels Lohmann <mail@nlohmann.me>
93 lines
3.7 KiB
C++
93 lines
3.7 KiB
C++
// __ _____ _____ _____
|
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
|
// | | |__ | | | | | | version 3.12.0
|
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|
//
|
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "doctest_compatibility.h"
|
|
|
|
#ifndef JSON_DIAGNOSTICS
|
|
#define JSON_DIAGNOSTICS 1
|
|
#endif
|
|
#define JSON_DIAGNOSTIC_POSITIONS 1
|
|
#include <nlohmann/json.hpp>
|
|
|
|
using json = nlohmann::json;
|
|
|
|
TEST_CASE("Better diagnostics with positions")
|
|
{
|
|
SECTION("invalid type")
|
|
{
|
|
const std::string json_invalid_string = R"(
|
|
{
|
|
"address": {
|
|
"street": "Fake Street",
|
|
"housenumber": "1"
|
|
}
|
|
}
|
|
)";
|
|
json j = json::parse(json_invalid_string);
|
|
#if JSON_DIAGNOSTICS
|
|
CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get<int>(),
|
|
"[json.exception.type_error.302] (/address/housenumber) (bytes 108-111) type must be number, but is string", json::type_error);
|
|
#else
|
|
CHECK_THROWS_WITH_AS(j.at("address").at("housenumber").get<int>(),
|
|
"[json.exception.type_error.302] (bytes 108-111) type must be number, but is string", json::type_error);
|
|
#endif
|
|
}
|
|
|
|
SECTION("invalid type without positions")
|
|
{
|
|
const json j = "foo";
|
|
CHECK_THROWS_WITH_AS(j.get<int>(),
|
|
"[json.exception.type_error.302] type must be number, but is string", json::type_error);
|
|
}
|
|
|
|
SECTION("positions of strings containing escape sequences")
|
|
{
|
|
// escape sequences make the token longer than the string it parses to,
|
|
// so the positions must not be derived from the parsed value's length
|
|
const auto check = [](const std::string & text, const std::string & token)
|
|
{
|
|
CAPTURE(text)
|
|
CAPTURE(token)
|
|
const json j = json::parse(text);
|
|
const json& v = j.at("a");
|
|
CHECK(text.substr(v.start_pos(), v.end_pos() - v.start_pos()) == token);
|
|
};
|
|
|
|
check(R"({"a":"plain"})", R"("plain")");
|
|
check(R"({"a":"tab\there"})", R"("tab\there")");
|
|
check(R"({"a":"\n\n\n\n\n\n"})", R"("\n\n\n\n\n\n")");
|
|
check(R"({"a":"\""})", R"("\"")");
|
|
check(R"({"a":"\\"})", R"("\\")");
|
|
check(R"({"a":"é"})", R"("é")");
|
|
check(R"({"a":"🌞"})", R"("🌞")");
|
|
check("{\"a\":\"\xc3\xa9\"}", "\"\xc3\xa9\""); // multi-byte UTF-8, no escapes
|
|
|
|
// a string at the root, where an escape would otherwise push the
|
|
// reported start position past the opening quote
|
|
const std::string root = R"("a\tb")";
|
|
const json j = json::parse(root);
|
|
CHECK(j.start_pos() == 0);
|
|
CHECK(j.end_pos() == root.size());
|
|
}
|
|
|
|
SECTION("JSON patch add to primitive parent (#4292)")
|
|
{
|
|
// the JSON Patch "add" target /foo/bar/baz has a string parent
|
|
// (/foo/bar); the position of that parent is reported in the message
|
|
const json doc = json::parse(R"({"foo":{"bar":"a string"}})");
|
|
const json patch = json::parse(R"([{"op":"add","path":"/foo/bar/baz","value":1}])");
|
|
#if JSON_DIAGNOSTICS
|
|
CHECK_THROWS_WITH_AS(doc.patch(patch),
|
|
"[json.exception.out_of_range.411] (/foo/bar) (bytes 14-24) cannot add value: the JSON Patch 'add' target's parent is of type string, but must be an object or array", json::out_of_range);
|
|
#else
|
|
CHECK_THROWS_WITH_AS(doc.patch(patch),
|
|
"[json.exception.out_of_range.411] (bytes 14-24) cannot add value: the JSON Patch 'add' target's parent is of type string, but must be an object or array", json::out_of_range);
|
|
#endif
|
|
}
|
|
}
|