1[ 2 { "comment": "empty list, empty docs", 3 "doc": {}, 4 "patch": [], 5 "expected": {} }, 6 7 { "comment": "empty patch list", 8 "doc": {"foo": 1}, 9 "patch": [], 10 "expected": {"foo": 1} }, 11 12 { "comment": "rearrangements OK?", 13 "doc": {"foo": 1, "bar": 2}, 14 "patch": [], 15 "expected": {"bar":2, "foo": 1} }, 16 17 { "comment": "rearrangements OK? How about one level down ... array", 18 "doc": [{"foo": 1, "bar": 2}], 19 "patch": [], 20 "expected": [{"bar":2, "foo": 1}] }, 21 22 { "comment": "rearrangements OK? How about one level down...", 23 "doc": {"foo":{"foo": 1, "bar": 2}}, 24 "patch": [], 25 "expected": {"foo":{"bar":2, "foo": 1}} }, 26 27 { "comment": "add replaces any existing field", 28 "doc": {"foo": null}, 29 "patch": [{"op": "add", "path": "/foo", "value":1}], 30 "expected": {"foo": 1} }, 31 32 { "comment": "toplevel array", 33 "doc": [], 34 "patch": [{"op": "add", "path": "/0", "value": "foo"}], 35 "expected": ["foo"] }, 36 37 { "comment": "toplevel array, no change", 38 "doc": ["foo"], 39 "patch": [], 40 "expected": ["foo"] }, 41 42 { "comment": "toplevel object, numeric string", 43 "doc": {}, 44 "patch": [{"op": "add", "path": "/foo", "value": "1"}], 45 "expected": {"foo":"1"} }, 46 47 { "comment": "toplevel object, integer", 48 "doc": {}, 49 "patch": [{"op": "add", "path": "/foo", "value": 1}], 50 "expected": {"foo":1} }, 51 52 { "comment": "Toplevel scalar values OK?", 53 "doc": "foo", 54 "patch": [{"op": "replace", "path": "", "value": "bar"}], 55 "expected": "bar", 56 "disabled": true }, 57 58 { "comment": "replace object document with array document?", 59 "doc": {}, 60 "patch": [{"op": "add", "path": "", "value": []}], 61 "expected": [] }, 62 63 { "comment": "replace array document with object document?", 64 "doc": [], 65 "patch": [{"op": "add", "path": "", "value": {}}], 66 "expected": {} }, 67 68 { "comment": "append to root array document?", 69 "doc": [], 70 "patch": [{"op": "add", "path": "/-", "value": "hi"}], 71 "expected": ["hi"] }, 72 73 { "comment": "Add, / target", 74 "doc": {}, 75 "patch": [ {"op": "add", "path": "/", "value":1 } ], 76 "expected": {"":1} }, 77 78 { "comment": "Add, /foo/ deep target (trailing slash)", 79 "doc": {"foo": {}}, 80 "patch": [ {"op": "add", "path": "/foo/", "value":1 } ], 81 "expected": {"foo":{"": 1}} }, 82 83 { "comment": "Add composite value at top level", 84 "doc": {"foo": 1}, 85 "patch": [{"op": "add", "path": "/bar", "value": [1, 2]}], 86 "expected": {"foo": 1, "bar": [1, 2]} }, 87 88 { "comment": "Add into composite value", 89 "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 90 "patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}], 91 "expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} }, 92 93 { "doc": {"bar": [1, 2]}, 94 "patch": [{"op": "add", "path": "/bar/8", "value": "5"}], 95 "error": "Out of bounds (upper)" }, 96 97 { "doc": {"bar": [1, 2]}, 98 "patch": [{"op": "add", "path": "/bar/-1", "value": "5"}], 99 "error": "Out of bounds (lower)" }, 100 101 { "doc": {"foo": 1}, 102 "patch": [{"op": "add", "path": "/bar", "value": true}], 103 "expected": {"foo": 1, "bar": true} }, 104 105 { "doc": {"foo": 1}, 106 "patch": [{"op": "add", "path": "/bar", "value": false}], 107 "expected": {"foo": 1, "bar": false} }, 108 109 { "doc": {"foo": 1}, 110 "patch": [{"op": "add", "path": "/bar", "value": null}], 111 "expected": {"foo": 1, "bar": null} }, 112 113 { "comment": "0 can be an array index or object element name", 114 "doc": {"foo": 1}, 115 "patch": [{"op": "add", "path": "/0", "value": "bar"}], 116 "expected": {"foo": 1, "0": "bar" } }, 117 118 { "doc": ["foo"], 119 "patch": [{"op": "add", "path": "/1", "value": "bar"}], 120 "expected": ["foo", "bar"] }, 121 122 { "doc": ["foo", "sil"], 123 "patch": [{"op": "add", "path": "/1", "value": "bar"}], 124 "expected": ["foo", "bar", "sil"] }, 125 126 { "doc": ["foo", "sil"], 127 "patch": [{"op": "add", "path": "/0", "value": "bar"}], 128 "expected": ["bar", "foo", "sil"] }, 129 130 { "comment": "push item to array via last index + 1", 131 "doc": ["foo", "sil"], 132 "patch": [{"op":"add", "path": "/2", "value": "bar"}], 133 "expected": ["foo", "sil", "bar"] }, 134 135 { "comment": "add item to array at index > length should fail", 136 "doc": ["foo", "sil"], 137 "patch": [{"op":"add", "path": "/3", "value": "bar"}], 138 "error": "index is greater than number of items in array" }, 139 140 { "comment": "test against implementation-specific numeric parsing", 141 "doc": {"1e0": "foo"}, 142 "patch": [{"op": "test", "path": "/1e0", "value": "foo"}], 143 "expected": {"1e0": "foo"} }, 144 145 { "comment": "test with bad number should fail", 146 "doc": ["foo", "bar"], 147 "patch": [{"op": "test", "path": "/1e0", "value": "bar"}], 148 "error": "test op shouldn't get array element 1" }, 149 150 { "doc": ["foo", "sil"], 151 "patch": [{"op": "add", "path": "/bar", "value": 42}], 152 "error": "Object operation on array target" }, 153 154 { "doc": ["foo", "sil"], 155 "patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}], 156 "expected": ["foo", ["bar", "baz"], "sil"], 157 "comment": "value in array add not flattened" }, 158 159 { "doc": {"foo": 1, "bar": [1, 2, 3, 4]}, 160 "patch": [{"op": "remove", "path": "/bar"}], 161 "expected": {"foo": 1} }, 162 163 { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 164 "patch": [{"op": "remove", "path": "/baz/0/qux"}], 165 "expected": {"foo": 1, "baz": [{}]} }, 166 167 { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 168 "patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}], 169 "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} }, 170 171 { "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]}, 172 "patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}], 173 "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} }, 174 175 { "doc": ["foo"], 176 "patch": [{"op": "replace", "path": "/0", "value": "bar"}], 177 "expected": ["bar"] }, 178 179 { "doc": [""], 180 "patch": [{"op": "replace", "path": "/0", "value": 0}], 181 "expected": [0] }, 182 183 { "doc": [""], 184 "patch": [{"op": "replace", "path": "/0", "value": true}], 185 "expected": [true] }, 186 187 { "doc": [""], 188 "patch": [{"op": "replace", "path": "/0", "value": false}], 189 "expected": [false] }, 190 191 { "doc": [""], 192 "patch": [{"op": "replace", "path": "/0", "value": null}], 193 "expected": [null] }, 194 195 { "doc": ["foo", "sil"], 196 "patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}], 197 "expected": ["foo", ["bar", "baz"]], 198 "comment": "value in array replace not flattened" }, 199 200 { "comment": "replace whole document", 201 "doc": {"foo": "bar"}, 202 "patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}], 203 "expected": {"baz": "qux"} }, 204 205 { "comment": "test replace with missing parent key should fail", 206 "doc": {"bar": "baz"}, 207 "patch": [{"op": "replace", "path": "/foo/bar", "value": false}], 208 "error": "replace op should fail with missing parent key" }, 209 210 { "comment": "spurious patch properties", 211 "doc": {"foo": 1}, 212 "patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}], 213 "expected": {"foo": 1} }, 214 215 { "doc": {"foo": null}, 216 "patch": [{"op": "test", "path": "/foo", "value": null}], 217 "comment": "null value should be valid obj property" }, 218 219 { "doc": {"foo": null}, 220 "patch": [{"op": "replace", "path": "/foo", "value": "truthy"}], 221 "expected": {"foo": "truthy"}, 222 "comment": "null value should be valid obj property to be replaced with something truthy" }, 223 224 { "doc": {"foo": null}, 225 "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], 226 "expected": {"bar": null}, 227 "comment": "null value should be valid obj property to be moved" }, 228 229 { "doc": {"foo": null}, 230 "patch": [{"op": "copy", "from": "/foo", "path": "/bar"}], 231 "expected": {"foo": null, "bar": null}, 232 "comment": "null value should be valid obj property to be copied" }, 233 234 { "doc": {"foo": null}, 235 "patch": [{"op": "remove", "path": "/foo"}], 236 "expected": {}, 237 "comment": "null value should be valid obj property to be removed" }, 238 239 { "doc": {"foo": "bar"}, 240 "patch": [{"op": "replace", "path": "/foo", "value": null}], 241 "expected": {"foo": null}, 242 "comment": "null value should still be valid obj property replace other value" }, 243 244 { "doc": {"foo": {"foo": 1, "bar": 2}}, 245 "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}], 246 "comment": "test should pass despite rearrangement" }, 247 248 { "doc": {"foo": [{"foo": 1, "bar": 2}]}, 249 "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}], 250 "comment": "test should pass despite (nested) rearrangement" }, 251 252 { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, 253 "patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}], 254 "comment": "test should pass - no error" }, 255 256 { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, 257 "patch": [{"op": "test", "path": "/foo", "value": [1, 2]}], 258 "error": "test op should fail" }, 259 260 { "comment": "Whole document", 261 "doc": { "foo": 1 }, 262 "patch": [{"op": "test", "path": "", "value": {"foo": 1}}], 263 "disabled": true }, 264 265 { "comment": "Empty-string element", 266 "doc": { "": 1 }, 267 "patch": [{"op": "test", "path": "/", "value": 1}] }, 268 269 { "doc": { 270 "foo": ["bar", "baz"], 271 "": 0, 272 "a/b": 1, 273 "c%d": 2, 274 "e^f": 3, 275 "g|h": 4, 276 "i\\j": 5, 277 "k\"l": 6, 278 " ": 7, 279 "m~n": 8 280 }, 281 "patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]}, 282 {"op": "test", "path": "/foo/0", "value": "bar"}, 283 {"op": "test", "path": "/", "value": 0}, 284 {"op": "test", "path": "/a~1b", "value": 1}, 285 {"op": "test", "path": "/c%d", "value": 2}, 286 {"op": "test", "path": "/e^f", "value": 3}, 287 {"op": "test", "path": "/g|h", "value": 4}, 288 {"op": "test", "path": "/i\\j", "value": 5}, 289 {"op": "test", "path": "/k\"l", "value": 6}, 290 {"op": "test", "path": "/ ", "value": 7}, 291 {"op": "test", "path": "/m~0n", "value": 8}] }, 292 293 { "comment": "Move to same location has no effect", 294 "doc": {"foo": 1}, 295 "patch": [{"op": "move", "from": "/foo", "path": "/foo"}], 296 "expected": {"foo": 1} }, 297 298 { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 299 "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], 300 "expected": {"baz": [{"qux": "hello"}], "bar": 1} }, 301 302 { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, 303 "patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}], 304 "expected": {"baz": [{}, "hello"], "bar": 1} }, 305 306 { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, 307 "patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}], 308 "expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} }, 309 310 { "comment": "replacing the root of the document is possible with add", 311 "doc": {"foo": "bar"}, 312 "patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}], 313 "expected": {"baz":"qux"}}, 314 315 { "comment": "Adding to \"/-\" adds to the end of the array", 316 "doc": [ 1, 2 ], 317 "patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ], 318 "expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]}, 319 320 { "comment": "Adding to \"/-\" adds to the end of the array, even n levels down", 321 "doc": [ 1, 2, [ 3, [ 4, 5 ] ] ], 322 "patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ], 323 "expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]}, 324 325 { "comment": "test remove with bad number should fail", 326 "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 327 "patch": [{"op": "remove", "path": "/baz/1e0/qux"}], 328 "error": "remove op shouldn't remove from array with bad number" }, 329 330 { "comment": "test remove on array", 331 "doc": [1, 2, 3, 4], 332 "patch": [{"op": "remove", "path": "/0"}], 333 "expected": [2, 3, 4] }, 334 335 { "comment": "test repeated removes", 336 "doc": [1, 2, 3, 4], 337 "patch": [{ "op": "remove", "path": "/1" }, 338 { "op": "remove", "path": "/2" }], 339 "expected": [1, 3] }, 340 341 { "comment": "test remove with bad index should fail", 342 "doc": [1, 2, 3, 4], 343 "patch": [{"op": "remove", "path": "/1e0"}], 344 "error": "remove op shouldn't remove from array with bad number" }, 345 346 { "comment": "test replace with bad number should fail", 347 "doc": [""], 348 "patch": [{"op": "replace", "path": "/1e0", "value": false}], 349 "error": "replace op shouldn't replace in array with bad number" }, 350 351 { "comment": "test copy with bad number should fail", 352 "doc": {"baz": [1,2,3], "bar": 1}, 353 "patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}], 354 "error": "copy op shouldn't work with bad number" }, 355 356 { "comment": "test move with bad number should fail", 357 "doc": {"foo": 1, "baz": [1,2,3,4]}, 358 "patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}], 359 "error": "move op shouldn't work with bad number" }, 360 361 { "comment": "test add with bad number should fail", 362 "doc": ["foo", "sil"], 363 "patch": [{"op": "add", "path": "/1e0", "value": "bar"}], 364 "error": "add op shouldn't add to array with bad number" }, 365 366 { "comment": "missing 'value' parameter to add", 367 "doc": [ 1 ], 368 "patch": [ { "op": "add", "path": "/-" } ], 369 "error": "missing 'value' parameter" }, 370 371 { "comment": "missing 'value' parameter to replace", 372 "doc": [ 1 ], 373 "patch": [ { "op": "replace", "path": "/0" } ], 374 "error": "missing 'value' parameter" }, 375 376 { "comment": "missing 'value' parameter to test", 377 "doc": [ null ], 378 "patch": [ { "op": "test", "path": "/0" } ], 379 "error": "missing 'value' parameter" }, 380 381 { "comment": "missing value parameter to test - where undef is falsy", 382 "doc": [ false ], 383 "patch": [ { "op": "test", "path": "/0" } ], 384 "error": "missing 'value' parameter" }, 385 386 { "comment": "missing from parameter to copy", 387 "doc": [ 1 ], 388 "patch": [ { "op": "copy", "path": "/-" } ], 389 "error": "missing 'from' parameter" }, 390 391 { "comment": "missing from parameter to move", 392 "doc": { "foo": 1 }, 393 "patch": [ { "op": "move", "path": "" } ], 394 "error": "missing 'from' parameter" }, 395 396 { "comment": "duplicate ops", 397 "doc": { "foo": "bar" }, 398 "patch": [ { "op": "add", "path": "/baz", "value": "qux", 399 "op": "move", "from":"/foo" } ], 400 "error": "patch has two 'op' members", 401 "disabled": true }, 402 403 { "comment": "unrecognized op should fail", 404 "doc": {"foo": 1}, 405 "patch": [{"op": "spam", "path": "/foo", "value": 1}], 406 "error": "Unrecognized op 'spam'" }, 407 408 { "comment": "test with bad array number that has leading zeros", 409 "doc": ["foo", "bar"], 410 "patch": [{"op": "test", "path": "/00", "value": "foo"}], 411 "error": "test op should reject the array value, it has leading zeros" }, 412 413 { "comment": "test with bad array number that has leading zeros", 414 "doc": ["foo", "bar"], 415 "patch": [{"op": "test", "path": "/01", "value": "bar"}], 416 "error": "test op should reject the array value, it has leading zeros" }, 417 418 { "comment": "Removing nonexistent field", 419 "doc": {"foo" : "bar"}, 420 "patch": [{"op": "remove", "path": "/baz"}], 421 "error": "removing a nonexistent field should fail" }, 422 423 { "comment": "Removing nonexistent index", 424 "doc": ["foo", "bar"], 425 "patch": [{"op": "remove", "path": "/2"}], 426 "error": "removing a nonexistent index should fail" }, 427 428 { "comment": "Patch with different capitalisation than doc", 429 "doc": {"foo":"bar"}, 430 "patch": [{"op": "add", "path": "/FOO", "value": "BAR"}], 431 "expected": {"foo": "bar", "FOO": "BAR"} 432 } 433 434] 435