diff --git a/dav_events/tests/test_urls.py b/dav_events/tests/test_urls.py index df70ec7..55552a4 100644 --- a/dav_events/tests/test_urls.py +++ b/dav_events/tests/test_urls.py @@ -1,13 +1,16 @@ from django.conf import settings +from django.contrib.auth import get_user_model +from django.urls import reverse from dav_base.tests.generic import Url, UrlsTestCase +from .generic import EventMixin from .. import views url_prefix = settings.MODULE_CONFIG.modules['dav_events'].url_prefix -class TestCase(UrlsTestCase): +class TestCase(EventMixin, UrlsTestCase): urls = ( Url('/{}/home'.format(url_prefix), 'dav_events:root', views.base.HomeView.as_view()), Url('/{}/'.format(url_prefix), 'dav_events:list', views.events.EventListView.as_view(), @@ -16,3 +19,38 @@ class TestCase(UrlsTestCase): redirect='/auth/login?next=/{}/export'.format(url_prefix)), Url('/{}/create'.format(url_prefix), 'dav_events:create', views.events.EventCreateView.as_view()), ) + + def setUp(self): + self.event = self.create_event_by_model() + model = get_user_model() + self.username = 'root' + self.password = 'mellon' + self.user = model.objects.create_superuser(username=self.username, password=self.password, + email='root@localhost') + + def test_registrations(self): + pk = self.event.pk + expected_location = '/{}/{}/registrations'.format(url_prefix, pk) + location = reverse('dav_events:registrations', kwargs={'pk': pk}) + self.assertEqual(location, expected_location) + self.client.login(username=self.username, password=self.password) + response = self.client.get(location) + self.assertEqual(response.status_code, 200) + + def test_update(self): + pk = self.event.pk + expected_location = '/{}/{}/edit'.format(url_prefix, pk) + location = reverse('dav_events:update', kwargs={'pk': pk}) + self.assertEqual(location, expected_location) + self.client.login(username=self.username, password=self.password) + response = self.client.get(location) + self.assertEqual(response.status_code, 200) + + def test_detail(self): + pk = self.event.pk + expected_location = '/{}/{}/'.format(url_prefix, pk) + location = reverse('dav_events:detail', kwargs={'pk': pk}) + self.assertEqual(location, expected_location) + self.client.login(username=self.username, password=self.password) + response = self.client.get(location) + self.assertEqual(response.status_code, 200) diff --git a/dav_events/tests/test_utils.py b/dav_events/tests/test_utils.py new file mode 100644 index 0000000..8fdbfe0 --- /dev/null +++ b/dav_events/tests/test_utils.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import datetime +from django.test import TestCase +from django.utils import timezone + +from ..models import Participant, TrashedParticipant +from .. import utils + +from .generic import EventMixin + + +class PurgeParticipantsTestCase(EventMixin, TestCase): + def test_purging_participants_only_with_elapsed_purge_date(self): + event = self.create_event_by_model() + + test_dates = [ + timezone.now(), + timezone.now() - datetime.timedelta(days=1), + timezone.now() + datetime.timedelta(days=1), + timezone.now() - datetime.timedelta(days=720), + timezone.now() + datetime.timedelta(days=720), + ] + + position = 0 + for date in test_dates: + position += 1 + participant = Participant( + event=event, + personal_names='Walter', + family_names='Bonatti', + address='Street 1', + postal_code='23032', + city='Bormio', + email_address='walter@farbemachtstark.de', + phone_number='555 1', + year_of_birth=1930, + dav_number='1', + position=position, + purge_at=date, + ) + participant.save() + + self.assertEqual(Participant.objects.count(), len(test_dates)) + + with self.assertLogs('dav_events.utils', level='INFO') as cm: + utils.purge_participants() + + position = 0 + expected_messages = 0 + for date in test_dates: + position += 1 + expected_purge = date <= timezone.now() + if expected_purge: + expected_messages += 1 + self.assertEqual(expected_purge, not Participant.objects.filter(position=position).exists()) + + self.assertEqual(len(cm.output), expected_messages) + for i in range(expected_messages): + self.assertStartsWith(cm.output[i], 'INFO:dav_events.utils:Purge participant \'') + + def test_purging_trashed_participants_only_with_elapsed_purge_date(self): + event = self.create_event_by_model() + + test_dates = [ + timezone.now(), + timezone.now() - datetime.timedelta(days=1), + timezone.now() + datetime.timedelta(days=1), + timezone.now() - datetime.timedelta(days=720), + timezone.now() + datetime.timedelta(days=720), + ] + + position = 0 + for date in test_dates: + position += 1 + participant = TrashedParticipant( + event=event, + personal_names='Walter', + family_names='Bonatti', + address='Street 1', + postal_code='23032', + city='Bormio', + email_address='walter@farbemachtstark.de', + phone_number='555 1', + year_of_birth=1930, + dav_number='1', + position=position, + created_at=timezone.now(), + purge_at=date, + ) + participant.save() + + self.assertEqual(TrashedParticipant.objects.count(), len(test_dates)) + + with self.assertLogs('dav_events.utils', level='INFO') as cm: + utils.purge_participants() + + position = 0 + expected_messages = 0 + for date in test_dates: + position += 1 + expected_purge = date <= timezone.now() + if expected_purge: + expected_messages += 1 + self.assertEqual(expected_purge, not TrashedParticipant.objects.filter(position=position).exists()) + + self.assertEqual(len(cm.output), expected_messages) + for i in range(expected_messages): + self.assertStartsWith(cm.output[i], 'INFO:dav_events.utils:Purge participant from trash \'') diff --git a/dav_events/tests/test_validators.py b/dav_events/tests/test_validators.py new file mode 100644 index 0000000..012284b --- /dev/null +++ b/dav_events/tests/test_validators.py @@ -0,0 +1,274 @@ +# -*- coding: utf-8 -*- +from django.test import SimpleTestCase + +from dav_base.tests.generic import ValidatorTestMixin + +from ..validators import AlphanumericValidator, LowerAlphanumericValidator, IdStringValidator + + +class AlphanumericValidatorTestCase(ValidatorTestMixin, SimpleTestCase): + validator = AlphanumericValidator + + def test_valid_data(self): + data = ( + '', # Empty string is valid + 'A', # Single uppercase letter + 'a', # Single lowercase letter + '0', # Single digit + 'abc', # Multiple lowercase letters + 'ABCD', # Multiple uppercase letters + 'AbCde', # Mixed case + '123456', # Multiple digits + 'bcd2345', # Letters and digits + 'CDEF3456', # Uppercase and digits + 'AbcD123', # Mixed case and digits + 'a1B2c3', # Alternating case and digits + '012345678909876543210', # Long digit sequence + 'abcdefghijklmnopqrstuvwxyz', # All lowercase letters + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', # All uppercase letters + 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789', # All valid chars + 'EventCode2024', # Real world example + 'USER123EVENT', # Real world example + 'A1', # Single letter and digit + '1A', # Single digit and letter + ) + self.assertValid(self.validator, data) + + def test_invalid_data(self): + """Test invalid strings with special characters, spaces, umlauts""" + data = ( + ' ', # Space + 'abc ', # Trailing space + ' abc', # Leading space + 'a b c', # Space in the middle + '-', # Hyphen + 'abc-def', # Letters with hyphen + '_', # Underscore + 'abc_def', # Letters with underscore + '.', # Dot + 'abc.def', # Letters with dot + ',', # Comma + 'abc,def', # Letters with comma + '!', # Exclamation mark + 'abc!def', # Letters with exclamation + '@', # At sign + 'abc@def', # Letters with at sign + '#', # Hash + 'abc#def', # Letters with hash + '$', # Dollar sign + 'abc$def', # Letters with dollar + '%', # Percent + 'abc%def', # Letters with percent + '&', # Ampersand + 'abc&def', # Letters with ampersand + '*', # Asterisk + 'abc*def', # Letters with asterisk + '+', # Plus + 'abc+def', # Letters with plus + '=', # Equals + 'abc=def', # Letters with equals + '/', # Slash + 'abc/def', # Letters with slash + '\\', # Backslash + 'abc\\def', # Letters with backslash + '?', # Question mark + 'abc?def', # Letters with question mark + ':', # Colon + 'abc:def', # Letters with colon + ';', # Semicolon + 'abc;def', # Letters with semicolon + '"', # Double quote + 'abc"def', # Letters with double quote + "'", # Single quote + "abc'def", # Letters with single quote + '<', # Less than + 'abc', # Greater than + 'abc>def', # Letters with greater than + '(', # Opening parenthesis + 'abc(def)', # Letters with parentheses + '[', # Opening bracket + 'abc[def]', # Letters with brackets + '{', # Opening brace + 'abc{def}', # Letters with braces + 'ä', # Umlaut + 'äbc', # Letters with umlaut + 'ö', # Umlaut o + 'ö', # Umlaut O + 'ü', # Umlaut u + 'ü', # Umlaut U + 'ß', # German sharp s + 'Straße', # German word with umlaut + 'café', # Accented character + 'naïve', # Accented character + '中文', # Chinese characters + 'русский', # Cyrillic characters + 'العربية', # Arabic characters + ) + self.assertInvalid(self.validator, data) + + +class LowerAlphanumericValidatorTestCase(ValidatorTestMixin, SimpleTestCase): + validator = LowerAlphanumericValidator + + def test_valid_data(self): + data = ( + '', # Empty string is valid + 'a', # Single lowercase letter + '0', # Single digit + 'abc', # Multiple lowercase letters + '123456', # Multiple digits + 'bcd2345', # Letters and digits + 'a1b2c3', # Alternating lowercase and digits + '012345678909876543210', # Long digit sequence + 'abcdefghijklmnopqrstuvwxyz', # All lowercase letters + 'eventcode2024', # Real world example (all lowercase) + 'user123event', # Real world example (all lowercase) + 'a1', # Single letter and digit + '1a', # Single digit and letter + ) + self.assertValid(self.validator, data) + + def test_invalid_data(self): + """Test invalid strings with uppercase letters and other characters""" + data = ( + 'A', # Single uppercase letter + 'ABC', # Multiple uppercase letters + 'AbC', # Mixed case + 'ABC123', # Uppercase and digits + 'AbC123', # Mixed case (with uppercase) + ' ', # Space + 'abc ', # Trailing space + ' abc', # Leading space + 'a b c', # Space in the middle + '-', # Hyphen + 'abc-def', # Letters with hyphen + '_', # Underscore + 'abc_def', # Letters with underscore + '.', # Dot + 'abc.def', # Letters with dot + ',', # Comma + 'abc,def', # Letters with comma + '!', # Exclamation mark + 'abc!def', # Letters with exclamation + '@', # At sign + 'abc@def', # Letters with at sign + '#', # Hash + 'abc#def', # Letters with hash + 'ä', # Umlaut + 'äbc', # Letters with umlaut + 'café', # Accented character + 'naïve', # Accented character + ) + self.assertInvalid(self.validator, data) + + +class IdStringValidatorTestCase(ValidatorTestMixin, SimpleTestCase): + validator = IdStringValidator + + def test_valid_data(self): + data = ( + '', # Empty string is valid + 'a', # Single lowercase letter + '0', # Single digit + 'abc', # Multiple lowercase letters + '123', # Multiple digits + '_', # Single underscore + '-', # Single hyphen + '.', # Single dot + 'abc123', # Lowercase letters and digits + 'a_b', # Underscore separator + 'a-b', # Hyphen separator + 'a.b', # Dot separator + 'user_name', # Underscore in middle + 'user-name', # Hyphen in middle + 'user.name', # Dot in middle + 'user_name_123', # Multiple underscores + 'user-name-123', # Multiple hyphens + 'user.name.123', # Multiple dots + 'mixed_name-with.numbers123', # Mixed separators + 'example.com', # Domain-like format + 'v1.0.0', # Version string + '2024-01-15', # Date-like format + 'snake_case', # Snake case convention + 'kebab-case', # Kebab case convention + 'dot.case', # Dot case convention + 'a1b2c3d4e5f6g7h8i9j0', # Alternating + 'test_123-abc.xyz', # Complex mixed format + '_leading_underscore', # Leading underscore + '-leading-hyphen', # Leading hyphen + '.leading-dot', # Leading dot + 'trailing_underscore_', # Trailing underscore + 'trailing-hyphen-', # Trailing hyphen + 'trailing.dot.', # Trailing dot + '___', # Multiple underscores only + '---', # Multiple hyphens only + '...', # Multiple dots only + 'a_b-c.d_e-f.g', # All separators mixed + ) + self.assertValid(self.validator, data) + + def test_invalid_data(self): + data = ( + 'A', # Uppercase letter + 'ABC', # Multiple uppercase letters + 'AbC', # Mixed case + 'ABC123', # Uppercase and digits + 'aBC123', # Mixed case (any uppercase) + ' ', # Space + 'abc ', # Trailing space + ' abc', # Leading space + 'a b c', # Space in the middle + 'a b-c', # Space mixed with valid chars + '@', # At sign + 'abc@def', # At sign in the middle + '#', # Hash + 'abc#def', # Hash in the middle + '$', # Dollar sign + 'abc$def', # Dollar in the middle + '%', # Percent + 'abc%def', # Percent in the middle + '&', # Ampersand + 'abc&def', # Ampersand in the middle + '*', # Asterisk + 'abc*def', # Asterisk in the middle + '+', # Plus + 'abc+def', # Plus in the middle + '=', # Equals + 'abc=def', # Equals in the middle + '/', # Slash + 'abc/def', # Slash in the middle + '\\', # Backslash + 'abc\\def', # Backslash in the middle + '?', # Question mark + 'abc?def', # Question mark in the middle + ':', # Colon + 'abc:def', # Colon in the middle + ';', # Semicolon + 'abc;def', # Semicolon in the middle + '"', # Double quote + 'abc"def', # Double quote in the middle + "'", # Single quote + "abc'def", # Single quote in the middle + '<', # Less than + 'abc', # Greater than + 'abc>def', # Greater than in the middle + '(', # Opening parenthesis + 'abc(def)', # Parentheses in the middle + '[', # Opening bracket + 'abc[def]', # Brackets in the middle + '{', # Opening brace + 'abc{def}', # Braces in the middle + '!', # Exclamation mark + 'abc!def', # Exclamation mark in the middle + ',', # Comma + 'abc,def', # Comma in the middle + 'ä', # Umlaut + 'äbc', # Letters with umlaut + 'café', # Accented character + 'naïve', # Accented character + '中文', # Chinese characters + 'русский', # Cyrillic characters + ) + self.assertInvalid(self.validator, data)