123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- from django.core.exceptions import PermissionDenied
- from django.http import Http404
- from django.test import TestCase
- from misago.core.apipatch import ApiPatch, InvalidAction
- class MockRequest(object):
- def __init__(self, data=None):
- self.data = data
- class MockObject(object):
- def __init__(self, pk):
- self.id = pk
- self.pk = pk
- class ApiPatchTests(TestCase):
- def test_add(self):
- """add method adds function to patch object"""
- patch = ApiPatch()
- def mock_function():
- pass
- patch.add("test-add", mock_function)
- self.assertEqual(len(patch._actions), 1)
- self.assertEqual(patch._actions[0]["op"], "add")
- self.assertEqual(patch._actions[0]["path"], "test-add")
- self.assertEqual(patch._actions[0]["handler"], mock_function)
- def test_remove(self):
- """remove method adds function to patch object"""
- patch = ApiPatch()
- def mock_function():
- pass
- patch.remove("test-remove", mock_function)
- self.assertEqual(len(patch._actions), 1)
- self.assertEqual(patch._actions[0]["op"], "remove")
- self.assertEqual(patch._actions[0]["path"], "test-remove")
- self.assertEqual(patch._actions[0]["handler"], mock_function)
- def test_replace(self):
- """replace method adds function to patch object"""
- patch = ApiPatch()
- def mock_function():
- pass
- patch.replace("test-replace", mock_function)
- self.assertEqual(len(patch._actions), 1)
- self.assertEqual(patch._actions[0]["op"], "replace")
- self.assertEqual(patch._actions[0]["path"], "test-replace")
- self.assertEqual(patch._actions[0]["handler"], mock_function)
- def test_validate_action(self):
- """validate_action method validates action dict"""
- patch = ApiPatch()
- VALID_ACTIONS = [
- {"op": "add", "path": "test", "value": 42},
- {"op": "remove", "path": "other-test", "value": "Lorem"},
- {"op": "replace", "path": "false-test", "value": None},
- ]
- for action in VALID_ACTIONS:
- patch.validate_action(action)
- # undefined op
- UNSUPPORTED_ACTIONS = ({}, {"op": ""}, {"no": "op"})
- for action in UNSUPPORTED_ACTIONS:
- try:
- patch.validate_action(action)
- except InvalidAction as e:
- self.assertEqual(e.args[0], "undefined op")
- # unsupported op
- try:
- patch.validate_action({"op": "nope"})
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"nope" op is unsupported')
- # op lacking patch
- try:
- patch.validate_action({"op": "add"})
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"add" op has to specify path')
- # op lacking value
- try:
- patch.validate_action({"op": "add", "path": "yolo"})
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"add" op has to specify value')
- # empty value is allowed
- try:
- patch.validate_action({"op": "add", "path": "yolo", "value": ""})
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"add" op has to specify value')
- def test_dispatch_action(self):
- """dispatch_action calls specified actions"""
- patch = ApiPatch()
- mock_target = MockObject(13)
- def action_a(request, target, value):
- self.assertEqual(request, "request")
- self.assertEqual(target, mock_target)
- return {"a": value * 2, "b": 111}
- patch.replace("abc", action_a)
- def action_b(request, target, value):
- self.assertEqual(request, "request")
- self.assertEqual(target, mock_target)
- return {"b": value * 10}
- patch.replace("abc", action_b)
- def action_fail(request, target, value):
- self.fail("unrequired action was called")
- patch.add("c", action_fail)
- patch.remove("c", action_fail)
- patch.replace("c", action_fail)
- patch_dict = {"id": 123}
- patch.dispatch_action(
- patch_dict,
- "request",
- mock_target,
- {"op": "replace", "path": "abc", "value": 5},
- )
- self.assertEqual(len(patch_dict), 3)
- self.assertEqual(patch_dict["id"], 123)
- self.assertEqual(patch_dict["a"], 10)
- self.assertEqual(patch_dict["b"], 50)
- def test_dispatch(self):
- """dispatch calls actions and returns response"""
- patch = ApiPatch()
- def action_error(request, target, value):
- if value == "404":
- raise Http404()
- if value == "perm":
- raise PermissionDenied("yo ain't doing that!")
- patch.replace("error", action_error)
- def action_mutate(request, target, value):
- return {"value": value * 2}
- patch.replace("mutate", action_mutate)
- # dispatch requires list as an argument
- response = patch.dispatch(MockRequest({}), {})
- self.assertEqual(response.status_code, 400)
- self.assertEqual(
- response.data["detail"], "PATCH request should be list of operations"
- )
- # valid dispatch
- response = patch.dispatch(
- MockRequest(
- [
- {"op": "replace", "path": "mutate", "value": 2},
- {"op": "replace", "path": "mutate", "value": 6},
- {"op": "replace", "path": "mutate", "value": 7},
- ]
- ),
- MockObject(13),
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(len(response.data["detail"]), 3)
- self.assertEqual(response.data["detail"][0], "ok")
- self.assertEqual(response.data["detail"][1], "ok")
- self.assertEqual(response.data["detail"][2], "ok")
- self.assertEqual(response.data["id"], 13)
- self.assertEqual(response.data["value"], 14)
- # invalid action in dispatch
- response = patch.dispatch(
- MockRequest(
- [
- {"op": "replace", "path": "mutate", "value": 2},
- {"op": "replace", "path": "mutate", "value": 6},
- {"op": "replace"},
- {"op": "replace", "path": "mutate", "value": 7},
- ]
- ),
- MockObject(13),
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(len(response.data["detail"]), 3)
- self.assertEqual(response.data["detail"][0], "ok")
- self.assertEqual(response.data["detail"][1], "ok")
- self.assertEqual(response.data["detail"][2], '"replace" op has to specify path')
- self.assertEqual(response.data["id"], 13)
- self.assertEqual(response.data["value"], 12)
- # action in dispatch raised 404
- response = patch.dispatch(
- MockRequest(
- [
- {"op": "replace", "path": "mutate", "value": 2},
- {"op": "replace", "path": "error", "value": "404"},
- {"op": "replace", "path": "mutate", "value": 6},
- {"op": "replace", "path": "mutate", "value": 7},
- ]
- ),
- MockObject(13),
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(len(response.data["detail"]), 2)
- self.assertEqual(response.data["detail"][0], "ok")
- self.assertEqual(response.data["detail"][1], "NOT FOUND")
- self.assertEqual(response.data["id"], 13)
- self.assertEqual(response.data["value"], 4)
- # action in dispatch raised perm denied
- response = patch.dispatch(
- MockRequest(
- [
- {"op": "replace", "path": "mutate", "value": 2},
- {"op": "replace", "path": "mutate", "value": 6},
- {"op": "replace", "path": "mutate", "value": 9},
- {"op": "replace", "path": "error", "value": "perm"},
- ]
- ),
- MockObject(13),
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(len(response.data["detail"]), 4)
- self.assertEqual(response.data["detail"][0], "ok")
- self.assertEqual(response.data["detail"][1], "ok")
- self.assertEqual(response.data["detail"][2], "ok")
- self.assertEqual(response.data["detail"][3], "yo ain't doing that!")
- self.assertEqual(response.data["id"], 13)
- self.assertEqual(response.data["value"], 18)
|