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 "expected": {"foo": null}, 218 "comment": "null value should be valid obj property" }, 219 220 { "doc": {"foo": null}, 221 "patch": [{"op": "replace", "path": "/foo", "value": "truthy"}], 222 "expected": {"foo": "truthy"}, 223 "comment": "null value should be valid obj property to be replaced with something truthy" }, 224 225 { "doc": {"foo": null}, 226 "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], 227 "expected": {"bar": null}, 228 "comment": "null value should be valid obj property to be moved" }, 229 230 { "doc": {"foo": null}, 231 "patch": [{"op": "copy", "from": "/foo", "path": "/bar"}], 232 "expected": {"foo": null, "bar": null}, 233 "comment": "null value should be valid obj property to be copied" }, 234 235 { "doc": {"foo": null}, 236 "patch": [{"op": "remove", "path": "/foo"}], 237 "expected": {}, 238 "comment": "null value should be valid obj property to be removed" }, 239 240 { "doc": {"foo": "bar"}, 241 "patch": [{"op": "replace", "path": "/foo", "value": null}], 242 "expected": {"foo": null}, 243 "comment": "null value should still be valid obj property replace other value" }, 244 245 { "doc": {"foo": {"foo": 1, "bar": 2}}, 246 "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}], 247 "expected": {"foo": {"foo": 1, "bar": 2}}, 248 "comment": "test should pass despite rearrangement" }, 249 250 { "doc": {"foo": [{"foo": 1, "bar": 2}]}, 251 "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}], 252 "expected": {"foo": [{"foo": 1, "bar": 2}]}, 253 "comment": "test should pass despite (nested) rearrangement" }, 254 255 { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, 256 "patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}], 257 "expected": {"foo": {"bar": [1, 2, 5, 4]}}, 258 "comment": "test should pass - no error" }, 259 260 { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, 261 "patch": [{"op": "test", "path": "/foo", "value": [1, 2]}], 262 "error": "test op should fail" }, 263 264 { "comment": "Whole document", 265 "doc": { "foo": 1 }, 266 "patch": [{"op": "test", "path": "", "value": {"foo": 1}}], 267 "disabled": true }, 268 269 { "comment": "Empty-string element", 270 "doc": { "": 1 }, 271 "patch": [{"op": "test", "path": "/", "value": 1}], 272 "expected": { "": 1 } }, 273 274 { "doc": { 275 "foo": ["bar", "baz"], 276 "": 0, 277 "a/b": 1, 278 "c%d": 2, 279 "e^f": 3, 280 "g|h": 4, 281 "i\\j": 5, 282 "k\"l": 6, 283 " ": 7, 284 "m~n": 8 285 }, 286 "patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]}, 287 {"op": "test", "path": "/foo/0", "value": "bar"}, 288 {"op": "test", "path": "/", "value": 0}, 289 {"op": "test", "path": "/a~1b", "value": 1}, 290 {"op": "test", "path": "/c%d", "value": 2}, 291 {"op": "test", "path": "/e^f", "value": 3}, 292 {"op": "test", "path": "/g|h", "value": 4}, 293 {"op": "test", "path": "/i\\j", "value": 5}, 294 {"op": "test", "path": "/k\"l", "value": 6}, 295 {"op": "test", "path": "/ ", "value": 7}, 296 {"op": "test", "path": "/m~0n", "value": 8}], 297 "expected": { 298 "": 0, 299 " ": 7, 300 "a/b": 1, 301 "c%d": 2, 302 "e^f": 3, 303 "foo": [ 304 "bar", 305 "baz" 306 ], 307 "g|h": 4, 308 "i\\j": 5, 309 "k\"l": 6, 310 "m~n": 8 311 } 312 }, 313 { "comment": "Move to same location has no effect", 314 "doc": {"foo": 1}, 315 "patch": [{"op": "move", "from": "/foo", "path": "/foo"}], 316 "expected": {"foo": 1} }, 317 318 { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 319 "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], 320 "expected": {"baz": [{"qux": "hello"}], "bar": 1} }, 321 322 { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, 323 "patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}], 324 "expected": {"baz": [{}, "hello"], "bar": 1} }, 325 326 { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, 327 "patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}], 328 "expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} }, 329 330 { "comment": "replacing the root of the document is possible with add", 331 "doc": {"foo": "bar"}, 332 "patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}], 333 "expected": {"baz":"qux"}}, 334 335 { "comment": "Adding to \"/-\" adds to the end of the array", 336 "doc": [ 1, 2 ], 337 "patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ], 338 "expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]}, 339 340 { "comment": "Adding to \"/-\" adds to the end of the array, even n levels down", 341 "doc": [ 1, 2, [ 3, [ 4, 5 ] ] ], 342 "patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ], 343 "expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]}, 344 345 { "comment": "test remove with bad number should fail", 346 "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, 347 "patch": [{"op": "remove", "path": "/baz/1e0/qux"}], 348 "error": "remove op shouldn't remove from array with bad number" }, 349 350 { "comment": "test remove on array", 351 "doc": [1, 2, 3, 4], 352 "patch": [{"op": "remove", "path": "/0"}], 353 "expected": [2, 3, 4] }, 354 355 { "comment": "test repeated removes", 356 "doc": [1, 2, 3, 4], 357 "patch": [{ "op": "remove", "path": "/1" }, 358 { "op": "remove", "path": "/2" }], 359 "expected": [1, 3] }, 360 361 { "comment": "test remove with bad index should fail", 362 "doc": [1, 2, 3, 4], 363 "patch": [{"op": "remove", "path": "/1e0"}], 364 "error": "remove op shouldn't remove from array with bad number" }, 365 366 { "comment": "test replace with bad number should fail", 367 "doc": [""], 368 "patch": [{"op": "replace", "path": "/1e0", "value": false}], 369 "error": "replace op shouldn't replace in array with bad number" }, 370 371 { "comment": "test copy with bad number should fail", 372 "doc": {"baz": [1,2,3], "bar": 1}, 373 "patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}], 374 "error": "copy op shouldn't work with bad number" }, 375 376 { "comment": "test move with bad number should fail", 377 "doc": {"foo": 1, "baz": [1,2,3,4]}, 378 "patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}], 379 "error": "move op shouldn't work with bad number" }, 380 381 { "comment": "test add with bad number should fail", 382 "doc": ["foo", "sil"], 383 "patch": [{"op": "add", "path": "/1e0", "value": "bar"}], 384 "error": "add op shouldn't add to array with bad number" }, 385 386 { "comment": "missing 'value' parameter to add", 387 "doc": [ 1 ], 388 "patch": [ { "op": "add", "path": "/-" } ], 389 "error": "missing 'value' parameter" }, 390 391 { "comment": "missing 'value' parameter to replace", 392 "doc": [ 1 ], 393 "patch": [ { "op": "replace", "path": "/0" } ], 394 "error": "missing 'value' parameter" }, 395 396 { "comment": "missing 'value' parameter to test", 397 "doc": [ null ], 398 "patch": [ { "op": "test", "path": "/0" } ], 399 "error": "missing 'value' parameter" }, 400 401 { "comment": "missing value parameter to test - where undef is falsy", 402 "doc": [ false ], 403 "patch": [ { "op": "test", "path": "/0" } ], 404 "error": "missing 'value' parameter" }, 405 406 { "comment": "missing from parameter to copy", 407 "doc": [ 1 ], 408 "patch": [ { "op": "copy", "path": "/-" } ], 409 "error": "missing 'from' parameter" }, 410 411 { "comment": "missing from location to copy", 412 "doc": { "foo": 1 }, 413 "patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ], 414 "error": "missing 'from' location" }, 415 416 { "comment": "missing from parameter to move", 417 "doc": { "foo": 1 }, 418 "patch": [ { "op": "move", "path": "" } ], 419 "error": "missing 'from' parameter" }, 420 421 { "comment": "missing from location to move", 422 "doc": { "foo": 1 }, 423 "patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ], 424 "error": "missing 'from' location" }, 425 426 { "comment": "duplicate ops", 427 "doc": { "foo": "bar" }, 428 "patch": [ { "op": "add", "path": "/baz", "value": "qux", 429 "op": "move", "from":"/foo" } ], 430 "error": "patch has two 'op' members", 431 "disabled": true }, 432 433 { "comment": "unrecognized op should fail", 434 "doc": {"foo": 1}, 435 "patch": [{"op": "spam", "path": "/foo", "value": 1}], 436 "error": "Unrecognized op 'spam'" }, 437 438 { "comment": "test with bad array number that has leading zeros", 439 "doc": ["foo", "bar"], 440 "patch": [{"op": "test", "path": "/00", "value": "foo"}], 441 "error": "test op should reject the array value, it has leading zeros" }, 442 443 { "comment": "test with bad array number that has leading zeros", 444 "doc": ["foo", "bar"], 445 "patch": [{"op": "test", "path": "/01", "value": "bar"}], 446 "error": "test op should reject the array value, it has leading zeros" }, 447 448 { "comment": "Removing nonexistent field", 449 "doc": {"foo" : "bar"}, 450 "patch": [{"op": "remove", "path": "/baz"}], 451 "error": "removing a nonexistent field should fail" }, 452 453 { "comment": "Removing nonexistent index", 454 "doc": ["foo", "bar"], 455 "patch": [{"op": "remove", "path": "/2"}], 456 "error": "removing a nonexistent index should fail" }, 457 458 { "comment": "Patch with different capitalisation than doc", 459 "doc": {"foo":"bar"}, 460 "patch": [{"op": "add", "path": "/FOO", "value": "BAR"}], 461 "expected": {"foo": "bar", "FOO": "BAR"} 462 } 463 464] 465