diff --git a/json_patch.c b/json_patch.c index 3f9567b..0930816 100644 --- a/json_patch.c +++ b/json_patch.c @@ -263,11 +263,13 @@ static int json_patch_apply_move_copy(struct json_object **res, const char *path, int move, struct json_patch_error *patch_error) { json_pointer_set_cb array_set_cb; + void *array_set_priv; struct json_pointer_get_result from; struct json_object *jfrom; struct json_object *value; const char *from_s; size_t from_s_len; + int add = 1; int rc; if (!json_object_object_get_ex(patch_elem, "from", &jfrom)) { @@ -331,7 +333,10 @@ static int json_patch_apply_move_copy(struct json_object **res, _set_err(ENOMEM, "Unable to copy value referenced by 'from' field"); return -1; } + /* copy is an "add" at the target, and json_object_array_insert_idx_cb() + * reads its priv as the int add flag, not as the "from" result */ array_set_cb = json_object_array_insert_idx_cb; + array_set_priv = &add; } else { json_object_get(from.obj); value = from.obj; @@ -341,9 +346,10 @@ static int json_patch_apply_move_copy(struct json_object **res, return rc; } array_set_cb = json_object_array_move_cb; + array_set_priv = &from; } - rc = json_pointer_set_with_cb(res, path, value, array_set_cb, 0, &from); + rc = json_pointer_set_with_cb(res, path, value, array_set_cb, 0, array_set_priv); if (rc) { _set_err(errno, "Failed to set value at path referenced by 'path' field"); diff --git a/tests/json_patch_tests.json b/tests/json_patch_tests.json index ef7575b..5b9a41d 100644 --- a/tests/json_patch_tests.json +++ b/tests/json_patch_tests.json @@ -386,6 +386,11 @@ "expected": {"foo": [null, null]}, "comment": "null value should be valid array element to be copied" }, + { "doc": {"foo": [1, 2, 3]}, + "patch": [{"op": "copy", "from": "/foo/0", "path": "/foo/1"}], + "expected": {"foo": [1, 1, 2, 3]}, + "comment": "copy to an array index inserts, it does not replace" }, + { "doc": {"foo": [null, 1]}, "patch": [{"op": "remove", "path": "/foo/0"}], "expected": {"foo": [1]}, diff --git a/tests/test_json_patch.expected b/tests/test_json_patch.expected index 28bd7c6..c4fe5f4 100644 --- a/tests/test_json_patch.expected +++ b/tests/test_json_patch.expected @@ -117,6 +117,7 @@ Testing 'null value should be valid array element', doc '{ "foo": [ null ] }' pa Testing 'null value should be valid array element to be replaced with something truthy', doc '{ "foo": [ null ] }' patch '[ { "op": "replace", "path": "\/foo\/0", "value": "truthy" } ]' : OK Testing 'null value should be valid array element to be moved', doc '{ "foo": [ null, 1 ] }' patch '[ { "op": "move", "from": "\/foo\/0", "path": "\/bar" } ]' : OK Testing 'null value should be valid array element to be copied', doc '{ "foo": [ null ] }' patch '[ { "op": "copy", "from": "\/foo\/0", "path": "\/foo\/-" } ]' : OK +Testing 'copy to an array index inserts, it does not replace', doc '{ "foo": [ 1, 2, 3 ] }' patch '[ { "op": "copy", "from": "\/foo\/0", "path": "\/foo\/1" } ]' : OK Testing 'null value should be valid array element to be removed', doc '{ "foo": [ null, 1 ] }' patch '[ { "op": "remove", "path": "\/foo\/0" } ]' : OK Testing 'test should pass despite rearrangement', doc '{ "foo": { "foo": 1, "bar": 2 } }' patch '[ { "op": "test", "path": "\/foo", "value": { "bar": 2, "foo": 1 } } ]' : OK Testing 'test should pass despite (nested) rearrangement', doc '{ "foo": [ { "foo": 1, "bar": 2 } ] }' patch '[ { "op": "test", "path": "\/foo", "value": [ { "bar": 2, "foo": 1 } ] } ]' : OK