mirror of
https://github.com/json-c/json-c.git
synced 2026-11-05 21:20:16 +08:00
json_pointer: find null array elements
json_pointer_get_single_path() returned ENOENT when the array element at an in-range index was NULL, which is how json-c stores a JSON null. A null object member was already found, but on [0, null, 2] "/1" failed with "not found", although RFC 6901 says it references the null value. The array index is bounds-checked just before, so a NULL element now resolves like a null member: json_pointer_get() returns 0 and sets *res to NULL. This also fixes json_patch_apply(), which failed every "test", "replace" and "remove" on a null array element, and every "move" and "copy" from one, with "Did not find element referenced by path field". Added a json_pointer_get() test, and json_patch_tests.json cases that mirror the existing null object member ones.
This commit is contained in:
1 parent
86fe287188
commit
d9b375ff1b
5 files changed
+45
-8
No files matched your search
+2
-8
@@ -102,17 +102,11 @@ static int json_pointer_get_single_path(struct json_object *obj, char *path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
obj = json_object_array_get_idx(obj, *idx);
|
||||
if (obj)
|
||||
{
|
||||
/* A null element is stored as NULL, but it exists */
|
||||
if (value)
|
||||
*value = obj;
|
||||
*value = json_object_array_get_idx(obj, *idx);
|
||||
return 0;
|
||||
}
|
||||
/* Entry not found */
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* RFC states that we first must eval all ~1 then all ~0 */
|
||||
string_replace_all_occurrences_with_char(path, "~1", '/');
|
||||
|
||||
@@ -291,6 +291,31 @@
|
||||
"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": [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}},
|
||||
|
||||
@@ -89,6 +89,11 @@ Testing 'null value should be valid obj property to be moved', doc '{ "foo": nul
|
||||
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 'null value should be valid array element', doc '{ "foo": [ null ] }' patch '[ { "op": "test", "path": "\/foo\/0", "value": null } ]' : OK
|
||||
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 '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
|
||||
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
|
||||
|
||||
@@ -122,6 +122,18 @@ static void test_example_get(void)
|
||||
test_example_int(jo1, json_pointers[i].s, json_pointers[i].i);
|
||||
|
||||
json_object_put(jo1);
|
||||
|
||||
/* Test /1 == null, a null array element is found and returned as NULL */
|
||||
jo1 = json_tokener_parse("[0, null, 2]");
|
||||
jo2 = jo1;
|
||||
assert(0 == json_pointer_get(jo1, "/1", NULL));
|
||||
assert(0 == json_pointer_get(jo1, "/1", &jo2));
|
||||
assert(NULL == jo2);
|
||||
errno = 0;
|
||||
assert(0 != json_pointer_get(jo1, "/1/foo", NULL));
|
||||
assert(errno == ENOENT);
|
||||
printf("PASSED - GET - /1 == null\n");
|
||||
json_object_put(jo1);
|
||||
}
|
||||
|
||||
/* I'm not too happy with the RFC example to test the recursion of the json_pointer_get() function */
|
||||
|
||||
@@ -12,6 +12,7 @@ PASSED - GET - /i\j == 5
|
||||
PASSED - GET - /k"l == 6
|
||||
PASSED - GET - / == 7
|
||||
PASSED - GET - /m~0n == 8
|
||||
PASSED - GET - /1 == null
|
||||
{ "arr": [ { "obj": [ { }, { }, { "obj1": 0, "obj2": "1" } ] } ], "obj": { "obj": { "obj": [ { "obj1": 0, "obj2": "1" } ] } } }
|
||||
PASSED - GET - RECURSION TEST
|
||||
PASSED - GET - LOADED TEST JSON
|
||||
|
||||
Reference in new issue
Block a user