mirror of
https://github.com/json-c/json-c.git
synced 2026-11-09 23:40:14 +08:00
json_object_array_move_cb() added one to the array length when "from"
and "path" are in the same array, so that the old length counted as a
valid target index. A move is a remove followed by an add (RFC 6902
section 4.4), and the add's index must not be greater than the number
of elements left after the remove. With the extra slot,
json_object_array_insert_idx() was called one past the end and padded
the array with a null:
doc: {"foo": [1, 2, 3]}
patch: [{"op": "move", "from": "/foo/0", "path": "/foo/3"}]
returned 0 with {"foo": [2, 3, null, 1]}. It now fails with EINVAL,
like an add to /foo/3 on a two-element array. Moving to /foo/2 or
/foo/- still puts the element last.
712 lines
27 KiB
JSON
712 lines
27 KiB
JSON
[
|
|
{ "comment": "empty list, empty docs",
|
|
"doc": {},
|
|
"patch": [],
|
|
"expected": {} },
|
|
|
|
{ "comment": "empty patch list",
|
|
"doc": {"foo": 1},
|
|
"patch": [],
|
|
"expected": {"foo": 1} },
|
|
|
|
{ "comment": "rearrangements OK?",
|
|
"doc": {"foo": 1, "bar": 2},
|
|
"patch": [],
|
|
"expected": {"bar":2, "foo": 1} },
|
|
|
|
{ "comment": "rearrangements OK? How about one level down ... array",
|
|
"doc": [{"foo": 1, "bar": 2}],
|
|
"patch": [],
|
|
"expected": [{"bar":2, "foo": 1}] },
|
|
|
|
{ "comment": "rearrangements OK? How about one level down...",
|
|
"doc": {"foo":{"foo": 1, "bar": 2}},
|
|
"patch": [],
|
|
"expected": {"foo":{"bar":2, "foo": 1}} },
|
|
|
|
{ "comment": "add replaces any existing field",
|
|
"doc": {"foo": null},
|
|
"patch": [{"op": "add", "path": "/foo", "value":1}],
|
|
"expected": {"foo": 1} },
|
|
|
|
{ "comment": "toplevel array",
|
|
"doc": [],
|
|
"patch": [{"op": "add", "path": "/0", "value": "foo"}],
|
|
"expected": ["foo"] },
|
|
|
|
{ "comment": "toplevel array, no change",
|
|
"doc": ["foo"],
|
|
"patch": [],
|
|
"expected": ["foo"] },
|
|
|
|
{ "comment": "toplevel object, numeric string",
|
|
"doc": {},
|
|
"patch": [{"op": "add", "path": "/foo", "value": "1"}],
|
|
"expected": {"foo":"1"} },
|
|
|
|
{ "comment": "toplevel object, integer",
|
|
"doc": {},
|
|
"patch": [{"op": "add", "path": "/foo", "value": 1}],
|
|
"expected": {"foo":1} },
|
|
|
|
{ "comment": "Toplevel scalar values OK?",
|
|
"doc": "foo",
|
|
"patch": [{"op": "replace", "path": "", "value": "bar"}],
|
|
"expected": "bar"
|
|
},
|
|
|
|
{ "comment": "replace object document with array document?",
|
|
"doc": {},
|
|
"patch": [{"op": "add", "path": "", "value": []}],
|
|
"expected": [] },
|
|
|
|
{ "comment": "replace array document with object document?",
|
|
"doc": [],
|
|
"patch": [{"op": "add", "path": "", "value": {}}],
|
|
"expected": {} },
|
|
|
|
{ "comment": "append to root array document?",
|
|
"doc": [],
|
|
"patch": [{"op": "add", "path": "/-", "value": "hi"}],
|
|
"expected": ["hi"] },
|
|
|
|
{ "comment": "Add, / target",
|
|
"doc": {},
|
|
"patch": [ {"op": "add", "path": "/", "value":1 } ],
|
|
"expected": {"":1} },
|
|
|
|
{ "comment": "Add, /foo/ deep target (trailing slash)",
|
|
"doc": {"foo": {}},
|
|
"patch": [ {"op": "add", "path": "/foo/", "value":1 } ],
|
|
"expected": {"foo":{"": 1}} },
|
|
|
|
{ "comment": "Add composite value at top level",
|
|
"doc": {"foo": 1},
|
|
"patch": [{"op": "add", "path": "/bar", "value": [1, 2]}],
|
|
"expected": {"foo": 1, "bar": [1, 2]} },
|
|
|
|
{ "comment": "Add into composite value",
|
|
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
|
"patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}],
|
|
"expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} },
|
|
|
|
{ "doc": {"bar": [1, 2]},
|
|
"patch": [{"op": "add", "path": "/bar/8", "value": "5"}],
|
|
"error": "Out of bounds (upper)" },
|
|
|
|
{ "doc": {"bar": [1, 2]},
|
|
"patch": [{"op": "add", "path": "/bar/-1", "value": "5"}],
|
|
"error": "Out of bounds (lower)" },
|
|
|
|
{ "doc": {"foo": 1},
|
|
"patch": [{"op": "add", "path": "/bar", "value": true}],
|
|
"expected": {"foo": 1, "bar": true} },
|
|
|
|
{ "doc": {"foo": 1},
|
|
"patch": [{"op": "add", "path": "/bar", "value": false}],
|
|
"expected": {"foo": 1, "bar": false} },
|
|
|
|
{ "doc": {"foo": 1},
|
|
"patch": [{"op": "add", "path": "/bar", "value": null}],
|
|
"expected": {"foo": 1, "bar": null} },
|
|
|
|
{ "comment": "0 can be an array index or object element name",
|
|
"doc": {"foo": 1},
|
|
"patch": [{"op": "add", "path": "/0", "value": "bar"}],
|
|
"expected": {"foo": 1, "0": "bar" } },
|
|
|
|
{ "doc": ["foo"],
|
|
"patch": [{"op": "add", "path": "/1", "value": "bar"}],
|
|
"expected": ["foo", "bar"] },
|
|
|
|
{ "doc": ["foo", "sil"],
|
|
"patch": [{"op": "add", "path": "/1", "value": "bar"}],
|
|
"expected": ["foo", "bar", "sil"] },
|
|
|
|
{ "doc": ["foo", "sil"],
|
|
"patch": [{"op": "add", "path": "/0", "value": "bar"}],
|
|
"expected": ["bar", "foo", "sil"] },
|
|
|
|
{ "comment": "push item to array via last index + 1",
|
|
"doc": ["foo", "sil"],
|
|
"patch": [{"op":"add", "path": "/2", "value": "bar"}],
|
|
"expected": ["foo", "sil", "bar"] },
|
|
|
|
{ "comment": "add item to array at index > length should fail",
|
|
"doc": ["foo", "sil"],
|
|
"patch": [{"op":"add", "path": "/3", "value": "bar"}],
|
|
"error": "index is greater than number of items in array" },
|
|
|
|
{ "comment": "Move within an array to the old array length is out of bounds",
|
|
"doc": {"foo": [1, 2, 3]},
|
|
"patch": [{"op": "move", "from": "/foo/0", "path": "/foo/3"}],
|
|
"error": "/foo/3 is past the end of the array once /foo/0 is removed" },
|
|
|
|
{ "comment": "Move within an array to its last index",
|
|
"doc": {"foo": [1, 2, 3]},
|
|
"patch": [{"op": "move", "from": "/foo/0", "path": "/foo/2"}],
|
|
"expected": {"foo": [2, 3, 1]} },
|
|
|
|
{ "comment": "test integer against equal double",
|
|
"doc": {"n": 1},
|
|
"patch": [{"op": "test", "path": "/n", "value": 1.0}],
|
|
"expected": {"n": 1} },
|
|
|
|
{ "comment": "test double against equal integer",
|
|
"doc": {"n": 1.0},
|
|
"patch": [{"op": "test", "path": "/n", "value": 1}],
|
|
"expected": {"n": 1.0} },
|
|
|
|
{ "comment": "test numeric equality inside arrays and objects",
|
|
"doc": {"a": [1, {"n": -2.0}], "b": null},
|
|
"patch": [{"op": "test", "path": "", "value": {"b": null, "a": [1.0, {"n": -2}]}}],
|
|
"expected": {"a": [1, {"n": -2.0}], "b": null} },
|
|
|
|
{ "comment": "test integer against negative zero",
|
|
"doc": 0,
|
|
"patch": [{"op": "test", "path": "", "value": -0.0}],
|
|
"expected": 0 },
|
|
|
|
{ "comment": "test unsigned integer against equal double",
|
|
"doc": 9223372036854775808,
|
|
"patch": [{"op": "test", "path": "", "value": 9223372036854775808.0}],
|
|
"expected": 9223372036854775808 },
|
|
|
|
{ "comment": "test minimum signed integer against equal double",
|
|
"doc": -9223372036854775808,
|
|
"patch": [{"op": "test", "path": "", "value": -9223372036854775808.0}],
|
|
"expected": -9223372036854775808 },
|
|
|
|
{ "comment": "test does not round integers to doubles",
|
|
"doc": 9007199254740993,
|
|
"patch": [{"op": "test", "path": "", "value": 9007199254740992.0}],
|
|
"error": "different integers must not compare equal after rounding" },
|
|
|
|
{ "comment": "test does not round negative integers to doubles",
|
|
"doc": -9007199254740993,
|
|
"patch": [{"op": "test", "path": "", "value": -9007199254740992.0}],
|
|
"error": "different negative integers must not compare equal after rounding" },
|
|
|
|
{ "comment": "test does not truncate fractional numbers",
|
|
"doc": 1,
|
|
"patch": [{"op": "test", "path": "", "value": 1.5}],
|
|
"error": "fractional number must not compare equal to an integer" },
|
|
|
|
{ "comment": "test does not truncate negative fractional numbers",
|
|
"doc": -1,
|
|
"patch": [{"op": "test", "path": "", "value": -1.5}],
|
|
"error": "negative fractional number must not compare equal to an integer" },
|
|
|
|
{ "comment": "test does not clamp out of range unsigned numbers",
|
|
"doc": 18446744073709551615,
|
|
"patch": [{"op": "test", "path": "", "value": 18446744073709551616.0}],
|
|
"error": "out of range double must not compare equal to UINT64_MAX" },
|
|
|
|
{ "comment": "test does not clamp out of range negative numbers",
|
|
"doc": -9223372036854775808,
|
|
"patch": [{"op": "test", "path": "", "value": -18446744073709551616.0}],
|
|
"error": "out of range double must not compare equal to INT64_MIN" },
|
|
|
|
{ "comment": "test does not coerce boolean values to numbers",
|
|
"doc": true,
|
|
"patch": [{"op": "test", "path": "", "value": 1.0}],
|
|
"error": "boolean is not a number" },
|
|
|
|
{ "comment": "test does not coerce strings to numbers",
|
|
"doc": "1",
|
|
"patch": [{"op": "test", "path": "", "value": 1.0}],
|
|
"error": "string is not a number" },
|
|
|
|
{ "comment": "test checks numeric equality recursively",
|
|
"doc": {"a": [1, {"n": -2}]},
|
|
"patch": [{"op": "test", "path": "", "value": {"a": [1.0, {"n": -3.0}]}}],
|
|
"error": "nested numbers differ" },
|
|
|
|
{ "comment": "test against implementation-specific numeric parsing",
|
|
"doc": {"1e0": "foo"},
|
|
"patch": [{"op": "test", "path": "/1e0", "value": "foo"}],
|
|
"expected": {"1e0": "foo"} },
|
|
|
|
{ "comment": "test with bad number should fail",
|
|
"doc": ["foo", "bar"],
|
|
"patch": [{"op": "test", "path": "/1e0", "value": "bar"}],
|
|
"error": "test op shouldn't get array element 1" },
|
|
|
|
{ "doc": ["foo", "sil"],
|
|
"patch": [{"op": "add", "path": "/bar", "value": 42}],
|
|
"error": "Object operation on array target" },
|
|
|
|
{ "doc": ["foo", "sil"],
|
|
"patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}],
|
|
"expected": ["foo", ["bar", "baz"], "sil"],
|
|
"comment": "value in array add not flattened" },
|
|
|
|
{ "doc": {"foo": 1, "bar": [1, 2, 3, 4]},
|
|
"patch": [{"op": "remove", "path": "/bar"}],
|
|
"expected": {"foo": 1} },
|
|
|
|
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
|
"patch": [{"op": "remove", "path": "/baz/0/qux"}],
|
|
"expected": {"foo": 1, "baz": [{}]} },
|
|
|
|
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
|
"patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}],
|
|
"expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} },
|
|
|
|
{ "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]},
|
|
"patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}],
|
|
"expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} },
|
|
|
|
{ "doc": ["foo"],
|
|
"patch": [{"op": "replace", "path": "/0", "value": "bar"}],
|
|
"expected": ["bar"] },
|
|
|
|
{ "doc": [""],
|
|
"patch": [{"op": "replace", "path": "/0", "value": 0}],
|
|
"expected": [0] },
|
|
|
|
{ "doc": [""],
|
|
"patch": [{"op": "replace", "path": "/0", "value": true}],
|
|
"expected": [true] },
|
|
|
|
{ "doc": [""],
|
|
"patch": [{"op": "replace", "path": "/0", "value": false}],
|
|
"expected": [false] },
|
|
|
|
{ "doc": [""],
|
|
"patch": [{"op": "replace", "path": "/0", "value": null}],
|
|
"expected": [null] },
|
|
|
|
{ "doc": ["foo", "sil"],
|
|
"patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}],
|
|
"expected": ["foo", ["bar", "baz"]],
|
|
"comment": "value in array replace not flattened" },
|
|
|
|
{ "comment": "replace whole document",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}],
|
|
"expected": {"baz": "qux"} },
|
|
|
|
{ "comment": "add whole document, null",
|
|
"doc": {},
|
|
"Note1": "We can't pass null in to json_patch_apply, so start with _something_ and remove it",
|
|
"patch": [
|
|
{"op": "remove", "path": ""},
|
|
{"op": "add", "path": "", "value": {"baz": "qux"}}
|
|
],
|
|
"expected": {"baz": "qux"} },
|
|
|
|
{ "comment": "replace whole document, null",
|
|
"doc": {},
|
|
"Note1": "We can't pass null in to json_patch_apply, so start with _something_ and remove it",
|
|
"patch": [
|
|
{"op": "remove", "path": ""},
|
|
{"op": "replace", "path": "", "value": {"baz": "qux"}}
|
|
],
|
|
"error": "The spec says the target location must exist, so replacing a null document fails"
|
|
},
|
|
|
|
{ "comment": "remove whole document",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": "remove", "path": ""}],
|
|
"expected": null },
|
|
|
|
{ "comment": "remove whole document",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": "remove", "path": ""}],
|
|
"expected": null },
|
|
|
|
{ "comment": "remove whole document, array",
|
|
"doc": ["foo", "bar"],
|
|
"patch": [{"op": "remove", "path": ""}],
|
|
"expected": null },
|
|
|
|
{ "comment": "remove whole document, string",
|
|
"doc": "foo",
|
|
"patch": [{"op": "remove", "path": ""}],
|
|
"expected": null },
|
|
|
|
{ "comment": "remove whole document, null",
|
|
"doc": {},
|
|
"Note1": "We can't pass null in to json_patch_apply, so start with _something_ and remove it",
|
|
"patch": [
|
|
{"op": "remove", "path": ""},
|
|
{"op": "remove", "path": ""},
|
|
],
|
|
"error": "The spec says the target location must exist, so removing a null document fails"
|
|
},
|
|
|
|
{ "comment": "test replace with missing parent key should fail",
|
|
"doc": {"bar": "baz"},
|
|
"patch": [{"op": "replace", "path": "/foo/bar", "value": false}],
|
|
"error": "replace op should fail with missing parent key" },
|
|
|
|
{ "comment": "spurious patch properties",
|
|
"doc": {"foo": 1},
|
|
"patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}],
|
|
"expected": {"foo": 1} },
|
|
|
|
{ "doc": {"foo": null},
|
|
"patch": [{"op": "test", "path": "/foo", "value": null}],
|
|
"expected": {"foo": null},
|
|
"comment": "null value should be valid obj property" },
|
|
|
|
{ "doc": {"foo": null},
|
|
"patch": [{"op": "replace", "path": "/foo", "value": "truthy"}],
|
|
"expected": {"foo": "truthy"},
|
|
"comment": "null value should be valid obj property to be replaced with something truthy" },
|
|
|
|
{ "doc": {"foo": null},
|
|
"patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
|
|
"expected": {"bar": null},
|
|
"comment": "null value should be valid obj property to be moved" },
|
|
|
|
{ "doc": {"foo": null},
|
|
"patch": [{"op": "copy", "from": "/foo", "path": "/bar"}],
|
|
"expected": {"foo": null, "bar": null},
|
|
"comment": "null value should be valid obj property to be copied" },
|
|
|
|
{ "doc": {"foo": null},
|
|
"patch": [{"op": "remove", "path": "/foo"}],
|
|
"expected": {},
|
|
"comment": "null value should be valid obj property to be removed" },
|
|
|
|
{ "doc": {"foo": "bar"},
|
|
"patch": [{"op": "replace", "path": "/foo", "value": null}],
|
|
"expected": {"foo": null},
|
|
"comment": "null value should still be valid obj property replace other value" },
|
|
|
|
{ "doc": {"foo": [null]},
|
|
"patch": [{"op": "test", "path": "/foo/0", "value": null}],
|
|
"expected": {"foo": [null]},
|
|
"comment": "null value should be valid array element" },
|
|
|
|
{ "doc": {"foo": [null]},
|
|
"patch": [{"op": "replace", "path": "/foo/0", "value": "truthy"}],
|
|
"expected": {"foo": ["truthy"]},
|
|
"comment": "null value should be valid array element to be replaced with something truthy" },
|
|
|
|
{ "doc": {"foo": [null, 1]},
|
|
"patch": [{"op": "move", "from": "/foo/0", "path": "/bar"}],
|
|
"expected": {"foo": [1], "bar": null},
|
|
"comment": "null value should be valid array element to be moved" },
|
|
|
|
{ "doc": {"foo": [null]},
|
|
"patch": [{"op": "copy", "from": "/foo/0", "path": "/foo/-"}],
|
|
"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]},
|
|
"comment": "null value should be valid array element to be removed" },
|
|
|
|
{ "doc": {"foo": {"foo": 1, "bar": 2}},
|
|
"patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}],
|
|
"expected": {"foo": {"foo": 1, "bar": 2}},
|
|
"comment": "test should pass despite rearrangement" },
|
|
|
|
{ "doc": {"foo": [{"foo": 1, "bar": 2}]},
|
|
"patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
|
|
"expected": {"foo": [{"foo": 1, "bar": 2}]},
|
|
"comment": "test should pass despite (nested) rearrangement" },
|
|
|
|
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
|
|
"patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}],
|
|
"expected": {"foo": {"bar": [1, 2, 5, 4]}},
|
|
"comment": "test should pass - no error" },
|
|
|
|
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
|
|
"patch": [{"op": "test", "path": "/foo", "value": [1, 2]}],
|
|
"error": "test op should fail" },
|
|
|
|
{ "comment": "Test the whole document",
|
|
"doc": { "foo": 1 },
|
|
"patch": [{"op": "test", "path": "", "value": {"foo": 1}}],
|
|
"expected": { "foo": 1 } },
|
|
|
|
{ "comment": "Test the whole document, no match",
|
|
"doc": { "foo": 1 },
|
|
"patch": [{"op": "test", "path": "", "value": {"foo": 2}}],
|
|
"expected": { "foo": 1 },
|
|
"error": "Tested value does not match original doc" },
|
|
|
|
{ "comment": "Empty-string element",
|
|
"doc": { "": 1 },
|
|
"patch": [{"op": "test", "path": "/", "value": 1}],
|
|
"expected": { "": 1 } },
|
|
|
|
{ "doc": {
|
|
"foo": ["bar", "baz"],
|
|
"": 0,
|
|
"a/b": 1,
|
|
"c%d": 2,
|
|
"e^f": 3,
|
|
"g|h": 4,
|
|
"i\\j": 5,
|
|
"k\"l": 6,
|
|
" ": 7,
|
|
"m~n": 8
|
|
},
|
|
"patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]},
|
|
{"op": "test", "path": "/foo/0", "value": "bar"},
|
|
{"op": "test", "path": "/", "value": 0},
|
|
{"op": "test", "path": "/a~1b", "value": 1},
|
|
{"op": "test", "path": "/c%d", "value": 2},
|
|
{"op": "test", "path": "/e^f", "value": 3},
|
|
{"op": "test", "path": "/g|h", "value": 4},
|
|
{"op": "test", "path": "/i\\j", "value": 5},
|
|
{"op": "test", "path": "/k\"l", "value": 6},
|
|
{"op": "test", "path": "/ ", "value": 7},
|
|
{"op": "test", "path": "/m~0n", "value": 8}],
|
|
"expected": {
|
|
"": 0,
|
|
" ": 7,
|
|
"a/b": 1,
|
|
"c%d": 2,
|
|
"e^f": 3,
|
|
"foo": [
|
|
"bar",
|
|
"baz"
|
|
],
|
|
"g|h": 4,
|
|
"i\\j": 5,
|
|
"k\"l": 6,
|
|
"m~n": 8
|
|
}
|
|
},
|
|
{ "comment": "Move to same location has no effect",
|
|
"doc": {"foo": 1},
|
|
"patch": [{"op": "move", "from": "/foo", "path": "/foo"}],
|
|
"expected": {"foo": 1} },
|
|
|
|
{ "comment": "Move between sibling keys sharing a name prefix is not a parent/child move",
|
|
"doc": {"aa": 1, "aab": 2},
|
|
"patch": [{"op": "move", "from": "/aa", "path": "/aab"}],
|
|
"expected": {"aab": 1} },
|
|
|
|
{ "comment": "Copy between sibling keys sharing a name prefix is not a parent/child move",
|
|
"doc": {"aa": 1, "aab": 2},
|
|
"patch": [{"op": "copy", "from": "/aa", "path": "/aab"}],
|
|
"expected": {"aa": 1, "aab": 1} },
|
|
|
|
{ "comment": "Moving the root to a path without a leading '/' must fail, not free the document",
|
|
"doc": {"a": null},
|
|
"patch": [{"op": "move", "from": "", "path": "a"}],
|
|
"error": "the root is a parent of every other location" },
|
|
|
|
{ "comment": "Copying the root to a path without a leading '/' must fail",
|
|
"doc": {"a": null},
|
|
"patch": [{"op": "copy", "from": "", "path": "a"}],
|
|
"error": "the root is a parent of every other location" },
|
|
|
|
{ "comment": "Remove members whose names need escaping",
|
|
"doc": {"a/b": 1, "m~n": 2, "c": 3},
|
|
"patch": [{"op": "remove", "path": "/a~1b"},
|
|
{"op": "remove", "path": "/m~0n"}],
|
|
"expected": {"c": 3} },
|
|
|
|
{ "comment": "Move from a member whose name needs escaping",
|
|
"doc": {"a/b": 1},
|
|
"patch": [{"op": "move", "from": "/a~1b", "path": "/c"}],
|
|
"expected": {"c": 1} },
|
|
|
|
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
|
"patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
|
|
"expected": {"baz": [{"qux": "hello"}], "bar": 1} },
|
|
|
|
{ "doc": {"baz": [{"qux": "hello"}], "bar": 1},
|
|
"patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}],
|
|
"expected": {"baz": [{}, "hello"], "bar": 1} },
|
|
|
|
{ "doc": {"baz": [{"qux": "hello"}], "bar": 1},
|
|
"patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}],
|
|
"expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} },
|
|
|
|
{ "comment": "replacing the root of the document is possible with add",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}],
|
|
"expected": {"baz":"qux"}},
|
|
|
|
{ "comment": "Adding to \"/-\" adds to the end of the array",
|
|
"doc": [ 1, 2 ],
|
|
"patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ],
|
|
"expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]},
|
|
|
|
{ "comment": "Adding to \"/-\" adds to the end of the array, even n levels down",
|
|
"doc": [ 1, 2, [ 3, [ 4, 5 ] ] ],
|
|
"patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ],
|
|
"expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]},
|
|
|
|
{ "comment": "test remove with bad number should fail",
|
|
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
|
"patch": [{"op": "remove", "path": "/baz/1e0/qux"}],
|
|
"error": "remove op shouldn't remove from array with bad number" },
|
|
|
|
{ "comment": "test remove on array",
|
|
"doc": [1, 2, 3, 4],
|
|
"patch": [{"op": "remove", "path": "/0"}],
|
|
"expected": [2, 3, 4] },
|
|
|
|
{ "comment": "test repeated removes",
|
|
"doc": [1, 2, 3, 4],
|
|
"patch": [{ "op": "remove", "path": "/1" },
|
|
{ "op": "remove", "path": "/2" }],
|
|
"expected": [1, 3] },
|
|
|
|
{ "comment": "test remove with bad index should fail",
|
|
"doc": [1, 2, 3, 4],
|
|
"patch": [{"op": "remove", "path": "/1e0"}],
|
|
"error": "remove op shouldn't remove from array with bad number" },
|
|
|
|
{ "comment": "test replace with bad number should fail",
|
|
"doc": [""],
|
|
"patch": [{"op": "replace", "path": "/1e0", "value": false}],
|
|
"error": "replace op shouldn't replace in array with bad number" },
|
|
|
|
{ "comment": "test copy with bad number should fail",
|
|
"doc": {"baz": [1,2,3], "bar": 1},
|
|
"patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}],
|
|
"error": "copy op shouldn't work with bad number" },
|
|
|
|
{ "comment": "test move with bad number should fail",
|
|
"doc": {"foo": 1, "baz": [1,2,3,4]},
|
|
"patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}],
|
|
"error": "move op shouldn't work with bad number" },
|
|
|
|
{ "comment": "test add with bad number should fail",
|
|
"doc": ["foo", "sil"],
|
|
"patch": [{"op": "add", "path": "/1e0", "value": "bar"}],
|
|
"error": "add op shouldn't add to array with bad number" },
|
|
|
|
{ "comment": "missing 'path' parameter",
|
|
"doc": {},
|
|
"patch": [ { "op": "add", "value": "bar" } ],
|
|
"error": "missing 'path' parameter" },
|
|
|
|
{ "comment": "'path' parameter with null value",
|
|
"doc": {},
|
|
"patch": [ { "op": "add", "path": null, "value": "bar" } ],
|
|
"error": "null is not valid value for 'path'" },
|
|
|
|
{ "comment": "invalid JSON Pointer token",
|
|
"doc": {},
|
|
"patch": [ { "op": "add", "path": "foo", "value": "bar" } ],
|
|
"error": "JSON Pointer should start with a slash" },
|
|
|
|
{ "comment": "missing 'value' parameter to add",
|
|
"doc": [ 1 ],
|
|
"patch": [ { "op": "add", "path": "/-" } ],
|
|
"error": "missing 'value' parameter" },
|
|
|
|
{ "comment": "missing 'value' parameter to replace",
|
|
"doc": [ 1 ],
|
|
"patch": [ { "op": "replace", "path": "/0" } ],
|
|
"error": "missing 'value' parameter" },
|
|
|
|
{ "comment": "missing 'value' parameter to test",
|
|
"doc": [ null ],
|
|
"patch": [ { "op": "test", "path": "/0" } ],
|
|
"error": "missing 'value' parameter" },
|
|
|
|
{ "comment": "missing value parameter to test - where undef is falsy",
|
|
"doc": [ false ],
|
|
"patch": [ { "op": "test", "path": "/0" } ],
|
|
"error": "missing 'value' parameter" },
|
|
|
|
{ "comment": "missing from parameter to copy",
|
|
"doc": [ 1 ],
|
|
"patch": [ { "op": "copy", "path": "/-" } ],
|
|
"error": "missing 'from' parameter" },
|
|
|
|
{ "comment": "missing from location to copy",
|
|
"doc": { "foo": 1 },
|
|
"patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ],
|
|
"error": "missing 'from' location" },
|
|
|
|
{ "comment": "missing from parameter to move",
|
|
"doc": { "foo": 1 },
|
|
"patch": [ { "op": "move", "path": "" } ],
|
|
"error": "missing 'from' parameter" },
|
|
|
|
{ "comment": "missing from location to move",
|
|
"doc": { "foo": 1 },
|
|
"patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ],
|
|
"error": "missing 'from' location" },
|
|
|
|
{ "comment": "duplicate ops, json-c parses this as op:move",
|
|
"doc": { "foo": "bar" },
|
|
"patch": [ { "op": "add", "path": "/baz", "value": "qux",
|
|
"op": "move", "from":"/foo" } ],
|
|
"error_wont_happen_in_jsonc": "patch has two 'op' members",
|
|
"expected": { "baz": "bar" }
|
|
},
|
|
|
|
{ "comment": "unrecognized op should fail",
|
|
"doc": {"foo": 1},
|
|
"patch": [{"op": "spam", "path": "/foo", "value": 1}],
|
|
"error": "Unrecognized op 'spam'" },
|
|
|
|
{ "comment": "test with bad array number that has leading zeros",
|
|
"doc": ["foo", "bar"],
|
|
"patch": [{"op": "test", "path": "/00", "value": "foo"}],
|
|
"error": "test op should reject the array value, it has leading zeros" },
|
|
|
|
{ "comment": "test with bad array number that has leading zeros",
|
|
"doc": ["foo", "bar"],
|
|
"patch": [{"op": "test", "path": "/01", "value": "bar"}],
|
|
"error": "test op should reject the array value, it has leading zeros" },
|
|
|
|
{ "comment": "Removing nonexistent field",
|
|
"doc": {"foo" : "bar"},
|
|
"patch": [{"op": "remove", "path": "/baz"}],
|
|
"error": "removing a nonexistent field should fail" },
|
|
|
|
{ "comment": "Removing deep nonexistent path",
|
|
"doc": {"foo" : "bar"},
|
|
"patch": [{"op": "remove", "path": "/missing1/missing2"}],
|
|
"error": "removing a nonexistent field should fail" },
|
|
|
|
{ "comment": "Removing nonexistent index",
|
|
"doc": ["foo", "bar"],
|
|
"patch": [{"op": "remove", "path": "/2"}],
|
|
"error": "removing a nonexistent index should fail" },
|
|
|
|
{ "comment": "Patch with different capitalisation than doc",
|
|
"doc": {"foo":"bar"},
|
|
"patch": [{"op": "add", "path": "/FOO", "value": "BAR"}],
|
|
"expected": {"foo": "bar", "FOO": "BAR"}
|
|
},
|
|
|
|
{ "comment": "copy must duplicate the value, not alias it, so no cycle can form",
|
|
"doc": {"a": {"p": {}}},
|
|
"patch": [{"op": "copy", "from": "/a", "path": "/b"},
|
|
{"op": "copy", "from": "/b", "path": "/a/p/x"}],
|
|
"expected": {"a": {"p": {"x": {"p": {}}}}, "b": {"p": {}}}
|
|
},
|
|
|
|
{ "comment": "null op field must be rejected, not dereferenced",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": null, "path": "/foo"}],
|
|
"error": "a null op field should fail rather than crash"
|
|
},
|
|
|
|
{ "comment": "null from field must be rejected, not dereferenced",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": "move", "from": null, "path": "/foo"}],
|
|
"error": "a null from field should fail rather than crash"
|
|
},
|
|
|
|
{ "comment": "null path field must be rejected, not dereferenced",
|
|
"doc": {"foo": "bar"},
|
|
"patch": [{"op": "remove", "path": null}],
|
|
"error": "a null path field should fail rather than crash"
|
|
}
|
|
|
|
]
|