Skip to content

Commit

Permalink
use new base class
Browse files Browse the repository at this point in the history
  • Loading branch information
SKairinos committed Jan 15, 2024
1 parent 765deaf commit 3370d58
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 87 deletions.
6 changes: 6 additions & 0 deletions codeforlife/permissions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,11 @@
Created on 14/12/2023 at 14:04:57(+00:00).
"""

import typing as t

from rest_framework.permissions import BasePermission

from .is_cron_request_from_google import IsCronRequestFromGoogle
from .is_self import IsSelf

AnyPermission = t.TypeVar("AnyPermission", bound=BasePermission)
1 change: 1 addition & 0 deletions codeforlife/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
from .api import APIClient, APITestCase
from .cron import CronTestCase, CronTestClient
from .model import ModelTestCase
from .permission import PermissionTestCase
99 changes: 99 additions & 0 deletions codeforlife/tests/permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""
© Ocado Group
Created on 15/01/2024 at 15:15:20(+00:00).
Test helpers for Django Rest Framework permissions.
"""

import typing as t

from django.test import TestCase
from rest_framework.request import Request
from rest_framework.test import APIRequestFactory
from rest_framework.views import APIView

from ..permissions import AnyPermission
from ..types import Args, KwArgs


class PermissionTestCase(TestCase, t.Generic[AnyPermission]):
"""Base for all permission test cases."""

@classmethod
def get_permission_class(cls) -> t.Type[AnyPermission]:
"""Get the permission's class.
Returns:
The permission's class.
"""

# pylint: disable-next=no-member
return t.get_args(cls.__orig_bases__[0])[ # type: ignore[attr-defined]
0
]

def setUp(self):
self.request_factory = APIRequestFactory()

def _assert_has_permission(
self,
request: Request,
view: t.Optional[APIView],
init_args: t.Optional[Args],
init_kwargs: t.Optional[KwArgs],
):
view = view or APIView()
init_args = init_args or tuple()
init_kwargs = init_kwargs or {}

permission_class = self.get_permission_class()
permission = permission_class(*init_args, **init_kwargs)
return permission.has_permission(request, view)

def assert_has_permission(
self,
request: Request,
view: t.Optional[APIView] = None,
init_args: t.Optional[Args] = None,
init_kwargs: t.Optional[KwArgs] = None,
):
"""Assert that the request does have permission.
Args:
request: The request being sent to the view.
view: The view that is being requested.
init_args: The arguments used to initialize the permission.
init_kwargs: The keyword arguments used to initialize the
permission.
"""

assert self._assert_has_permission(
request,
view,
init_args,
init_kwargs,
)

def assert_not_has_permission(
self,
request: Request,
view: t.Optional[APIView] = None,
init_args: t.Optional[Args] = None,
init_kwargs: t.Optional[KwArgs] = None,
):
"""Assert that the request does not have permission.
Args:
request: The request being sent to the view.
view: The view that is being requested.
init_args: The arguments used to initialize the permission.
init_kwargs: The keyword arguments used to initialize the
permission.
"""

assert not self._assert_has_permission(
request,
view,
init_args,
init_kwargs,
)
15 changes: 15 additions & 0 deletions codeforlife/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
© Ocado Group
Created on 15/01/2024 at 15:32:54(+00:00).
Reusable type hints.
"""

import typing as t

Args = t.Tuple[t.Any, ...]
KwArgs = t.Dict[str, t.Any]

JsonList = t.List["JsonValue"]
JsonDict = t.Dict[str, "JsonValue"]
JsonValue = t.Union[int, str, bool, JsonList, JsonDict]
6 changes: 2 additions & 4 deletions codeforlife/user/tests/permissions/test_in_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
Created on 14/12/2023 at 14:26:20(+00:00).
"""

from rest_framework.views import APIView

from ....tests import APITestCase
from ....tests import PermissionTestCase
from ...permissions import InClass


class TestInClass(APITestCase):
class TestInClass(PermissionTestCase[InClass]):
"""
Naming convention:
test_{class_id}__{user_type}
Expand Down
6 changes: 2 additions & 4 deletions codeforlife/user/tests/permissions/test_in_school.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
Created on 14/12/2023 at 14:26:20(+00:00).
"""

from rest_framework.views import APIView

from ....tests import APITestCase
from ....tests import PermissionTestCase
from ...permissions import InSchool


class TestInSchool(APITestCase):
class TestInSchool(PermissionTestCase[InSchool]):
"""
Naming convention:
test_{school_id}__{user_type}
Expand Down
6 changes: 2 additions & 4 deletions codeforlife/user/tests/permissions/test_is_independent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
Created on 14/12/2023 at 14:26:20(+00:00).
"""

from rest_framework.views import APIView

from ....tests import APITestCase
from ....tests import PermissionTestCase
from ...permissions import IsIndependent


class TestIsIndependent(APITestCase):
class TestIsIndependent(PermissionTestCase[IsIndependent]):
"""
Naming convention:
test_{user_type}
Expand Down
6 changes: 2 additions & 4 deletions codeforlife/user/tests/permissions/test_is_student.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
Created on 14/12/2023 at 14:26:20(+00:00).
"""

from rest_framework.views import APIView

from ....tests import APITestCase
from ....tests import PermissionTestCase
from ...permissions import IsStudent


class TestIsStudent(APITestCase):
class TestIsStudent(PermissionTestCase[IsStudent]):
"""
Naming convention:
test_{user_type}__{student_id}
Expand Down
Loading

0 comments on commit 3370d58

Please sign in to comment.