initiating django package from a work in progress lib

This commit is contained in:
2026-10-06 15:03:00 +02:00
parent 43fa94e6b0
commit 8d8acd052e
22 changed files with 1848 additions and 1 deletions

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
# Test configuration package

66
tests/settings.py Normal file
View File

@ -0,0 +1,66 @@
"""
Django settings for testing django-courriel package.
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
SECRET_KEY = 'test-secret-key-for-django-courriel-testing-only'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django_courriel',
]
MIDDLEWARE = []
ROOT_URLCONF = ''
# Database
# https://docs.djangoproject.com/en/6.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}
# Internationalization
USE_I18N = True
USE_TZ = True
# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Django templates
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'django_courriel', 'templates'),
os.path.join(BASE_DIR, 'tests', 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [],
},
},
]
# Markdown email settings
MARKDOWN_EMAIL_EXTENSIONS = ['extra', 'nl2br']
MARKDOWN_EMAIL_DEFAULT_LAYOUT = 'courriel/base.dj.html'
# Use in-memory storage for testing
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

View File

@ -0,0 +1,4 @@
---
subject is invalid
---
This shall raise a InvalidFrontMatter exception

View File

@ -0,0 +1,4 @@
---
subject: "Hello"
---
Hello world !

View File

@ -0,0 +1,2 @@
# Gabarit sans front matter délimité
Ce fichier n'a pas de front matter valide.

View File

@ -0,0 +1,5 @@
---
to: "test@example.com"
cc: "another@example.com"
---
This shall raise a MissingSubject exception

View File

@ -0,0 +1,8 @@
---
subject: "Notification de groupe"
to_groups:
- "managers"
cc:
- "{{ extra_email }}"
---
Message envoyé au groupe.

View File

@ -0,0 +1,5 @@
---
subject: "Notification pour {{ missing_user }}"
to: "test@example.com"
---
Corps de test.

View File

@ -0,0 +1,5 @@
---
subject: "Sujet présent"
to: "{{ missing_recipient }}"
---
Corps de test.

View File

@ -0,0 +1,14 @@
---
subject: "Bienvenue à la session {{ session_title }}"
to: "{{ recipient_email }}"
reply_to: "contact@gobelins.fr"
format: both
---
# Formation {{ session_title }}
Bonjour {{ recipient_name }},
Voici le programme :
{% for item in items %}
* {{ item }}
{% endfor %}

View File

@ -0,0 +1,6 @@
---
subject: "Notification inexistante"
to_groups:
- "inexistant"
---
Message.

View File

@ -0,0 +1,6 @@
---
subject: "Sujet présent"
to: "{{ recipient_email }}"
reply_to: "{{ missing_reply_to }}"
---
Corps de test.

16
tests/test_md.py Normal file
View File

@ -0,0 +1,16 @@
from django.test import SimpleTestCase
class MarkdownTemplateTest(SimpleTestCase):
def test_init(self):
raise NotImplementedError()
def test_minimal(self):
raise NotImplementedError()
def test_subject_rendering(self):
raise NotImplementedError()
def test_addresses(self):
raise NotImplementedError()

155
tests/test_validation.py Normal file
View File

@ -0,0 +1,155 @@
from email.headerregistry import Address
from django.test import SimpleTestCase
from django_courriel.validation import (
CourrielError,
InvalidAddressError,
InvalidRecipientsError,
InvalidSenderError,
ValidAddress,
ValidAddressList,
)
# test data
valid_inputs = (
ValidAddress('Boris Vian', 'boris', 'vian.jazz'),
'antoine@saint-exupery.aero',
Address('Savinien de Cyrano', 'savinien', 'cyrano.lune'),
'Aimé Césaire <cesaire@cahiers.net>',
'Victor Hugo <victor-hugo@les-misérables.fr>',
)
invalid_inputs = (
Address(),
Address('Charles Baudelaire'),
Address('Charles', 'charles', 'les fleurs du mal'),
'Vernon Sullivan',
'simone@bovary',
)
class TestValidAddress(SimpleTestCase):
def setUp(self) -> None:
self.invalid_specs = [
'boris@vian',
'bad adress',
]
def test_interface(self):
""" respects parent email.headerregistry.Address interface """
try:
a = ValidAddress('Boris Vian', 'boris', 'vian.jazz')
self.assertEqual(a.display_name, 'Boris Vian')
self.assertEqual(a.addr_spec, 'boris@vian.jazz')
self.assertEqual(a.username, 'boris')
self.assertEqual(a.domain, 'vian.jazz')
self.assertEqual(str(a), 'Boris Vian <boris@vian.jazz>')
except Exception as e:
self.fail(f"should not have raised {e}")
with self.assertRaises(AttributeError): # should not be mutable
a.addr_spec = "<vernon@affreux.org>"
def test_new(self):
""" __new__ shall raise InvalidAddress errors """
with self.assertRaises(InvalidAddressError):
ValidAddress()
with self.assertRaises(InvalidAddressError):
ValidAddress('Simone Veil')
with self.assertRaises(InvalidAddressError):
ValidAddress(username='Simone Veil', domain='cafe.philo')
with self.assertRaises(InvalidAddressError):
ValidAddress(username='simone', domain='veil')
# some more bad specs
for spec in self.invalid_specs:
with self.assertRaises(InvalidAddressError):
ValidAddress(addr_spec=spec)
def test_factory(self):
""" builder from string or Address """
# invalid cases
inputs = self.invalid_specs + [None, Address()]
for input in inputs:
with self.assertRaises(InvalidAddressError):
ValidAddress.factory(input)
# valid cases
try:
a = ValidAddress.factory('antoine@saint-exupery.aero')
self.assertEqual(a.addr_spec, 'antoine@saint-exupery.aero')
a = ValidAddress.factory('"Victor Hugo" <hugo@miserables.paris>')
self.assertEqual(a.display_name, 'Victor Hugo')
self.assertEqual(a.addr_spec, 'hugo@miserables.paris')
# from an address
old = Address(display_name='Savinien de Cyrano', username='savinien', domain='cyrano.lune')
a = ValidAddress.factory(old)
self.assertEqual(str(a), 'Savinien de Cyrano <savinien@cyrano.lune>')
except InvalidAddressError as e:
self.fail(f"should not have raised {e}")
class TestValidAddressList(SimpleTestCase):
def setUp(self) -> None:
self.test_list = ValidAddressList()
def test__init(self):
# valid values
try:
ValidAddressList()
ValidAddressList(['victor@hugo.paris', 'Aimé Césaire <cesaire@cahiers.net>'])
except InvalidAddressError as e:
self.fail(f"should not have raised {e}")
# invalid values
with self.assertRaises(InvalidAddressError):
ValidAddressList(['invalid@address'])
def test_append(self):
# valid values
try:
for i in valid_inputs:
self.test_list.append(i)
except InvalidAddressError as e:
self.fail(f"should not have raised {e} when appending {i}")
# invalid values
for i in invalid_inputs:
with self.assertRaises(InvalidAddressError):
self.test_list.append(i)
# checking conversions
for item in self.test_list:
self.assertIsInstance(item, ValidAddress)
def test_insert(self):
for i in valid_inputs:
try:
self.test_list.insert(0, i)
except InvalidAddressError as e:
self.fail(f"should not have raised {e} when inserting {i}")
for i in invalid_inputs:
with self.assertRaises(InvalidAddressError):
self.test_list.insert(0, i)
# checking conversions
for item in self.test_list:
self.assertIsInstance(item, ValidAddress)
def test_set_item(self):
# cannot set item on empty list !?
self.test_list = ValidAddressList(['virginie@subutex.livre'])
for i in valid_inputs:
try:
self.test_list[0] = i
except InvalidAddressError as e:
self.fail(f"should not have raised {e} when inserting {i}")
for i in invalid_inputs:
with self.assertRaises(InvalidAddressError):
self.test_list[0] = i
# checking conversions
for item in self.test_list:
self.assertIsInstance(item, ValidAddress)
def test_extend(self):
try:
self.test_list.extend(valid_inputs)
except InvalidAddressError as e:
self.fail(f"should not have raised {e} when extending {valid_inputs}")
with self.assertRaises(InvalidAddressError):
self.test_list.extend(invalid_inputs)