Essentially, this change adds the test cases from this repo:
https://github.com/json-patch/json-patch-tests
Specifically:
https://github.com/json-patch/json-patch-tests/blob/master/spec_tests.json
https://github.com/json-patch/json-patch-tests/blob/master/tests.json
The files were taken at the date of this commit, at git hash
ea3af85790
Some tests may not have an 'expected' or 'error' field. Those are ignored.
One test was disabled manually via "disabled_in_json_c", because it tries
an impossible test, i.e. to add 2 "op" fields in the same patch entry,
something which is impossible in a JSON object.
For the 'error' cases, right now we only test that an error happens.
Later, we can extend this to check the error codes.
Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
tags/json-c-0.17-20230812
@@ -39,6 +39,9 @@ set(ALL_TEST_NAMES | |||
if (NOT DISABLE_JSON_POINTER) | |||
set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_pointer) | |||
if (NOT DISABLE_JSON_PATCH) | |||
set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_patch) | |||
endif() | |||
endif() | |||
foreach(TESTNAME ${ALL_TEST_NAMES}) | |||
@@ -0,0 +1,233 @@ | |||
[ | |||
{ | |||
"comment": "4.1. add with missing object", | |||
"doc": { "q": { "bar": 2 } }, | |||
"patch": [ {"op": "add", "path": "/a/b", "value": 1} ], | |||
"error": | |||
"path /a does not exist -- missing objects are not created recursively" | |||
}, | |||
{ | |||
"comment": "A.1. Adding an Object Member", | |||
"doc": { | |||
"foo": "bar" | |||
}, | |||
"patch": [ | |||
{ "op": "add", "path": "/baz", "value": "qux" } | |||
], | |||
"expected": { | |||
"baz": "qux", | |||
"foo": "bar" | |||
} | |||
}, | |||
{ | |||
"comment": "A.2. Adding an Array Element", | |||
"doc": { | |||
"foo": [ "bar", "baz" ] | |||
}, | |||
"patch": [ | |||
{ "op": "add", "path": "/foo/1", "value": "qux" } | |||
], | |||
"expected": { | |||
"foo": [ "bar", "qux", "baz" ] | |||
} | |||
}, | |||
{ | |||
"comment": "A.3. Removing an Object Member", | |||
"doc": { | |||
"baz": "qux", | |||
"foo": "bar" | |||
}, | |||
"patch": [ | |||
{ "op": "remove", "path": "/baz" } | |||
], | |||
"expected": { | |||
"foo": "bar" | |||
} | |||
}, | |||
{ | |||
"comment": "A.4. Removing an Array Element", | |||
"doc": { | |||
"foo": [ "bar", "qux", "baz" ] | |||
}, | |||
"patch": [ | |||
{ "op": "remove", "path": "/foo/1" } | |||
], | |||
"expected": { | |||
"foo": [ "bar", "baz" ] | |||
} | |||
}, | |||
{ | |||
"comment": "A.5. Replacing a Value", | |||
"doc": { | |||
"baz": "qux", | |||
"foo": "bar" | |||
}, | |||
"patch": [ | |||
{ "op": "replace", "path": "/baz", "value": "boo" } | |||
], | |||
"expected": { | |||
"baz": "boo", | |||
"foo": "bar" | |||
} | |||
}, | |||
{ | |||
"comment": "A.6. Moving a Value", | |||
"doc": { | |||
"foo": { | |||
"bar": "baz", | |||
"waldo": "fred" | |||
}, | |||
"qux": { | |||
"corge": "grault" | |||
} | |||
}, | |||
"patch": [ | |||
{ "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } | |||
], | |||
"expected": { | |||
"foo": { | |||
"bar": "baz" | |||
}, | |||
"qux": { | |||
"corge": "grault", | |||
"thud": "fred" | |||
} | |||
} | |||
}, | |||
{ | |||
"comment": "A.7. Moving an Array Element", | |||
"doc": { | |||
"foo": [ "all", "grass", "cows", "eat" ] | |||
}, | |||
"patch": [ | |||
{ "op": "move", "from": "/foo/1", "path": "/foo/3" } | |||
], | |||
"expected": { | |||
"foo": [ "all", "cows", "eat", "grass" ] | |||
} | |||
}, | |||
{ | |||
"comment": "A.8. Testing a Value: Success", | |||
"doc": { | |||
"baz": "qux", | |||
"foo": [ "a", 2, "c" ] | |||
}, | |||
"patch": [ | |||
{ "op": "test", "path": "/baz", "value": "qux" }, | |||
{ "op": "test", "path": "/foo/1", "value": 2 } | |||
], | |||
"expected": { | |||
"baz": "qux", | |||
"foo": [ "a", 2, "c" ] | |||
} | |||
}, | |||
{ | |||
"comment": "A.9. Testing a Value: Error", | |||
"doc": { | |||
"baz": "qux" | |||
}, | |||
"patch": [ | |||
{ "op": "test", "path": "/baz", "value": "bar" } | |||
], | |||
"error": "string not equivalent" | |||
}, | |||
{ | |||
"comment": "A.10. Adding a nested Member Object", | |||
"doc": { | |||
"foo": "bar" | |||
}, | |||
"patch": [ | |||
{ "op": "add", "path": "/child", "value": { "grandchild": { } } } | |||
], | |||
"expected": { | |||
"foo": "bar", | |||
"child": { | |||
"grandchild": { | |||
} | |||
} | |||
} | |||
}, | |||
{ | |||
"comment": "A.11. Ignoring Unrecognized Elements", | |||
"doc": { | |||
"foo":"bar" | |||
}, | |||
"patch": [ | |||
{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 } | |||
], | |||
"expected": { | |||
"foo":"bar", | |||
"baz":"qux" | |||
} | |||
}, | |||
{ | |||
"comment": "A.12. Adding to a Non-existent Target", | |||
"doc": { | |||
"foo": "bar" | |||
}, | |||
"patch": [ | |||
{ "op": "add", "path": "/baz/bat", "value": "qux" } | |||
], | |||
"error": "add to a non-existent target" | |||
}, | |||
{ | |||
"comment": "A.13 Invalid JSON Patch Document", | |||
"doc": { | |||
"foo": "bar" | |||
}, | |||
"patch": [ | |||
{ "op": "add", "path": "/baz", "value": "qux", "op": "remove" } | |||
], | |||
"error": "operation has two 'op' members", | |||
"disabled": true | |||
}, | |||
{ | |||
"comment": "A.14. ~ Escape Ordering", | |||
"doc": { | |||
"/": 9, | |||
"~1": 10 | |||
}, | |||
"patch": [{"op": "test", "path": "/~01", "value": 10}], | |||
"expected": { | |||
"/": 9, | |||
"~1": 10 | |||
} | |||
}, | |||
{ | |||
"comment": "A.15. Comparing Strings and Numbers", | |||
"doc": { | |||
"/": 9, | |||
"~1": 10 | |||
}, | |||
"patch": [{"op": "test", "path": "/~01", "value": "10"}], | |||
"error": "number is not equal to string" | |||
}, | |||
{ | |||
"comment": "A.16. Adding an Array Value", | |||
"doc": { | |||
"foo": ["bar"] | |||
}, | |||
"patch": [{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }], | |||
"expected": { | |||
"foo": ["bar", ["abc", "def"]] | |||
} | |||
} | |||
] |
@@ -0,0 +1,485 @@ | |||
[ | |||
{ "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", | |||
"disabled": true }, | |||
{ "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": "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": "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": {"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": "Whole document", | |||
"doc": { "foo": 1 }, | |||
"patch": [{"op": "test", "path": "", "value": {"foo": 1}}], | |||
"disabled": true }, | |||
{ "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} }, | |||
{ "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", | |||
"doc": { "foo": "bar" }, | |||
"patch": [ { "op": "add", "path": "/baz", "value": "qux", | |||
"op": "move", "from":"/foo" } ], | |||
"error": "patch has two 'op' members", | |||
"disabled_in_json_c": true, | |||
"disabled": true }, | |||
{ "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"} | |||
} | |||
] |
@@ -0,0 +1,119 @@ | |||
#ifdef NDEBUG | |||
#undef NDEBUG | |||
#endif | |||
#include <assert.h> | |||
#include <errno.h> | |||
#include <limits.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "json.h" | |||
#ifndef PATH_MAX | |||
#define PATH_MAX 256 | |||
#endif | |||
void test_json_patch_op(struct json_object *jo) | |||
{ | |||
const char *comment = json_object_get_string(json_object_object_get(jo, "comment")); | |||
struct json_object *doc = json_object_object_get(jo, "doc"); | |||
struct json_object *patch = json_object_object_get(jo, "patch"); | |||
struct json_object *expected = json_object_object_get(jo, "expected"); | |||
struct json_object *error = json_object_object_get(jo, "error"); | |||
int disabled_test = json_object_get_boolean(json_object_object_get(jo, "disabled_in_json_c")); | |||
const char *error_s = json_object_get_string(error); | |||
struct json_object *res = NULL; | |||
int ret; | |||
printf("Testing '%s', doc '%s' patch '%s' : ", | |||
comment ? comment : error_s, | |||
json_object_get_string(doc), | |||
json_object_get_string(patch)); | |||
if (disabled_test) { | |||
printf("SKIPPING - disabled in the test spec\n"); | |||
return; | |||
} | |||
if (!error && !expected) { | |||
printf("SKIPPING - no expected or error conditions in test\n"); | |||
return; | |||
} | |||
fflush(stdout); | |||
if (error) { | |||
assert(-1 == json_patch_apply(doc, patch, &res)); | |||
assert(res == NULL); | |||
} else { | |||
ret = json_patch_apply(doc, patch, &res); | |||
if (ret) { | |||
fprintf(stderr, "json_patch_apply() returned '%d'\n", ret); | |||
fprintf(stderr, "Expected: %s\n", json_object_get_string(expected)); | |||
fprintf(stderr, "Got: %s\n", json_object_get_string(res)); | |||
fflush(stderr); | |||
assert(0); | |||
} | |||
assert(res != NULL); | |||
ret = json_object_equal(expected, res); | |||
if (ret == 0) { | |||
fprintf(stderr, "json_object_equal() returned '%d'\n", ret); | |||
fprintf(stderr, "Expected: %s\n", json_object_get_string(expected)); | |||
fprintf(stderr, "Got: %s\n", json_object_get_string(res)); | |||
fflush(stderr); | |||
assert(0); | |||
} | |||
json_object_put(res); | |||
res = NULL; | |||
} | |||
printf("OK\n"); | |||
} | |||
void test_json_patch_using_file(const char *testdir, const char *filename) | |||
{ | |||
char full_filename[PATH_MAX]; | |||
(void)snprintf(full_filename, sizeof(full_filename), "%s/%s", testdir, filename); | |||
int i; | |||
json_object *jo = json_object_from_file(full_filename); | |||
if (!jo) { | |||
fprintf(stderr, "FAIL: unable to open %s: %s\n", full_filename, strerror(errno)); | |||
exit(EXIT_FAILURE); | |||
} | |||
for (i = 0; i < json_object_array_length(jo); i++) { | |||
struct json_object *jo1 = json_object_array_get_idx(jo, i); | |||
test_json_patch_op(jo1); | |||
} | |||
json_object_put(jo); | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
const char *testdir; | |||
if (argc < 2) | |||
{ | |||
fprintf(stderr, | |||
"Usage: %s <testdir>\n" | |||
" <testdir> is the location of input files\n", | |||
argv[0]); | |||
return EXIT_FAILURE; | |||
} | |||
testdir = argv[1]; | |||
// Test json_c_version.c | |||
if (strncmp(json_c_version(), JSON_C_VERSION, sizeof(JSON_C_VERSION))) | |||
{ | |||
printf("FAIL: Output from json_c_version(): %s does not match %s", | |||
json_c_version(), JSON_C_VERSION); | |||
return EXIT_FAILURE; | |||
} | |||
if (json_c_version_num() != JSON_C_VERSION_NUM) | |||
{ | |||
printf("FAIL: Output from json_c_version_num(): %d does not match %d", | |||
json_c_version_num(), JSON_C_VERSION_NUM); | |||
return EXIT_FAILURE; | |||
} | |||
test_json_patch_using_file(testdir, "json_patch_spec_tests.json"); | |||
test_json_patch_using_file(testdir, "json_patch_tests.json"); | |||
return 0; | |||
} |
@@ -0,0 +1,110 @@ | |||
Testing '4.1. add with missing object', doc '{ "q": { "bar": 2 } }' patch '[ { "op": "add", "path": "\/a\/b", "value": 1 } ]' : OK | |||
Testing 'A.1. Adding an Object Member', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/baz", "value": "qux" } ]' : OK | |||
Testing 'A.2. Adding an Array Element', doc '{ "foo": [ "bar", "baz" ] }' patch '[ { "op": "add", "path": "\/foo\/1", "value": "qux" } ]' : OK | |||
Testing 'A.3. Removing an Object Member', doc '{ "baz": "qux", "foo": "bar" }' patch '[ { "op": "remove", "path": "\/baz" } ]' : OK | |||
Testing 'A.4. Removing an Array Element', doc '{ "foo": [ "bar", "qux", "baz" ] }' patch '[ { "op": "remove", "path": "\/foo\/1" } ]' : OK | |||
Testing 'A.5. Replacing a Value', doc '{ "baz": "qux", "foo": "bar" }' patch '[ { "op": "replace", "path": "\/baz", "value": "boo" } ]' : OK | |||
Testing 'A.6. Moving a Value', doc '{ "foo": { "bar": "baz", "waldo": "fred" }, "qux": { "corge": "grault" } }' patch '[ { "op": "move", "from": "\/foo\/waldo", "path": "\/qux\/thud" } ]' : OK | |||
Testing 'A.7. Moving an Array Element', doc '{ "foo": [ "all", "grass", "cows", "eat" ] }' patch '[ { "op": "move", "from": "\/foo\/1", "path": "\/foo\/3" } ]' : OK | |||
Testing 'A.8. Testing a Value: Success', doc '{ "baz": "qux", "foo": [ "a", 2, "c" ] }' patch '[ { "op": "test", "path": "\/baz", "value": "qux" }, { "op": "test", "path": "\/foo\/1", "value": 2 } ]' : OK | |||
Testing 'A.9. Testing a Value: Error', doc '{ "baz": "qux" }' patch '[ { "op": "test", "path": "\/baz", "value": "bar" } ]' : OK | |||
Testing 'A.10. Adding a nested Member Object', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/child", "value": { "grandchild": { } } } ]' : OK | |||
Testing 'A.11. Ignoring Unrecognized Elements', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/baz", "value": "qux", "xyz": 123 } ]' : OK | |||
Testing 'A.12. Adding to a Non-existent Target', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/baz\/bat", "value": "qux" } ]' : OK | |||
Testing 'A.13 Invalid JSON Patch Document', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "\/baz", "value": "qux" } ]' : OK | |||
Testing 'A.14. ~ Escape Ordering', doc '{ "\/": 9, "~1": 10 }' patch '[ { "op": "test", "path": "\/~01", "value": 10 } ]' : OK | |||
Testing 'A.15. Comparing Strings and Numbers', doc '{ "\/": 9, "~1": 10 }' patch '[ { "op": "test", "path": "\/~01", "value": "10" } ]' : OK | |||
Testing 'A.16. Adding an Array Value', doc '{ "foo": [ "bar" ] }' patch '[ { "op": "add", "path": "\/foo\/-", "value": [ "abc", "def" ] } ]' : OK | |||
Testing 'empty list, empty docs', doc '{ }' patch '[ ]' : OK | |||
Testing 'empty patch list', doc '{ "foo": 1 }' patch '[ ]' : OK | |||
Testing 'rearrangements OK?', doc '{ "foo": 1, "bar": 2 }' patch '[ ]' : OK | |||
Testing 'rearrangements OK? How about one level down ... array', doc '[ { "foo": 1, "bar": 2 } ]' patch '[ ]' : OK | |||
Testing 'rearrangements OK? How about one level down...', doc '{ "foo": { "foo": 1, "bar": 2 } }' patch '[ ]' : OK | |||
Testing 'add replaces any existing field', doc '{ "foo": null }' patch '[ { "op": "add", "path": "\/foo", "value": 1 } ]' : OK | |||
Testing 'toplevel array', doc '[ ]' patch '[ { "op": "add", "path": "\/0", "value": "foo" } ]' : OK | |||
Testing 'toplevel array, no change', doc '[ "foo" ]' patch '[ ]' : OK | |||
Testing 'toplevel object, numeric string', doc '{ }' patch '[ { "op": "add", "path": "\/foo", "value": "1" } ]' : OK | |||
Testing 'toplevel object, integer', doc '{ }' patch '[ { "op": "add", "path": "\/foo", "value": 1 } ]' : OK | |||
Testing 'Toplevel scalar values OK?', doc 'foo' patch '[ { "op": "replace", "path": "", "value": "bar" } ]' : OK | |||
Testing 'replace object document with array document?', doc '{ }' patch '[ { "op": "add", "path": "", "value": [ ] } ]' : OK | |||
Testing 'replace array document with object document?', doc '[ ]' patch '[ { "op": "add", "path": "", "value": { } } ]' : OK | |||
Testing 'append to root array document?', doc '[ ]' patch '[ { "op": "add", "path": "\/-", "value": "hi" } ]' : OK | |||
Testing 'Add, / target', doc '{ }' patch '[ { "op": "add", "path": "\/", "value": 1 } ]' : OK | |||
Testing 'Add, /foo/ deep target (trailing slash)', doc '{ "foo": { } }' patch '[ { "op": "add", "path": "\/foo\/", "value": 1 } ]' : OK | |||
Testing 'Add composite value at top level', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": [ 1, 2 ] } ]' : OK | |||
Testing 'Add into composite value', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "add", "path": "\/baz\/0\/foo", "value": "world" } ]' : OK | |||
Testing 'Out of bounds (upper)', doc '{ "bar": [ 1, 2 ] }' patch '[ { "op": "add", "path": "\/bar\/8", "value": "5" } ]' : OK | |||
Testing 'Out of bounds (lower)', doc '{ "bar": [ 1, 2 ] }' patch '[ { "op": "add", "path": "\/bar\/-1", "value": "5" } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": true } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": false } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": null } ]' : OK | |||
Testing '0 can be an array index or object element name', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/0", "value": "bar" } ]' : OK | |||
Testing '(null)', doc '[ "foo" ]' patch '[ { "op": "add", "path": "\/1", "value": "bar" } ]' : OK | |||
Testing '(null)', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/1", "value": "bar" } ]' : OK | |||
Testing '(null)', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/0", "value": "bar" } ]' : OK | |||
Testing 'push item to array via last index + 1', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/2", "value": "bar" } ]' : OK | |||
Testing 'add item to array at index > length should fail', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/3", "value": "bar" } ]' : OK | |||
Testing 'test against implementation-specific numeric parsing', doc '{ "1e0": "foo" }' patch '[ { "op": "test", "path": "\/1e0", "value": "foo" } ]' : OK | |||
Testing 'test with bad number should fail', doc '[ "foo", "bar" ]' patch '[ { "op": "test", "path": "\/1e0", "value": "bar" } ]' : OK | |||
Testing 'Object operation on array target', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/bar", "value": 42 } ]' : OK | |||
Testing 'value in array add not flattened', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/1", "value": [ "bar", "baz" ] } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1, "bar": [ 1, 2, 3, 4 ] }' patch '[ { "op": "remove", "path": "\/bar" } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "remove", "path": "\/baz\/0\/qux" } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "replace", "path": "\/foo", "value": [ 1, 2, 3, 4 ] } ]' : OK | |||
Testing '(null)', doc '{ "foo": [ 1, 2, 3, 4 ], "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "replace", "path": "\/baz\/0\/qux", "value": "world" } ]' : OK | |||
Testing '(null)', doc '[ "foo" ]' patch '[ { "op": "replace", "path": "\/0", "value": "bar" } ]' : OK | |||
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": 0 } ]' : OK | |||
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": true } ]' : OK | |||
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": false } ]' : OK | |||
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": null } ]' : OK | |||
Testing 'value in array replace not flattened', doc '[ "foo", "sil" ]' patch '[ { "op": "replace", "path": "\/1", "value": [ "bar", "baz" ] } ]' : OK | |||
Testing 'replace whole document', doc '{ "foo": "bar" }' patch '[ { "op": "replace", "path": "", "value": { "baz": "qux" } } ]' : OK | |||
Testing 'test replace with missing parent key should fail', doc '{ "bar": "baz" }' patch '[ { "op": "replace", "path": "\/foo\/bar", "value": false } ]' : OK | |||
Testing 'spurious patch properties', doc '{ "foo": 1 }' patch '[ { "op": "test", "path": "\/foo", "value": 1, "spurious": 1 } ]' : OK | |||
Testing 'null value should be valid obj property', doc '{ "foo": null }' patch '[ { "op": "test", "path": "\/foo", "value": null } ]' : OK | |||
Testing 'null value should be valid obj property to be replaced with something truthy', doc '{ "foo": null }' patch '[ { "op": "replace", "path": "\/foo", "value": "truthy" } ]' : OK | |||
Testing 'null value should be valid obj property to be moved', doc '{ "foo": null }' patch '[ { "op": "move", "from": "\/foo", "path": "\/bar" } ]' : OK | |||
Testing 'null value should be valid obj property to be copied', doc '{ "foo": null }' patch '[ { "op": "copy", "from": "\/foo", "path": "\/bar" } ]' : OK | |||
Testing 'null value should be valid obj property to be removed', doc '{ "foo": null }' patch '[ { "op": "remove", "path": "\/foo" } ]' : OK | |||
Testing 'null value should still be valid obj property replace other value', doc '{ "foo": "bar" }' patch '[ { "op": "replace", "path": "\/foo", "value": null } ]' : 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 | |||
Testing 'test should pass - no error', doc '{ "foo": { "bar": [ 1, 2, 5, 4 ] } }' patch '[ { "op": "test", "path": "\/foo", "value": { "bar": [ 1, 2, 5, 4 ] } } ]' : OK | |||
Testing 'test op should fail', doc '{ "foo": { "bar": [ 1, 2, 5, 4 ] } }' patch '[ { "op": "test", "path": "\/foo", "value": [ 1, 2 ] } ]' : OK | |||
Testing 'Whole document', doc '{ "foo": 1 }' patch '[ { "op": "test", "path": "", "value": { "foo": 1 } } ]' : SKIPPING - no expected or error conditions in test | |||
Testing 'Empty-string element', doc '{ "": 1 }' patch '[ { "op": "test", "path": "\/", "value": 1 } ]' : OK | |||
Testing '(null)', 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 } ]' : OK | |||
Testing 'Move to same location has no effect', doc '{ "foo": 1 }' patch '[ { "op": "move", "from": "\/foo", "path": "\/foo" } ]' : OK | |||
Testing '(null)', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "move", "from": "\/foo", "path": "\/bar" } ]' : OK | |||
Testing '(null)', doc '{ "baz": [ { "qux": "hello" } ], "bar": 1 }' patch '[ { "op": "move", "from": "\/baz\/0\/qux", "path": "\/baz\/1" } ]' : OK | |||
Testing '(null)', doc '{ "baz": [ { "qux": "hello" } ], "bar": 1 }' patch '[ { "op": "copy", "from": "\/baz\/0", "path": "\/boo" } ]' : OK | |||
Testing 'replacing the root of the document is possible with add', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "", "value": { "baz": "qux" } } ]' : OK | |||
Testing 'Adding to "/-" adds to the end of the array', doc '[ 1, 2 ]' patch '[ { "op": "add", "path": "\/-", "value": { "foo": [ "bar", "baz" ] } } ]' : OK | |||
Testing '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" ] } } ]' : OK | |||
Testing 'test remove with bad number should fail', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "remove", "path": "\/baz\/1e0\/qux" } ]' : OK | |||
Testing 'test remove on array', doc '[ 1, 2, 3, 4 ]' patch '[ { "op": "remove", "path": "\/0" } ]' : OK | |||
Testing 'test repeated removes', doc '[ 1, 2, 3, 4 ]' patch '[ { "op": "remove", "path": "\/1" }, { "op": "remove", "path": "\/2" } ]' : OK | |||
Testing 'test remove with bad index should fail', doc '[ 1, 2, 3, 4 ]' patch '[ { "op": "remove", "path": "\/1e0" } ]' : OK | |||
Testing 'test replace with bad number should fail', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/1e0", "value": false } ]' : OK | |||
Testing 'test copy with bad number should fail', doc '{ "baz": [ 1, 2, 3 ], "bar": 1 }' patch '[ { "op": "copy", "from": "\/baz\/1e0", "path": "\/boo" } ]' : OK | |||
Testing 'test move with bad number should fail', doc '{ "foo": 1, "baz": [ 1, 2, 3, 4 ] }' patch '[ { "op": "move", "from": "\/baz\/1e0", "path": "\/foo" } ]' : OK | |||
Testing 'test add with bad number should fail', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/1e0", "value": "bar" } ]' : OK | |||
Testing 'missing 'path' parameter', doc '{ }' patch '[ { "op": "add", "value": "bar" } ]' : OK | |||
Testing ''path' parameter with null value', doc '{ }' patch '[ { "op": "add", "path": null, "value": "bar" } ]' : OK | |||
Testing 'invalid JSON Pointer token', doc '{ }' patch '[ { "op": "add", "path": "foo", "value": "bar" } ]' : OK | |||
Testing 'missing 'value' parameter to add', doc '[ 1 ]' patch '[ { "op": "add", "path": "\/-" } ]' : OK | |||
Testing 'missing 'value' parameter to replace', doc '[ 1 ]' patch '[ { "op": "replace", "path": "\/0" } ]' : OK | |||
Testing 'missing 'value' parameter to test', doc '[ null ]' patch '[ { "op": "test", "path": "\/0" } ]' : OK | |||
Testing 'missing value parameter to test - where undef is falsy', doc '[ false ]' patch '[ { "op": "test", "path": "\/0" } ]' : OK | |||
Testing 'missing from parameter to copy', doc '[ 1 ]' patch '[ { "op": "copy", "path": "\/-" } ]' : OK | |||
Testing 'missing from location to copy', doc '{ "foo": 1 }' patch '[ { "op": "copy", "from": "\/bar", "path": "\/foo" } ]' : OK | |||
Testing 'missing from parameter to move', doc '{ "foo": 1 }' patch '[ { "op": "move", "path": "" } ]' : OK | |||
Testing 'missing from location to move', doc '{ "foo": 1 }' patch '[ { "op": "move", "from": "\/bar", "path": "\/foo" } ]' : OK | |||
Testing 'duplicate ops', doc '{ "foo": "bar" }' patch '[ { "op": "move", "path": "\/baz", "value": "qux", "from": "\/foo" } ]' : SKIPPING - disabled in the test spec | |||
Testing 'unrecognized op should fail', doc '{ "foo": 1 }' patch '[ { "op": "spam", "path": "\/foo", "value": 1 } ]' : OK | |||
Testing 'test with bad array number that has leading zeros', doc '[ "foo", "bar" ]' patch '[ { "op": "test", "path": "\/00", "value": "foo" } ]' : OK | |||
Testing 'test with bad array number that has leading zeros', doc '[ "foo", "bar" ]' patch '[ { "op": "test", "path": "\/01", "value": "bar" } ]' : OK | |||
Testing 'Removing nonexistent field', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "\/baz" } ]' : OK | |||
Testing 'Removing deep nonexistent path', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "\/missing1\/missing2" } ]' : OK | |||
Testing 'Removing nonexistent index', doc '[ "foo", "bar" ]' patch '[ { "op": "remove", "path": "\/2" } ]' : OK | |||
Testing 'Patch with different capitalisation than doc', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/FOO", "value": "BAR" } ]' : OK |
@@ -0,0 +1,17 @@ | |||
#!/bin/sh | |||
export _JSON_C_STRERROR_ENABLE=1 | |||
# Common definitions | |||
if test -z "$srcdir"; then | |||
srcdir="${0%/*}" | |||
test "$srcdir" = "$0" && srcdir=. | |||
test -z "$srcdir" && srcdir=. | |||
fi | |||
. "$srcdir/test-defs.sh" | |||
filename=$(basename "$0") | |||
filename="${filename%.*}" | |||
run_output_test $filename "$srcdir" | |||
exit $? |