Skip to content

Commit 4a9dce7

Browse files
committed
Handle null correctly when introduced by replace. Fixes #171
1 parent f72a464 commit 4a9dce7

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

v5/patch.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ func (n *lazyNode) intoDoc() (*partialDoc, error) {
254254

255255
err := json.Unmarshal(*n.raw, &n.doc)
256256

257+
if n.doc == nil {
258+
return nil, ErrInvalid
259+
}
260+
257261
if err != nil {
258262
return nil, err
259263
}
@@ -308,6 +312,10 @@ func (n *lazyNode) tryDoc() bool {
308312
return false
309313
}
310314

315+
if n.doc == nil {
316+
return false
317+
}
318+
311319
n.which = eDoc
312320
return true
313321
}
@@ -327,6 +335,18 @@ func (n *lazyNode) tryAry() bool {
327335
return true
328336
}
329337

338+
func (n *lazyNode) isNull() bool {
339+
if n == nil {
340+
return true
341+
}
342+
343+
if n.raw == nil {
344+
return true
345+
}
346+
347+
return bytes.Equal(n.compact(), rawJSONNull)
348+
}
349+
330350
func (n *lazyNode) equal(o *lazyNode) bool {
331351
if n.which == eRaw {
332352
if !n.tryDoc() && !n.tryAry() {
@@ -446,6 +466,10 @@ func (o Operation) From() (string, error) {
446466

447467
func (o Operation) value() *lazyNode {
448468
if obj, ok := o["value"]; ok {
469+
// A `null` gets decoded as a nil RawMessage, so let's fix it up here.
470+
if obj == nil {
471+
return newLazyNode(newRawMessage(rawJSONNull))
472+
}
449473
return newLazyNode(obj)
450474
}
451475

@@ -798,7 +822,10 @@ func ensurePathExists(pd *container, path string, options *ApplyOptions) error {
798822
newNode := newLazyNode(newRawMessage(rawJSONObject))
799823

800824
doc.add(part, newNode, options)
801-
doc, _ = newNode.intoDoc()
825+
doc, err = newNode.intoDoc()
826+
if err != nil {
827+
return err
828+
}
802829
}
803830
} else {
804831
if isArray(*target.raw) {
@@ -1005,12 +1032,14 @@ func (p Patch) test(doc *container, op Operation, options *ApplyOptions) error {
10051032
return errors.Wrapf(err, "error in test for path: '%s'", path)
10061033
}
10071034

1035+
ov := op.value()
1036+
10081037
if val == nil {
1009-
if op.value() == nil || op.value().raw == nil {
1038+
if ov.isNull() {
10101039
return nil
10111040
}
10121041
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
1013-
} else if op.value() == nil {
1042+
} else if ov.isNull() {
10141043
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
10151044
}
10161045

v5/patch_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,11 @@ var BadCases = []BadCase{
727727
`[{"op": "copy", "path": "/qux", "from": "/baz"}]`,
728728
false,
729729
},
730+
{
731+
`{ "foo": {"bar": []}}`,
732+
`[{"op": "replace", "path": "/foo/bar", "value": null}, {"op": "add", "path": "/foo/bar/0", "value": "blah"}]`,
733+
false,
734+
},
730735
}
731736

732737
// This is not thread safe, so we cannot run patch tests in parallel.

0 commit comments

Comments
 (0)