mirror of
https://github.com/nlohmann/json.git
synced 2026-09-07 16:57:59 +00:00
test: add coverage for patch_inplace() (#5423)
patch_inplace() had no unit test at all. Add a happy-path case mirroring an existing patch() example, and -- more importantly -- pin its distinguishing contract versus patch(): when a multi-operation JSON Patch fails partway through, patch_inplace() (which mutates the document directly, operation by operation) leaves whatever operations already succeeded applied, whereas patch() (which applies the patch to an internal copy that is discarded on exception) leaves the original completely untouched either way. Verified empirically against the current implementation before writing the assertions. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -672,6 +672,83 @@ TEST_CASE("JSON patch")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("patch_inplace")
|
||||||
|
{
|
||||||
|
SECTION("happy path: patch_inplace mirrors patch() on success")
|
||||||
|
{
|
||||||
|
// mirrors "A.5. Replacing a Value" above, but applies the patch with
|
||||||
|
// patch_inplace() to a mutable copy instead of using patch()'s
|
||||||
|
// returned copy
|
||||||
|
json doc = R"(
|
||||||
|
{
|
||||||
|
"baz": "qux",
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
)"_json;
|
||||||
|
|
||||||
|
json const patch = R"(
|
||||||
|
[
|
||||||
|
{ "op": "replace", "path": "/baz", "value": "boo" }
|
||||||
|
]
|
||||||
|
)"_json;
|
||||||
|
|
||||||
|
json const expected = R"(
|
||||||
|
{
|
||||||
|
"baz": "boo",
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
)"_json;
|
||||||
|
|
||||||
|
doc.patch_inplace(patch);
|
||||||
|
CHECK(doc == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("distinguishing contract vs patch(): partial application on failure")
|
||||||
|
{
|
||||||
|
// Unlike patch(), which is all-or-nothing because it applies the
|
||||||
|
// patch to an internal copy that is simply discarded when an
|
||||||
|
// exception is thrown (leaving the original untouched no matter
|
||||||
|
// what), patch_inplace() mutates the document it is called on
|
||||||
|
// directly and immediately, operation by operation. So if a JSON
|
||||||
|
// Patch fails partway through, whatever operations already
|
||||||
|
// succeeded remain applied -- the document is left in a partially
|
||||||
|
// patched state. This is empirically verified current behavior,
|
||||||
|
// not just documented intent, and is pinned here as such.
|
||||||
|
json const original = R"(
|
||||||
|
{
|
||||||
|
"baz": "qux",
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
)"_json;
|
||||||
|
|
||||||
|
// the first operation ("replace") succeeds; the second ("test")
|
||||||
|
// fails because the value at "/baz" no longer (and never did)
|
||||||
|
// equal "not boo"
|
||||||
|
json const patch = R"(
|
||||||
|
[
|
||||||
|
{ "op": "replace", "path": "/baz", "value": "boo" },
|
||||||
|
{ "op": "test", "path": "/baz", "value": "not boo" }
|
||||||
|
]
|
||||||
|
)"_json;
|
||||||
|
|
||||||
|
// patch() never modifies the object it is called on -- it always
|
||||||
|
// operates on (and returns) a separate copy, so the original is
|
||||||
|
// left completely untouched, regardless of success or failure
|
||||||
|
json copy_for_patch = original;
|
||||||
|
CHECK_THROWS_AS(copy_for_patch.patch(patch), json::other_error&);
|
||||||
|
CHECK(copy_for_patch == original);
|
||||||
|
|
||||||
|
// patch_inplace(), in contrast, already applied the successful
|
||||||
|
// "replace" operation to the document before the "test" operation
|
||||||
|
// threw -- that change is not rolled back
|
||||||
|
json doc = original;
|
||||||
|
CHECK_THROWS_AS(doc.patch_inplace(patch), json::other_error&);
|
||||||
|
CHECK(doc != original);
|
||||||
|
CHECK(doc.at("baz") == "boo");
|
||||||
|
CHECK(doc.at("foo") == "bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("errors")
|
SECTION("errors")
|
||||||
{
|
{
|
||||||
SECTION("unknown operation")
|
SECTION("unknown operation")
|
||||||
|
|||||||
Reference in New Issue
Block a user