1 package jsonpatch
2
3 import (
4 "fmt"
5 "strings"
6 "testing"
7 )
8
9 func mergePatch(doc, patch string) string {
10 out, err := MergePatch([]byte(doc), []byte(patch))
11
12 if err != nil {
13 panic(err)
14 }
15
16 return string(out)
17 }
18
19 func TestMergePatchReplaceKey(t *testing.T) {
20 doc := `{ "title": "hello" }`
21 pat := `{ "title": "goodbye" }`
22
23 res := mergePatch(doc, pat)
24
25 if !compareJSON(pat, res) {
26 t.Fatalf("Key was not replaced")
27 }
28 }
29
30 func TestMergePatchIgnoresOtherValues(t *testing.T) {
31 doc := `{ "title": "hello", "age": 18 }`
32 pat := `{ "title": "goodbye" }`
33
34 res := mergePatch(doc, pat)
35
36 exp := `{ "title": "goodbye", "age": 18 }`
37
38 if !compareJSON(exp, res) {
39 t.Fatalf("Key was not replaced")
40 }
41 }
42
43 func TestMergePatchNilDoc(t *testing.T) {
44 doc := `{ "title": null }`
45 pat := `{ "title": {"foo": "bar"} }`
46
47 res := mergePatch(doc, pat)
48
49 exp := `{ "title": {"foo": "bar"} }`
50
51 if !compareJSON(exp, res) {
52 t.Fatalf("Key was not replaced")
53 }
54 }
55
56 type arrayCases struct {
57 original, patch, res string
58 }
59
60 func TestMergePatchNilArray(t *testing.T) {
61
62 cases := []arrayCases {
63 {`{"a": [ {"b":"c"} ] }`, `{"a": [1]}`, `{"a": [1]}`},
64 {`{"a": [ {"b":"c"} ] }`, `{"a": [null, 1]}`, `{"a": [null, 1]}`},
65 {`["a",null]`, `[null]`, `[null]`},
66 {`["a"]`, `[null]`, `[null]`},
67 {`["a", "b"]`, `["a", null]`, `["a", null]`},
68 {`{"a":["b"]}`, `{"a": ["b", null]}`, `{"a":["b", null]}`},
69 {`{"a":[]}`, `{"a": ["b", null, null, "a"]}`, `{"a":["b", null, null, "a"]}`},
70 }
71
72 for _, c := range cases {
73 act := mergePatch(c.original, c.patch)
74
75 if !compareJSON(c.res, act) {
76 t.Errorf("null values not preserved in array")
77 }
78 }
79 }
80
81 func TestMergePatchRecursesIntoObjects(t *testing.T) {
82 doc := `{ "person": { "title": "hello", "age": 18 } }`
83 pat := `{ "person": { "title": "goodbye" } }`
84
85 res := mergePatch(doc, pat)
86
87 exp := `{ "person": { "title": "goodbye", "age": 18 } }`
88
89 if !compareJSON(exp, res) {
90 t.Fatalf("Key was not replaced")
91 }
92 }
93
94 type nonObjectCases struct {
95 doc, pat, res string
96 }
97
98 func TestMergePatchReplacesNonObjectsWholesale(t *testing.T) {
99 a1 := `[1]`
100 a2 := `[2]`
101 o1 := `{ "a": 1 }`
102 o2 := `{ "a": 2 }`
103 o3 := `{ "a": 1, "b": 1 }`
104 o4 := `{ "a": 2, "b": 1 }`
105
106 cases := []nonObjectCases{
107 {a1, a2, a2},
108 {o1, a2, a2},
109 {a1, o1, o1},
110 {o3, o2, o4},
111 }
112
113 for _, c := range cases {
114 act := mergePatch(c.doc, c.pat)
115
116 if !compareJSON(c.res, act) {
117 t.Errorf("whole object replacement failed")
118 }
119 }
120 }
121
122 func TestMergePatchReturnsErrorOnBadJSON(t *testing.T) {
123 _, err := MergePatch([]byte(`[[[[`), []byte(`1`))
124
125 if err == nil {
126 t.Errorf("Did not return an error for bad json: %s", err)
127 }
128
129 _, err = MergePatch([]byte(`1`), []byte(`[[[[`))
130
131 if err == nil {
132 t.Errorf("Did not return an error for bad json: %s", err)
133 }
134 }
135
136 func TestMergePatchReturnsEmptyArrayOnEmptyArray(t *testing.T) {
137 doc := `{ "array": ["one", "two"] }`
138 pat := `{ "array": [] }`
139
140 exp := `{ "array": [] }`
141
142 res, err := MergePatch([]byte(doc), []byte(pat))
143
144 if err != nil {
145 t.Errorf("Unexpected error: %s, %s", err, string(res))
146 }
147
148 if !compareJSON(exp, string(res)) {
149 t.Fatalf("Emtpy array did not return not return as empty array")
150 }
151 }
152
153 var rfcTests = []struct {
154 target string
155 patch string
156 expected string
157 }{
158
159 {target: `{"a":"b"}`, patch: `{"a":"c"}`, expected: `{"a":"c"}`},
160 {target: `{"a":"b"}`, patch: `{"b":"c"}`, expected: `{"a":"b","b":"c"}`},
161 {target: `{"a":"b"}`, patch: `{"a":null}`, expected: `{}`},
162 {target: `{"a":"b","b":"c"}`, patch: `{"a":null}`, expected: `{"b":"c"}`},
163 {target: `{"a":["b"]}`, patch: `{"a":"c"}`, expected: `{"a":"c"}`},
164 {target: `{"a":"c"}`, patch: `{"a":["b"]}`, expected: `{"a":["b"]}`},
165 {target: `{"a":{"b": "c"}}`, patch: `{"a": {"b": "d","c": null}}`, expected: `{"a":{"b":"d"}}`},
166 {target: `{"a":[{"b":"c"}]}`, patch: `{"a":[1]}`, expected: `{"a":[1]}`},
167 {target: `["a","b"]`, patch: `["c","d"]`, expected: `["c","d"]`},
168 {target: `{"a":"b"}`, patch: `["c"]`, expected: `["c"]`},
169
170
171 {target: `{"e":null}`, patch: `{"a":1}`, expected: `{"a":1,"e":null}`},
172 {target: `[1,2]`, patch: `{"a":"b","c":null}`, expected: `{"a":"b"}`},
173 {target: `{}`, patch: `{"a":{"bb":{"ccc":null}}}`, expected: `{"a":{"bb":{}}}`},
174 }
175
176 func TestMergePatchRFCCases(t *testing.T) {
177 for i, c := range rfcTests {
178 out := mergePatch(c.target, c.patch)
179
180 if !compareJSON(out, c.expected) {
181 t.Errorf("case[%d], patch '%s' did not apply properly to '%s'. expected:\n'%s'\ngot:\n'%s'", i, c.patch, c.target, c.expected, out)
182 }
183 }
184 }
185
186 var rfcFailTests = `
187 {"a":"foo"} | null
188 {"a":"foo"} | "bar"
189 `
190
191 func TestMergePatchFailRFCCases(t *testing.T) {
192 tests := strings.Split(rfcFailTests, "\n")
193
194 for _, c := range tests {
195 if strings.TrimSpace(c) == "" {
196 continue
197 }
198
199 parts := strings.SplitN(c, "|", 2)
200
201 doc := strings.TrimSpace(parts[0])
202 pat := strings.TrimSpace(parts[1])
203
204 out, err := MergePatch([]byte(doc), []byte(pat))
205
206 if err != ErrBadJSONPatch {
207 t.Errorf("error not returned properly: %s, %s", err, string(out))
208 }
209 }
210
211 }
212
213 func TestResembleJSONArray(t *testing.T) {
214 testCases := []struct {
215 input []byte
216 expected bool
217 }{
218
219 {input: []byte(``), expected: false},
220 {input: []byte(`not an array`), expected: false},
221 {input: []byte(`{"foo": "bar"}`), expected: false},
222 {input: []byte(`{"fizz": ["buzz"]}`), expected: false},
223 {input: []byte(`[bad suffix`), expected: false},
224 {input: []byte(`bad prefix]`), expected: false},
225 {input: []byte(`][`), expected: false},
226
227
228 {input: []byte(`[]`), expected: true},
229 {input: []byte(`["foo", "bar"]`), expected: true},
230 {input: []byte(`[["foo", "bar"]]`), expected: true},
231 {input: []byte(`[not valid syntax]`), expected: true},
232
233
234 {input: []byte(` []`), expected: true},
235 {input: []byte(`[] `), expected: true},
236 {input: []byte(` [] `), expected: true},
237 {input: []byte(` [ ] `), expected: true},
238 {input: []byte("\t[]"), expected: true},
239 {input: []byte("[]\n"), expected: true},
240 {input: []byte("\n\t\r[]"), expected: true},
241 }
242
243 for _, test := range testCases {
244 result := resemblesJSONArray(test.input)
245 if result != test.expected {
246 t.Errorf(
247 `expected "%t" but received "%t" for case: "%s"`,
248 test.expected,
249 result,
250 string(test.input),
251 )
252 }
253 }
254 }
255
256 func TestCreateMergePatchReplaceKey(t *testing.T) {
257 doc := `{ "title": "hello", "nested": {"one": 1, "two": 2} }`
258 pat := `{ "title": "goodbye", "nested": {"one": 2, "two": 2} }`
259
260 exp := `{ "title": "goodbye", "nested": {"one": 2} }`
261
262 res, err := CreateMergePatch([]byte(doc), []byte(pat))
263
264 if err != nil {
265 t.Errorf("Unexpected error: %s, %s", err, string(res))
266 }
267
268 if !compareJSON(exp, string(res)) {
269 t.Fatalf("Key was not replaced")
270 }
271 }
272
273 func TestCreateMergePatchGetArray(t *testing.T) {
274 doc := `{ "title": "hello", "array": ["one", "two"], "notmatch": [1, 2, 3] }`
275 pat := `{ "title": "hello", "array": ["one", "two", "three"], "notmatch": [1, 2, 3] }`
276
277 exp := `{ "array": ["one", "two", "three"] }`
278
279 res, err := CreateMergePatch([]byte(doc), []byte(pat))
280
281 if err != nil {
282 t.Errorf("Unexpected error: %s, %s", err, string(res))
283 }
284
285 if !compareJSON(exp, string(res)) {
286 t.Fatalf("Array was not added")
287 }
288 }
289
290 func TestCreateMergePatchGetObjArray(t *testing.T) {
291 doc := `{ "title": "hello", "array": [{"banana": true}, {"evil": false}], "notmatch": [{"one":1}, {"two":2}, {"three":3}] }`
292 pat := `{ "title": "hello", "array": [{"banana": false}, {"evil": true}], "notmatch": [{"one":1}, {"two":2}, {"three":3}] }`
293
294 exp := `{ "array": [{"banana": false}, {"evil": true}] }`
295
296 res, err := CreateMergePatch([]byte(doc), []byte(pat))
297
298 if err != nil {
299 t.Errorf("Unexpected error: %s, %s", err, string(res))
300 }
301
302 if !compareJSON(exp, string(res)) {
303 t.Fatalf("Object array was not added")
304 }
305 }
306
307 func TestCreateMergePatchDeleteKey(t *testing.T) {
308 doc := `{ "title": "hello", "nested": {"one": 1, "two": 2} }`
309 pat := `{ "title": "hello", "nested": {"one": 1} }`
310
311 exp := `{"nested":{"two":null}}`
312
313 res, err := CreateMergePatch([]byte(doc), []byte(pat))
314
315 if err != nil {
316 t.Errorf("Unexpected error: %s, %s", err, string(res))
317 }
318
319
320 if exp != string(res) {
321 t.Fatalf("Key was not removed")
322 }
323 }
324
325 func TestCreateMergePatchEmptyArray(t *testing.T) {
326 doc := `{ "array": null }`
327 pat := `{ "array": [] }`
328
329 exp := `{"array":[]}`
330
331 res, err := CreateMergePatch([]byte(doc), []byte(pat))
332
333 if err != nil {
334 t.Errorf("Unexpected error: %s, %s", err, string(res))
335 }
336
337
338 if exp != string(res) {
339 t.Fatalf("Key was not removed")
340 }
341 }
342
343 func TestCreateMergePatchNil(t *testing.T) {
344 doc := `{ "title": "hello", "nested": {"one": 1, "two": [{"one":null}, {"two":null}, {"three":null}]} }`
345 pat := doc
346
347 exp := `{}`
348
349 res, err := CreateMergePatch([]byte(doc), []byte(pat))
350
351 if err != nil {
352 t.Errorf("Unexpected error: %s, %s", err, string(res))
353 }
354
355 if !compareJSON(exp, string(res)) {
356 t.Fatalf("Object array was not added")
357 }
358 }
359
360 func TestCreateMergePatchObjArray(t *testing.T) {
361 doc := `{ "array": [ {"a": {"b": 2}}, {"a": {"b": 3}} ]}`
362 exp := `{}`
363
364 res, err := CreateMergePatch([]byte(doc), []byte(doc))
365
366 if err != nil {
367 t.Errorf("Unexpected error: %s, %s", err, string(res))
368 }
369
370
371 if exp != string(res) {
372 t.Fatalf("Array was not empty, was " + string(res))
373 }
374 }
375
376 func TestCreateMergePatchSameOuterArray(t *testing.T) {
377 doc := `[{"foo": "bar"}]`
378 pat := doc
379 exp := `[{}]`
380
381 res, err := CreateMergePatch([]byte(doc), []byte(pat))
382
383 if err != nil {
384 t.Errorf("Unexpected error: %s, %s", err, string(res))
385 }
386
387 if !compareJSON(exp, string(res)) {
388 t.Fatalf("Outer array was not unmodified")
389 }
390 }
391
392 func TestCreateMergePatchModifiedOuterArray(t *testing.T) {
393 doc := `[{"name": "John"}, {"name": "Will"}]`
394 pat := `[{"name": "Jane"}, {"name": "Will"}]`
395 exp := `[{"name": "Jane"}, {}]`
396
397 res, err := CreateMergePatch([]byte(doc), []byte(pat))
398
399 if err != nil {
400 t.Errorf("Unexpected error: %s, %s", err, string(res))
401 }
402
403 if !compareJSON(exp, string(res)) {
404 t.Fatalf("Expected %s but received %s", exp, res)
405 }
406 }
407
408 func TestCreateMergePatchMismatchedOuterArray(t *testing.T) {
409 doc := `[{"name": "John"}, {"name": "Will"}]`
410 pat := `[{"name": "Jane"}]`
411
412 _, err := CreateMergePatch([]byte(doc), []byte(pat))
413
414 if err == nil {
415 t.Errorf("Expected error due to array length differences but received none")
416 }
417 }
418
419 func TestCreateMergePatchMismatchedOuterTypes(t *testing.T) {
420 doc := `[{"name": "John"}]`
421 pat := `{"name": "Jane"}`
422
423 _, err := CreateMergePatch([]byte(doc), []byte(pat))
424
425 if err == nil {
426 t.Errorf("Expected error due to mismatched types but received none")
427 }
428 }
429
430 func TestCreateMergePatchNoDifferences(t *testing.T) {
431 doc := `{ "title": "hello", "nested": {"one": 1, "two": 2} }`
432 pat := doc
433
434 exp := `{}`
435
436 res, err := CreateMergePatch([]byte(doc), []byte(pat))
437
438 if err != nil {
439 t.Errorf("Unexpected error: %s, %s", err, string(res))
440 }
441
442 if !compareJSON(exp, string(res)) {
443 t.Fatalf("Key was not replaced")
444 }
445 }
446
447 func TestCreateMergePatchComplexMatch(t *testing.T) {
448 doc := `{"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4], "nested": {"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]} }`
449 empty := `{}`
450 res, err := CreateMergePatch([]byte(doc), []byte(doc))
451
452 if err != nil {
453 t.Errorf("Unexpected error: %s, %s", err, string(res))
454 }
455
456
457 if empty != string(res) {
458 t.Fatalf("Did not get empty result, was:%s", string(res))
459 }
460 }
461
462 func TestCreateMergePatchComplexAddAll(t *testing.T) {
463 doc := `{"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4], "nested": {"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]} }`
464 empty := `{}`
465 res, err := CreateMergePatch([]byte(empty), []byte(doc))
466
467 if err != nil {
468 t.Errorf("Unexpected error: %s, %s", err, string(res))
469 }
470
471 if !compareJSON(doc, string(res)) {
472 t.Fatalf("Did not get everything as, it was:\n%s", string(res))
473 }
474 }
475
476
477
478 func createNestedMap(m map[string]interface{}, depth int, objectCount *int) {
479 if depth == 0 {
480 return
481 }
482 for i := 0; i < 2; i++ {
483 nested := map[string]interface{}{}
484 *objectCount += 1
485 createNestedMap(nested, depth-1, objectCount)
486 m[fmt.Sprintf("key-%v", i)] = nested
487 }
488 }
489
490 func TestMatchesValue(t *testing.T) {
491 testcases := []struct {
492 name string
493 a interface{}
494 b interface{}
495 want bool
496 }{
497 {
498 name: "map empty",
499 a: map[string]interface{}{},
500 b: map[string]interface{}{},
501 want: true,
502 },
503 {
504 name: "map equal keys, equal non-nil value",
505 a: map[string]interface{}{"1": true},
506 b: map[string]interface{}{"1": true},
507 want: true,
508 },
509 {
510 name: "map equal keys, equal nil value",
511 a: map[string]interface{}{"1": nil},
512 b: map[string]interface{}{"1": nil},
513 want: true,
514 },
515
516 {
517 name: "map different value",
518 a: map[string]interface{}{"1": true},
519 b: map[string]interface{}{"1": false},
520 want: false,
521 },
522 {
523 name: "map different key, matching non-nil value",
524 a: map[string]interface{}{"1": true},
525 b: map[string]interface{}{"2": true},
526 want: false,
527 },
528 {
529 name: "map different key, matching nil value",
530 a: map[string]interface{}{"1": nil},
531 b: map[string]interface{}{"2": nil},
532 want: false,
533 },
534 {
535 name: "map different key, first nil value",
536 a: map[string]interface{}{"1": true},
537 b: map[string]interface{}{"2": nil},
538 want: false,
539 },
540 {
541 name: "map different key, second nil value",
542 a: map[string]interface{}{"1": nil},
543 b: map[string]interface{}{"2": true},
544 want: false,
545 },
546 }
547 for _, tc := range testcases {
548 t.Run(tc.name, func(t *testing.T) {
549 got := matchesValue(tc.a, tc.b)
550 if got != tc.want {
551 t.Fatalf("want %v, got %v", tc.want, got)
552 }
553 })
554 }
555 }
556
557 func benchmarkMatchesValueWithDeeplyNestedFields(depth int, b *testing.B) {
558 a := map[string]interface{}{}
559 objCount := 1
560 createNestedMap(a, depth, &objCount)
561 b.ResetTimer()
562 b.Run(fmt.Sprintf("objectCount=%v", objCount), func(b *testing.B) {
563 for i := 0; i < b.N; i++ {
564 if !matchesValue(a, a) {
565 b.Errorf("Should be equal")
566 }
567 }
568 })
569 }
570
571 func BenchmarkMatchesValue1(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(1, b) }
572 func BenchmarkMatchesValue2(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(2, b) }
573 func BenchmarkMatchesValue3(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(3, b) }
574 func BenchmarkMatchesValue4(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(4, b) }
575 func BenchmarkMatchesValue5(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(5, b) }
576 func BenchmarkMatchesValue6(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(6, b) }
577 func BenchmarkMatchesValue7(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(7, b) }
578 func BenchmarkMatchesValue8(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(8, b) }
579 func BenchmarkMatchesValue9(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(9, b) }
580 func BenchmarkMatchesValue10(b *testing.B) { benchmarkMatchesValueWithDeeplyNestedFields(10, b) }
581
582 func TestCreateMergePatchComplexRemoveAll(t *testing.T) {
583 doc := `{"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4], "nested": {"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]} }`
584 exp := `{"a":null,"f":null,"hello":null,"i":null,"n":null,"nested":null,"pi":null,"t":null}`
585 empty := `{}`
586 res, err := CreateMergePatch([]byte(doc), []byte(empty))
587
588 if err != nil {
589 t.Errorf("Unexpected error: %s, %s", err, string(res))
590 }
591
592 if exp != string(res) {
593 t.Fatalf("Did not get result, was:%s", string(res))
594 }
595
596
597
602 }
603
604 func TestCreateMergePatchObjectWithInnerArray(t *testing.T) {
605 stateString := `{
606 "OuterArray": [
607 {
608 "InnerArray": [
609 {
610 "StringAttr": "abc123"
611 }
612 ],
613 "StringAttr": "def456"
614 }
615 ]
616 }`
617
618 patch, err := CreateMergePatch([]byte(stateString), []byte(stateString))
619 if err != nil {
620 t.Fatal(err)
621 }
622
623 if string(patch) != "{}" {
624 t.Fatalf("Patch should have been {} but was: %v", string(patch))
625 }
626 }
627
628 func TestCreateMergePatchReplaceKeyNotEscape(t *testing.T) {
629 doc := `{ "title": "hello", "nested": {"title/escaped": 1, "two": 2} }`
630 pat := `{ "title": "goodbye", "nested": {"title/escaped": 2, "two": 2} }`
631
632 exp := `{ "title": "goodbye", "nested": {"title/escaped": 2} }`
633
634 res, err := CreateMergePatch([]byte(doc), []byte(pat))
635
636 if err != nil {
637 t.Errorf("Unexpected error: %s, %s", err, string(res))
638 }
639
640 if !compareJSON(exp, string(res)) {
641 t.Log(string(res))
642 t.Fatalf("Key was not replaced")
643 }
644 }
645
646 func TestMergePatchReplaceKeyNotEscaping(t *testing.T) {
647 doc := `{ "obj": { "title/escaped": "hello" } }`
648 pat := `{ "obj": { "title/escaped": "goodbye" } }`
649 exp := `{ "obj": { "title/escaped": "goodbye" } }`
650
651 res := mergePatch(doc, pat)
652
653 if !compareJSON(exp, res) {
654 t.Fatalf("Key was not replaced")
655 }
656 }
657
658 func TestMergeMergePatches(t *testing.T) {
659 cases := []struct {
660 demonstrates string
661 p1 string
662 p2 string
663 exp string
664 }{
665 {
666 demonstrates: "simple patches are merged normally",
667 p1: `{"add1": 1}`,
668 p2: `{"add2": 2}`,
669 exp: `{"add1": 1, "add2": 2}`,
670 },
671 {
672 demonstrates: "nulls are kept",
673 p1: `{"del1": null}`,
674 p2: `{"del2": null}`,
675 exp: `{"del1": null, "del2": null}`,
676 },
677 {
678 demonstrates: "nulls are kept in complex objects",
679 p1: `{}`,
680 p2: `{"request":{"object":{"complex_object_array":["value1","value2","value3"],"complex_object_map":{"key1":"value1","key2":"value2","key3":"value3"},"simple_object_bool":false,"simple_object_float":-5.5,"simple_object_int":5,"simple_object_null":null,"simple_object_string":"example"}}}`,
681 exp: `{"request":{"object":{"complex_object_array":["value1","value2","value3"],"complex_object_map":{"key1":"value1","key2":"value2","key3":"value3"},"simple_object_bool":false,"simple_object_float":-5.5,"simple_object_int":5,"simple_object_null":null,"simple_object_string":"example"}}}`,
682 },
683 {
684 demonstrates: "a key added then deleted is kept deleted",
685 p1: `{"add_then_delete": "atd"}`,
686 p2: `{"add_then_delete": null}`,
687 exp: `{"add_then_delete": null}`,
688 },
689 {
690 demonstrates: "a key deleted then added is kept added",
691 p1: `{"delete_then_add": null}`,
692 p2: `{"delete_then_add": "dta"}`,
693 exp: `{"delete_then_add": "dta"}`,
694 },
695 {
696 demonstrates: "object overrides array",
697 p1: `[]`,
698 p2: `{"del": null, "add": "a"}`,
699 exp: `{"del": null, "add": "a"}`,
700 },
701 {
702 demonstrates: "array overrides object",
703 p1: `{"del": null, "add": "a"}`,
704 p2: `[]`,
705 exp: `[]`,
706 },
707 }
708
709 for _, c := range cases {
710 out, err := MergeMergePatches([]byte(c.p1), []byte(c.p2))
711
712 if err != nil {
713 panic(err)
714 }
715
716 if !compareJSON(c.exp, string(out)) {
717 t.Logf("Error while trying to demonstrate: %v", c.demonstrates)
718 t.Logf("Got %v", string(out))
719 t.Logf("Expected %v", c.exp)
720 t.Fatalf("Merged merge patch is incorrect")
721 }
722 }
723 }
724
View as plain text