cmsmanage/paperwork/tests.py

168 lines
5.2 KiB
Python

import logging
from collections.abc import Callable
from itertools import chain
from typing import TypedDict
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser, Permission
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.test import Client
from hypothesis import given
from hypothesis import strategies as st
from hypothesis.extra.django import TestCase, from_model
from paperwork.models import (
Certification,
CertificationDefinition,
CertificationVersion,
Department,
InstructorOrVendor,
Waiver,
)
class PermissionLookup(TypedDict):
codename: str
model: type[models.Model]
class PermissionRequiredViewTestCaseMixin:
permissions: list[PermissionLookup] = []
path: str
client: Client
user_with_permission: AbstractBaseUser
user_without_permission: AbstractBaseUser
assertEqual: Callable
@classmethod
def setUpTestData(cls):
User = get_user_model()
cls.client = Client()
cls.user_without_permission = User.objects.create_user(
username="user_without_permission"
)
cls.user_with_permission = User.objects.create_user(
username="user_with_permission"
)
resolved_permissions = [
Permission.objects.get(
content_type=ContentType.objects.get_for_model(permission["model"]),
codename=permission["codename"],
)
for permission in cls.permissions
]
cls.user_with_permission.user_permissions.add(*resolved_permissions)
def test_missing_permission(self) -> None:
# suppress PermissionDenied messages
logger = logging.getLogger("django.request")
previous_log_level = logger.getEffectiveLevel()
logger.setLevel(logging.ERROR)
self.client.force_login(self.user_without_permission)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 403)
logger.setLevel(previous_log_level)
class WaiverReportTestCase(PermissionRequiredViewTestCaseMixin, TestCase):
permissions = [{"model": Waiver, "codename": "view_waiver"}]
path = "/paperwork/waivers"
@given(waivers=st.lists(from_model(Waiver, number=st.none())))
def test_waiver_report(self, waivers: list[Waiver]) -> None:
self.client.force_login(self.user_with_permission)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)
class InstructorOrVendorReportTestCase(PermissionRequiredViewTestCaseMixin, TestCase):
permissions = [{"model": InstructorOrVendor, "codename": "view_instructororvendor"}]
path = "/paperwork/instructors-and-vendors"
@given(
instructors_or_vendors=st.lists(
from_model(InstructorOrVendor, serial=st.none())
)
)
def test_waiver_report(
self, instructors_or_vendors: list[InstructorOrVendor]
) -> None:
self.client.force_login(self.user_with_permission)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)
@st.composite
def random_certifications(
draw,
) -> list[Certification]:
def certifications(version: CertificationVersion):
return st.lists(
from_model(
Certification,
number=st.none(),
certification_version=st.just(version),
),
max_size=10,
)
def versions_with_certifications(definition: CertificationDefinition):
return st.lists(
from_model(CertificationVersion, definition=st.just(definition)).flatmap(
certifications
),
max_size=2,
)
def definitions_with_versions(department: Department):
return st.lists(
from_model(CertificationDefinition, department=st.just(department)).flatmap(
versions_with_certifications
),
max_size=2,
)
return draw(
st.lists(
from_model(Department).flatmap(definitions_with_versions),
max_size=2,
).map(
lambda x: list(
chain.from_iterable(chain.from_iterable(chain.from_iterable(x)))
)
)
)
class CertifiersReportTestCase(PermissionRequiredViewTestCaseMixin, TestCase):
permissions = [{"model": Certification, "codename": "view_certification"}]
path = "/paperwork/certifiers"
@given(certifications=random_certifications())
def test_certifiers_report(self, certifications: list[Certification]) -> None:
self.client.force_login(self.user_with_permission)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)
class CertificationCountReportTestCase(PermissionRequiredViewTestCaseMixin, TestCase):
permissions = [{"model": Certification, "codename": "view_certification"}]
path = "/paperwork/certification-count"
@given(certifications=random_certifications())
def test_certification_count_report(
self, certifications: list[Certification]
) -> None:
self.client.force_login(self.user_with_permission)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)