Skip to content
This repository was archived by the owner on Mar 19, 2024. It is now read-only.

Commit a010229

Browse files
committed
Lesson1 updates
1 parent be3f28d commit a010229

File tree

8 files changed

+266
-95
lines changed

8 files changed

+266
-95
lines changed

poetry.lock

Lines changed: 106 additions & 92 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dennis = "^1.1"
6666
dump-env = "^1.3"
6767
ipython = "^8.15"
6868
import-linter = "^1.11"
69+
mimesis = "^11.1.0"
6970

7071
[tool.poetry.group.docs]
7172
optional = true

tests/conftest.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
"""
88

99
pytest_plugins = [
10-
# Should be the first custom one:
1110
'plugins.django_settings',
12-
13-
# TODO: add your own plugins here!
11+
'plugins.identity.user',
1412
]

tests/plugins/django_settings.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
from random import SystemRandom
2+
13
import pytest
24
from django.conf import LazySettings
35
from django.core.cache import BaseCache, caches
46

7+
MAX_RANDOM_INT = 999999
8+
59

610
@pytest.fixture(autouse=True)
711
def _media_root(
@@ -36,6 +40,12 @@ def _debug(settings: LazySettings) -> None:
3640
template['OPTIONS']['debug'] = True
3741

3842

43+
@pytest.fixture(scope='session', autouse=True)
44+
def faker_seed() -> int:
45+
"""Create a random seed for the Faker library."""
46+
return SystemRandom().randint(0, MAX_RANDOM_INT)
47+
48+
3949
@pytest.fixture(autouse=True)
4050
def cache(settings: LazySettings) -> BaseCache:
4151
"""Modifies how cache is used in Django tests."""

tests/plugins/identity/__init__.py

Whitespace-only changes.

tests/plugins/identity/user.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Identity data related plugins."""
2+
from datetime import datetime
3+
from typing import Callable, Protocol, TypeAlias, TypedDict, Unpack, final
4+
5+
import pytest
6+
from django.contrib.auth import get_user_model
7+
from mimesis.locales import Locale
8+
from mimesis.schema import Field, Schema
9+
10+
11+
@final
12+
class ProfileData(TypedDict, total=False):
13+
"""Represent the simplified profile data."""
14+
15+
first_name: str
16+
last_name: str
17+
date_of_birth: datetime
18+
address: str
19+
job_title: str
20+
phone: str
21+
22+
23+
ProfileAssertion: TypeAlias = Callable[[str, ProfileData], None]
24+
25+
26+
class ProfileDataFactory(Protocol):
27+
"""Factory for representation of the simplified profile data."""
28+
29+
def __call__(self, **fields: Unpack[ProfileData]) -> ProfileData:
30+
"""User data factory protocol."""
31+
32+
33+
@pytest.fixture()
34+
def profile_data_factory(
35+
faker_seed: int,
36+
) -> ProfileDataFactory:
37+
"""Returns factory for fake random profile data."""
38+
39+
def factory(**fields: Unpack[ProfileData]) -> ProfileData:
40+
mf = Field(locale=Locale.EN, seed=faker_seed)
41+
schema = Schema(
42+
schema=lambda: {
43+
'first_name': mf('person.first_name'),
44+
'last_name': mf('person.last_name'),
45+
'date_of_birth': mf('datetime.date'),
46+
'address': mf('address.city'),
47+
'job_title': mf('person.occupation'),
48+
'phone': mf('person.telephone'),
49+
},
50+
iterations=1,
51+
)
52+
return {
53+
**schema.create()[0], # type: ignore[typeddict-item]
54+
**fields,
55+
}
56+
57+
return factory
58+
59+
60+
@pytest.fixture(scope='session')
61+
def assert_correct_profile() -> ProfileAssertion:
62+
"""All profile fields are equal to reference."""
63+
64+
def factory(email: str, expected: ProfileData) -> None:
65+
user = get_user_model().objects.get(email=email)
66+
assert user.id
67+
assert user.is_active
68+
for field_name, data_value in expected.items():
69+
assert getattr(user, field_name) == data_value
70+
return factory
71+
72+
73+
@pytest.fixture(scope='session')
74+
def assert_incorrect_profile() -> ProfileAssertion:
75+
"""At least one field does not match."""
76+
77+
def factory(email: str, expected: ProfileData) -> None:
78+
user = get_user_model().objects.get(email=email)
79+
assert user.id
80+
assert user.is_active
81+
matches = []
82+
for field_name, data_value in expected.items():
83+
matches.append(getattr(user, field_name) == data_value)
84+
85+
assert not all(matches)
86+
87+
return factory

tests/test_server/test_urls.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from http import HTTPStatus
22

33
import pytest
4+
from django.contrib.auth.models import User
45
from django.test import Client
6+
from plugins.identity.user import ProfileAssertion, ProfileDataFactory
57

68

79
@pytest.mark.django_db()()
@@ -43,6 +45,65 @@ def test_admin_docs_authorized(admin_client: Client) -> None:
4345
assert b'docutils' not in response.content
4446

4547

48+
def test_picture_pages_unauthorized(client: Client) -> None:
49+
"""This test ensures that picture management pages require auth."""
50+
response = client.get('/pictures/dashboard')
51+
assert response.status_code == HTTPStatus.FOUND
52+
53+
response = client.get('/pictures/favourites')
54+
assert response.status_code == HTTPStatus.FOUND
55+
56+
57+
@pytest.mark.django_db()
58+
def test_picture_pages_authorized(
59+
client: Client,
60+
django_user_model: User,
61+
) -> None:
62+
"""Ensures picture management pages are accessible for authorized user."""
63+
password, email = 'password', '[email protected]'
64+
user = django_user_model.objects.create_user(
65+
email,
66+
password,
67+
)
68+
client.force_login(user)
69+
70+
response = client.get('/pictures/dashboard')
71+
assert response.status_code == HTTPStatus.OK
72+
73+
response = client.get('/pictures/favourites')
74+
assert response.status_code == HTTPStatus.OK
75+
76+
77+
@pytest.mark.django_db()
78+
def test_profile_update_authorized(
79+
client: Client,
80+
django_user_model: User,
81+
profile_data_factory: 'ProfileDataFactory',
82+
assert_correct_profile: 'ProfileAssertion',
83+
assert_incorrect_profile: 'ProfileAssertion',
84+
) -> None:
85+
"""This test ensures profile updating for an authorized user."""
86+
user_data = profile_data_factory()
87+
88+
password, email = 'password', '[email protected]'
89+
user = django_user_model.objects.create_user(
90+
email,
91+
password,
92+
)
93+
client.force_login(user)
94+
95+
# there might be a probability of accidental match, but disregard it for now
96+
assert_incorrect_profile(email, user_data)
97+
98+
response = client.post(
99+
'/identity/update',
100+
data=user_data,
101+
)
102+
assert response.status_code == HTTPStatus.FOUND
103+
assert response.get('Location') == '/identity/update'
104+
assert_correct_profile(email, user_data)
105+
106+
46107
@pytest.mark.parametrize('page', [
47108
'/robots.txt',
48109
'/humans.txt',

0 commit comments

Comments
 (0)