Skip to content

Commit

Permalink
Fix patch::add creating nonexistent parents (#3628)
Browse files Browse the repository at this point in the history
* Fix patch::add creating nonexistent parents

The previous behavior was not in accordance with RFC6902.
Add unit test.

Fixes #3134.

* Fix incorrect JSON patch unit test

Co-authored-by: Hudson00 <yagdhscdasg@gmail.com>
  • Loading branch information
falbrechtskirchinger and Hudson00 committed Jul 30, 2022
1 parent d1d79b9 commit fca1ddd
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 9 deletions.
3 changes: 2 additions & 1 deletion include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4683,7 +4683,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// get reference to parent of JSON pointer ptr
const auto last_path = ptr.back();
ptr.pop_back();
basic_json& parent = result[ptr];
// parent must exist when performing patch add per RFC6902 specs
basic_json& parent = result.at(ptr);

switch (parent.m_type)
{
Expand Down
3 changes: 2 additions & 1 deletion single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23527,7 +23527,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// get reference to parent of JSON pointer ptr
const auto last_path = ptr.back();
ptr.pop_back();
basic_json& parent = result[ptr];
// parent must exist when performing patch add per RFC6902 specs
basic_json& parent = result.at(ptr);

switch (parent.m_type)
{
Expand Down
22 changes: 15 additions & 7 deletions tests/src/unit-json_patch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ TEST_CASE("JSON patch")

SECTION("4.1 add")
{
json patch = R"([{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }])"_json;
json patch1 = R"([{ "op": "add", "path": "/a/b", "value": [ "foo", "bar" ] }])"_json;

// However, the object itself or an array containing it does need
// to exist, and it remains an error for that not to be the case.
Expand All @@ -42,24 +42,32 @@ TEST_CASE("JSON patch")

// is not an error, because "a" exists, and "b" will be added to
// its value.
CHECK_NOTHROW(doc1.patch(patch));
CHECK_NOTHROW(doc1.patch(patch1));
auto doc1_ans = R"(
{
"a": {
"foo": 1,
"b": {
"c": [ "foo", "bar" ]
}
"b": [ "foo", "bar" ]
}
}
)"_json;
CHECK(doc1.patch(patch) == doc1_ans);
CHECK(doc1.patch(patch1) == doc1_ans);

// It is an error in this document:
json doc2 = R"({ "q": { "bar": 2 } })"_json;

// because "a" does not exist.
CHECK_THROWS_WITH_AS(doc2.patch(patch), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&);
CHECK_THROWS_WITH_AS(doc2.patch(patch1), "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&);

json doc3 = R"({ "a": {} })"_json;
json patch2 = R"([{ "op": "add", "path": "/a/b/c", "value": 1 }])"_json;

// should cause an error because "b" does not exist in doc3
#if JSON_DIAGNOSTICS
CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] (/a) key 'b' not found", json::out_of_range&);
#else
CHECK_THROWS_WITH_AS(doc3.patch(patch2), "[json.exception.out_of_range.403] key 'b' not found", json::out_of_range&);
#endif
}

SECTION("4.2 remove")
Expand Down

0 comments on commit fca1ddd

Please sign in to comment.