From 266c2249feaca6ba69022e4e5afd49769e773aba Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 29 Sep 2026 02:36:50 +0200 Subject: [PATCH] Cover the edit storage in tests Test edits of an empty document and assignments through a view of a value that is no longer part of the document; copy the entries of a block through deref() (one path for links and values); mark the 4 GiB limit and the returns of find_parent() that no document reaches. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/view/edit_storage.hpp | 17 +++++------------ single_include/nlohmann/json_view.hpp | 17 +++++------------ tests/src/unit-json_view_edit.cpp | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/include/nlohmann/detail/view/edit_storage.hpp b/include/nlohmann/detail/view/edit_storage.hpp index 8e0ff8e37..11bff9faa 100644 --- a/include/nlohmann/detail/view/edit_storage.hpp +++ b/include/nlohmann/detail/view/edit_storage.hpp @@ -73,7 +73,7 @@ inline std::uint32_t append_text(document_data& d, const char* s, std::size_t n) const std::size_t cap = (std::max)(e.text_cap * 2, e.text_used + n + 256); if (cap > 0xFFFFFFFFu) { - throw_out_of_range(416, "edits of 4 GiB or more are not supported by json_document"); + throw_out_of_range(416, "edits of 4 GiB or more are not supported by json_document"); // LCOV_EXCL_LINE (4 GiB) } std::unique_ptr fresh(new char[cap]); // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) if (e.text_used != 0) @@ -161,14 +161,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra) { *o++ = *c++; // the key } - if (c->kind == kind_link) - { - *o = *c; - } - else - { - make_link(*o, c); - } + make_link(*o, document_data::deref(c)); ++o; c = document_data::after(c); } @@ -197,14 +190,14 @@ inline node* find_parent(const document_data& d, const node* target) auto it = d.edits->regions.upper_bound(target); if (it == d.edits->regions.begin()) { - return nullptr; + return nullptr; // LCOV_EXCL_LINE (an array/object with elements is in the index or a new value) } --it; lo = it->first; hi = lo + lo->next; if (!lt(target, hi)) { - return nullptr; // a single-node value, reached through a link + return nullptr; // LCOV_EXCL_LINE (a single-node value, reached through a link) } // the root of a new value is the element sequence of its owner, or a linked value c = it->second != nullptr ? it->second : lo; @@ -217,7 +210,7 @@ inline node* find_parent(const document_data& d, const node* target) { if (!is_container(*c)) { - return nullptr; + return nullptr; // LCOV_EXCL_LINE (the value is inside c) } const bool object = c->kind == static_cast(value_t::object); const node* down = nullptr; diff --git a/single_include/nlohmann/json_view.hpp b/single_include/nlohmann/json_view.hpp index 53e15aac4..ad69a4f3d 100644 --- a/single_include/nlohmann/json_view.hpp +++ b/single_include/nlohmann/json_view.hpp @@ -2546,7 +2546,7 @@ inline std::uint32_t append_text(document_data& d, const char* s, std::size_t n) const std::size_t cap = (std::max)(e.text_cap * 2, e.text_used + n + 256); if (cap > 0xFFFFFFFFu) { - throw_out_of_range(416, "edits of 4 GiB or more are not supported by json_document"); + throw_out_of_range(416, "edits of 4 GiB or more are not supported by json_document"); // LCOV_EXCL_LINE (4 GiB) } std::unique_ptr fresh(new char[cap]); // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) if (e.text_used != 0) @@ -2634,14 +2634,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra) { *o++ = *c++; // the key } - if (c->kind == kind_link) - { - *o = *c; - } - else - { - make_link(*o, c); - } + make_link(*o, document_data::deref(c)); ++o; c = document_data::after(c); } @@ -2670,14 +2663,14 @@ inline node* find_parent(const document_data& d, const node* target) auto it = d.edits->regions.upper_bound(target); if (it == d.edits->regions.begin()) { - return nullptr; + return nullptr; // LCOV_EXCL_LINE (an array/object with elements is in the index or a new value) } --it; lo = it->first; hi = lo + lo->next; if (!lt(target, hi)) { - return nullptr; // a single-node value, reached through a link + return nullptr; // LCOV_EXCL_LINE (a single-node value, reached through a link) } // the root of a new value is the element sequence of its owner, or a linked value c = it->second != nullptr ? it->second : lo; @@ -2690,7 +2683,7 @@ inline node* find_parent(const document_data& d, const node* target) { if (!is_container(*c)) { - return nullptr; + return nullptr; // LCOV_EXCL_LINE (the value is inside c) } const bool object = c->kind == static_cast(value_t::object); const node* down = nullptr; diff --git a/tests/src/unit-json_view_edit.cpp b/tests/src/unit-json_view_edit.cpp index 6d89d937c..692d68289 100644 --- a/tests/src/unit-json_view_edit.cpp +++ b/tests/src/unit-json_view_edit.cpp @@ -327,6 +327,12 @@ std::string exception_of_call(const std::function& f) TEST_CASE("json_view edits: errors") { + SECTION("an empty document") + { + json_editable_document d; + CHECK_THROWS_WITH_AS(d.set(d.root(), 1), "[json.exception.invalid_iterator.202] view does not belong to this document", json::invalid_iterator&); + } + json_editable_document d = json_editable_document::parse(R"({"o": {"a": 1}, "a": [1, 2], "n": 1, "z": null})"); const json_editable_view root = d.root(); const json_document other = json_document::parse("[1]"); @@ -367,6 +373,16 @@ TEST_CASE("json_view edits: errors") TEST_CASE("json_view edits: views and values") { + SECTION("a value that is no longer part of the document") + { + json_editable_document d = json_editable_document::parse("[[[1,2]]]"); + const json_editable_view inner = d.root()[0][0]; + d.set(d.root()[0], json::array({7})); + d.set(inner, 5); + CHECK(d.root().dump() == "[[7]]"); + CHECK(inner.get() == 5); + } + SECTION("strings stay valid while more edits come") { json_editable_document d = json_editable_document::parse("[]");