Tests: cover the remaining lines of the library headers

Add tests for the lines of include/nlohmann that were not covered: the
binary readers and writers, the lexer and locale paths, the json_view
modules, the custom number, key and array types, json_pointer, json_patch,
diff and the iterators.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-11-01 22:32:42 +01:00
1 parent d7b9472173
commit 056ba3b7c1
33 files changed
+1627 -1

No files matched your search

+70
View File
@@ -20,6 +20,7 @@ using nlohmann::ordered_json;
using nlohmann::json_document;
using nlohmann::json_editable_document;
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <fstream>
@@ -427,6 +428,31 @@ TEST_CASE("json_view materialize() source positions")
CHECK(same_positions(m[std::string("a") + '\n'][2], j[std::string("a") + '\n'][2]));
}
SECTION("a damaged text: the end of a container is not found")
{
// (the text of an image is not checked with image_check::none)
const std::string array_text = "[1,2]";
const std::vector<std::uint8_t> original = json_document::parse(array_text).save();
const auto at = std::search(original.begin(), original.end(), array_text.begin(), array_text.end());
REQUIRE(at != original.end());
const auto closing = static_cast<std::size_t>(at - original.begin()) + array_text.size() - 1;
// not a closing bracket, a slash that starts no comment, and the end of the text
for (const char replacement :
{
'x', '/', ' '
})
{
CAPTURE(replacement)
std::vector<std::uint8_t> damaged = original;
damaged[closing] = static_cast<std::uint8_t>(replacement);
const json_document d = json_document::load(damaged, json_document::image_check::none);
const json m = d.root().materialize();
CHECK(range(m) == "none");
CHECK(range(m[0]) == "1-2");
CHECK(range(m[1]) == "3-4");
}
}
#if !defined(JSON_NOEXCEPTION)
SECTION("a decoded string's position must be within the text")
{
@@ -461,6 +487,7 @@ TEST_CASE("json_view exceptions name the path and the bytes of the value")
{
"null", "true", "42", "\"s\"", "[]", "{}", "[1, [2, [3, []]]]", R"({"a": {"b": [1, {"c": null}]}, "d": "e"})",
R"({"a/b": {"~": [1]}, "\u0041\n": {"x": "\t"}, "": [{}]})",
R"({"a\u0000b": [1, "x"], "c": {"d\u0000": 2}})", // (the path of a key ends at a null byte, as in basic_json)
R"([1 /* ] */, {"a": [] // }
, "b": {} } , ])",
"\n\t[\r\n 1 ,\n {\n \"a\" : [ ]\n }\n]\n",
@@ -512,6 +539,49 @@ TEST_CASE("json_view exceptions name the path and the bytes of the value")
CHECK(exception_of_call([&] { static_cast<void>(d.root()["a"][2]["n"][0].get<int>()); }) == expected);
}
SECTION("views of values that are no longer part of the document, and of no value")
{
const std::string expected_string = "[json.exception.type_error.302] type must be number, but is string";
static_cast<void>(expected_string);
// (a value that is not found has no path, and with it no bytes)
{
json_editable_document d = json_editable_document::parse(R"(["x", ["y"]])");
const auto removed = d.root()[0];
d.erase(d.root(), 0);
#if JSON_DIAGNOSTICS
CHECK(exception_of_call([&] { static_cast<void>(removed.get<int>()); }) == expected_string);
#endif
// (the root is a scalar now: the value cannot be in it)
d.set(d.root(), 5);
#if JSON_DIAGNOSTICS
CHECK(exception_of_call([&] { static_cast<void>(removed.get<int>()); }) == expected_string);
#endif
CHECK(d.root().get<int>() == 5);
}
{
json_editable_document d = json_editable_document::parse(R"(["x"])");
const auto removed = d.root()[0];
d.set(d.root(), 5);
#if JSON_DIAGNOSTICS
CHECK(exception_of_call([&] { static_cast<void>(removed.get<int>()); }) == expected_string);
#endif
}
// a view of no value has no context
CHECK(exception_of_call([&] { static_cast<void>(nlohmann::json_view().get<int>()); }) == "[json.exception.type_error.302] type must be number, but is discarded");
}
SECTION("an array whose last element was replaced by a new container has no bytes")
{
json_editable_document d = json_editable_document::parse(R"({"a": [1, [2]], "b": 1})");
d.set(d.root()["a"][1], json::array({3}));
std::string expected = "[json.exception.type_error.302] ";
#if JSON_DIAGNOSTICS
expected += "(/a) ";
#endif
expected += "type must be number, but is array";
CHECK(exception_of_call([&] { static_cast<void>(d.root()["a"].get<int>()); }) == expected);
}
SECTION("deep documents with siblings after every nested container")
{
// the search for the path pushes and pops one frame per level (the