Rework tests.
This commit is contained in:
98
jsonpatch.py
98
jsonpatch.py
@@ -51,11 +51,14 @@ class JsonPatchConflict(JsonPatchException):
|
|||||||
|
|
||||||
|
|
||||||
def apply_patch(doc, patch):
|
def apply_patch(doc, patch):
|
||||||
"""
|
""" Apply list of patches to specified json document.
|
||||||
>>> obj = { 'baz': 'qux', 'foo': 'bar' }
|
|
||||||
>>> patch = [ { 'remove': '/baz' } ]
|
>>> doc = {'foo': 'bar'}
|
||||||
>>> apply_patch(obj, patch)
|
>>> other = apply_patch(doc, [{'add': '/baz', 'value': 'qux'}])
|
||||||
{'foo': 'bar'}
|
>>> doc is other
|
||||||
|
True
|
||||||
|
>>> doc
|
||||||
|
{'foo': 'bar', 'baz': 'qux'}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
p = JsonPatch(patch)
|
p = JsonPatch(patch)
|
||||||
@@ -63,7 +66,20 @@ def apply_patch(doc, patch):
|
|||||||
|
|
||||||
|
|
||||||
class JsonPatch(object):
|
class JsonPatch(object):
|
||||||
""" A JSON Patch is a list of Patch Operations """
|
""" A JSON Patch is a list of Patch Operations.
|
||||||
|
|
||||||
|
>>> patch = JsonPatch([
|
||||||
|
... {'add': '/foo', 'value': 'bar'},
|
||||||
|
... {'add': '/baz', 'value': [1, 2, 3]},
|
||||||
|
... {'remove': '/baz/1'},
|
||||||
|
... {'test': '/baz', 'value': [1, 3]},
|
||||||
|
... {'replace': '/baz/0', 'value': 42},
|
||||||
|
... {'remove': '/baz/1'},
|
||||||
|
... ])
|
||||||
|
>>> doc = {}
|
||||||
|
>>> patch.apply(doc)
|
||||||
|
{'foo': 'bar', 'baz': [42]}
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, patch):
|
def __init__(self, patch):
|
||||||
self.patch = patch
|
self.patch = patch
|
||||||
@@ -105,7 +121,7 @@ class JsonPatch(object):
|
|||||||
|
|
||||||
|
|
||||||
class PatchOperation(object):
|
class PatchOperation(object):
|
||||||
""" A single operation inside a JSON Patch """
|
""" A single operation inside a JSON Patch. """
|
||||||
|
|
||||||
def __init__(self, location, operation):
|
def __init__(self, location, operation):
|
||||||
self.location = location
|
self.location = location
|
||||||
@@ -153,18 +169,7 @@ class PatchOperation(object):
|
|||||||
|
|
||||||
|
|
||||||
class RemoveOperation(PatchOperation):
|
class RemoveOperation(PatchOperation):
|
||||||
""" Removes an object property or an array element
|
""" Removes an object property or an array element. """
|
||||||
|
|
||||||
>>> obj = { 'baz': 'qux', 'foo': 'bar' }
|
|
||||||
>>> patch = JsonPatch( [ { 'remove': '/baz' } ] )
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': 'bar'}
|
|
||||||
|
|
||||||
>>> obj = { 'foo': [ 'bar', 'qux', 'baz' ] }
|
|
||||||
>>> patch = JsonPatch( [ { "remove": "/foo/1" } ] )
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': ['bar', 'baz']}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def apply(self, obj):
|
def apply(self, obj):
|
||||||
subobj, part = self.locate(obj, self.location)
|
subobj, part = self.locate(obj, self.location)
|
||||||
@@ -172,18 +177,7 @@ class RemoveOperation(PatchOperation):
|
|||||||
|
|
||||||
|
|
||||||
class AddOperation(PatchOperation):
|
class AddOperation(PatchOperation):
|
||||||
""" Adds an object property or an array element
|
""" Adds an object property or an array element. """
|
||||||
|
|
||||||
>>> obj = { "foo": "bar" }
|
|
||||||
>>> patch = JsonPatch([ { "add": "/baz", "value": "qux" } ])
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': 'bar', 'baz': 'qux'}
|
|
||||||
|
|
||||||
>>> obj = { "foo": [ "bar", "baz" ] }
|
|
||||||
>>> patch = JsonPatch([ { "add": "/foo/1", "value": "qux" } ])
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': ['bar', 'qux', 'baz']}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def apply(self, obj):
|
def apply(self, obj):
|
||||||
value = self.operation["value"]
|
value = self.operation["value"]
|
||||||
@@ -206,13 +200,7 @@ class AddOperation(PatchOperation):
|
|||||||
|
|
||||||
|
|
||||||
class ReplaceOperation(PatchOperation):
|
class ReplaceOperation(PatchOperation):
|
||||||
""" Replaces a value
|
""" Replaces an object property or an array element by new value. """
|
||||||
|
|
||||||
>>> obj = { "baz": "qux", "foo": "bar" }
|
|
||||||
>>> patch = JsonPatch([ { "replace": "/baz", "value": "boo" } ])
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': 'bar', 'baz': 'boo'}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def apply(self, obj):
|
def apply(self, obj):
|
||||||
value = self.operation["value"]
|
value = self.operation["value"]
|
||||||
@@ -233,18 +221,7 @@ class ReplaceOperation(PatchOperation):
|
|||||||
|
|
||||||
|
|
||||||
class MoveOperation(PatchOperation):
|
class MoveOperation(PatchOperation):
|
||||||
""" Moves a value
|
""" Moves an object property or an array element to new location. """
|
||||||
|
|
||||||
>>> obj = {'foo': {'bar': 'baz', 'waldo': 'fred'}, 'qux': {'corge': 'grault'}}
|
|
||||||
>>> patch = JsonPatch([{'move': '/foo/waldo', 'to': '/qux/thud'}])
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'qux': {'thud': 'fred', 'corge': 'grault'}, 'foo': {'bar': 'baz'}}
|
|
||||||
|
|
||||||
>>> obj = {'foo': ['all', 'grass', 'cows', 'eat']}
|
|
||||||
>>> patch = JsonPatch([{'move': '/foo/1', 'to': '/foo/3'}])
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': ['all', 'cows', 'eat', 'grass']}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def apply(self, obj):
|
def apply(self, obj):
|
||||||
subobj, part = self.locate(obj, self.location)
|
subobj, part = self.locate(obj, self.location)
|
||||||
@@ -254,26 +231,7 @@ class MoveOperation(PatchOperation):
|
|||||||
|
|
||||||
|
|
||||||
class TestOperation(PatchOperation):
|
class TestOperation(PatchOperation):
|
||||||
""" Test value by specified location
|
""" Test value by specified location. """
|
||||||
|
|
||||||
>>> obj = {'baz': 'qux', 'foo': ['a', 2, 'c']}
|
|
||||||
>>> patch = JsonPatch([
|
|
||||||
... {'test': '/baz', 'value': 'qux'},
|
|
||||||
... {'test': '/foo/1', 'value': 2}
|
|
||||||
... ])
|
|
||||||
>>> patch.apply(obj)
|
|
||||||
{'foo': ['a', 2, 'c'], 'baz': 'qux'}
|
|
||||||
|
|
||||||
>>> patch = JsonPatch([
|
|
||||||
... {'test': '/foo/1', 'value': 'BOOM!'}
|
|
||||||
... ])
|
|
||||||
>>> try:
|
|
||||||
... patch.apply(obj)
|
|
||||||
... except AssertionError:
|
|
||||||
... pass
|
|
||||||
... else:
|
|
||||||
... assert False, 'test should fall'
|
|
||||||
"""
|
|
||||||
|
|
||||||
def apply(self, obj):
|
def apply(self, obj):
|
||||||
value = self.operation['value']
|
value = self.operation['value']
|
||||||
|
|||||||
87
tests.py
87
tests.py
@@ -1,44 +1,73 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import doctest
|
import doctest
|
||||||
import unittest
|
import unittest
|
||||||
import sys
|
import jsonpatch
|
||||||
|
|
||||||
modules = ['jsonpatch']
|
|
||||||
coverage_modules = []
|
|
||||||
|
|
||||||
suite = unittest.TestSuite()
|
class ApplyPatchTestCase(unittest.TestCase):
|
||||||
|
|
||||||
for module in modules:
|
def test_add_object_key(self):
|
||||||
m = __import__(module, fromlist=[module])
|
obj = {'foo': 'bar'}
|
||||||
coverage_modules.append(m)
|
jsonpatch.apply_patch(obj, [{'add': '/baz', 'value': 'qux'}])
|
||||||
suite.addTest(doctest.DocTestSuite(m))
|
self.assertTrue('baz' in obj)
|
||||||
|
self.assertEqual(obj['baz'], 'qux')
|
||||||
|
|
||||||
runner = unittest.TextTestRunner(verbosity=2)
|
def test_add_array_item(self):
|
||||||
|
obj = {'foo': ['bar', 'baz']}
|
||||||
|
jsonpatch.apply_patch(obj, [{'add': '/foo/1', 'value': 'qux'}])
|
||||||
|
self.assertEqual(obj['foo'], ['bar', 'qux', 'baz'])
|
||||||
|
|
||||||
try:
|
def test_remove_object_key(self):
|
||||||
import coverage
|
obj = {'foo': 'bar', 'baz': 'qux'}
|
||||||
except ImportError:
|
jsonpatch.apply_patch(obj, [{'remove': '/baz'}])
|
||||||
coverage = None
|
self.assertTrue('baz' not in obj)
|
||||||
|
|
||||||
if coverage is not None:
|
def test_remove_array_item(self):
|
||||||
coverage.erase()
|
obj = {'foo': ['bar', 'qux', 'baz']}
|
||||||
coverage.start()
|
jsonpatch.apply_patch(obj, [{'remove': '/foo/1'}])
|
||||||
|
self.assertEqual(obj['foo'], ['bar', 'baz'])
|
||||||
|
|
||||||
result = runner.run(suite)
|
def test_replace_object_key(self):
|
||||||
|
obj = {'foo': 'bar', 'baz': 'qux'}
|
||||||
|
jsonpatch.apply_patch(obj, [{'replace': '/baz', 'value': 'boo'}])
|
||||||
|
self.assertTrue(obj['baz'], 'boo')
|
||||||
|
|
||||||
if not result.wasSuccessful():
|
def test_replace_array_item(self):
|
||||||
sys.exit(1)
|
obj = {'foo': ['bar', 'qux', 'baz']}
|
||||||
|
jsonpatch.apply_patch(obj, [{'replace': '/foo/1', 'value': 'boo'}])
|
||||||
|
self.assertEqual(obj['foo'], ['bar', 'boo', 'baz'])
|
||||||
|
|
||||||
if coverage is not None:
|
def test_move_object_key(self):
|
||||||
coverage.stop()
|
obj = {'foo': {'bar': 'baz', 'waldo': 'fred'},
|
||||||
coverage.report(coverage_modules)
|
'qux': {'corge': 'grault'}}
|
||||||
coverage.erase()
|
jsonpatch.apply_patch(obj, [{'move': '/foo/waldo', 'to': '/qux/thud'}])
|
||||||
|
self.assertEqual(obj, {'qux': {'thud': 'fred', 'corge': 'grault'},
|
||||||
|
'foo': {'bar': 'baz'}})
|
||||||
|
|
||||||
if coverage is None:
|
def test_move_array_item(self):
|
||||||
print("""
|
obj = {'foo': ['all', 'grass', 'cows', 'eat']}
|
||||||
No coverage reporting done (Python module "coverage" is missing)
|
jsonpatch.apply_patch(obj, [{'move': '/foo/1', 'to': '/foo/3'}])
|
||||||
Please install the python-coverage package to get coverage reporting.
|
self.assertEqual(obj, {'foo': ['all', 'cows', 'eat', 'grass']})
|
||||||
""", file=sys.stderr)
|
|
||||||
|
def test_test_success(self):
|
||||||
|
obj = {'baz': 'qux', 'foo': ['a', 2, 'c']}
|
||||||
|
jsonpatch.apply_patch(obj, [{'test': '/baz', 'value': 'qux'},
|
||||||
|
{'test': '/foo/1', 'value': 2}])
|
||||||
|
|
||||||
|
def test_test_error(self):
|
||||||
|
obj = {'bar': 'qux'}
|
||||||
|
self.assertRaises(AssertionError,
|
||||||
|
jsonpatch.apply_patch,
|
||||||
|
obj, [{'test': '/bar', 'value': 'bar'}])
|
||||||
|
|
||||||
|
|
||||||
|
def suite():
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
suite.addTest(doctest.DocTestSuite(jsonpatch))
|
||||||
|
suite.addTest(unittest.makeSuite(ApplyPatchTestCase))
|
||||||
|
return suite
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(defaultTest='suite')
|
||||||
|
|||||||
Reference in New Issue
Block a user