Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions jsonpatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,12 @@ def apply(self, obj):
if part is None:
return value

if part == "-":
raise InvalidJsonPatch("'path' with '-' can't be applied to 'replace' operation")

if isinstance(subobj, MutableSequence):
# '-' only refers to the (nonexistent) element after the end of
# an array; for an object it is an ordinary member name
if part == "-":
raise InvalidJsonPatch("'path' with '-' can't be applied to 'replace' operation")

if part >= len(subobj) or part < 0:
raise JsonPatchConflict("can't replace outside of list")

Expand Down
6 changes: 2 additions & 4 deletions property_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,8 @@ def test_diff_of_equal_documents_is_empty(self, doc):
self.assertEqual(list(jsonpatch.make_patch(doc, copy.deepcopy(doc))),
[])

@unittest.expectedFailure
@given(doc_pairs)
# replace of the object member '-' is rejected
# replace of the object member '-' was rejected, #212
@example(docs=({'-': 0}, {'-': 1}))
def test_roundtrip(self, docs):
self.check_roundtrip(*docs)
Expand Down Expand Up @@ -417,9 +416,8 @@ def test_move_into_own_child_fails(self, case):
jsonpatch.apply_patch(
doc, [{'op': 'move', 'from': source, 'path': target}])

# '-' is rejected even where it is an object key, not an array index
@unittest.expectedFailure
@given(docs_with_locations(), json_docs)
# '-' was rejected even where it is an object key, not an array index, #212
@example(case=({'-': None}, ['-']), value=0)
def test_replace_any_existing_location(self, case, value):
doc, parts = case
Expand Down
22 changes: 22 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ def test_replace_object_key(self):
res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '/baz', 'value': 'boo'}])
self.assertTrue(res['baz'], 'boo')

def test_replace_object_key_dash(self):
# '-' only has a special meaning for arrays (#212)
obj = {'foo': {'-': 'bar', 'baz': 'qux'}}
res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '/foo/-',
'value': 'boo'}])
self.assertEqual(res, {'foo': {'-': 'boo', 'baz': 'qux'}})

def test_replace_array_dash(self):
obj = {'foo': ['bar', 'qux']}
with self.assertRaises(jsonpatch.InvalidJsonPatch):
jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '/foo/-',
'value': 'boo'}])

def test_replace_whole_document(self):
obj = {'foo': 'bar'}
res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '', 'value': {'baz': 'qux'}}])
Expand Down Expand Up @@ -847,6 +860,11 @@ def test_issue_179(self):
with self.subTest(old=old, new=new):
self.assertMakesPatch(old, new)

def test_issue_212(self):
"""A changed object member named '-' is replaced, not rejected."""
self.assertMakesPatch({'-': 0}, {'-': 1})
self.assertMakesPatch({'a': {'-': [1]}}, {'a': {'-': [2]}})

def test_move_with_numeric_object_keys(self):
"""Object keys that look like array indices are not shifted."""
self.assertMakesPatch({'0': None, 'a': []}, {'1': [], 'a': [None]})
Expand Down Expand Up @@ -1308,6 +1326,10 @@ def test_replace_operation_structure(self):
jsonpatch.ReplaceOperation({'path': '/'}).apply({})

with self.assertRaises(jsonpatch.InvalidJsonPatch):
jsonpatch.ReplaceOperation({'path': '/top/-', 'value': 'foo'}).apply({'top': ['value']})

# for an object, '-' is an ordinary member name (#212)
with self.assertRaises(jsonpatch.JsonPatchConflict):
jsonpatch.ReplaceOperation({'path': '/top/-', 'value': 'foo'}).apply({'top': {'inner': 'value'}})

with self.assertRaises(jsonpatch.JsonPatchConflict):
Expand Down
Loading