aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authornatsuoto <[email protected]>2026-07-15 16:56:09 +0530
committernatsuoto <[email protected]>2026-07-15 16:56:09 +0530
commit93371d459ad47a46310f729950ec383372cd2706 (patch)
treea669070a6a3225cc7a2e27ffc1a6e3d3807bee10 /tests
parent433d41bf5887e61cc570a874e244e226c25b8a41 (diff)
downloadedify-93371d459ad47a46310f729950ec383372cd2706.tar.xz
edify-93371d459ad47a46310f729950ec383372cd2706.zip
feat(integrations): edify[pydantic], edify[fastapi], edify[django] with deferred imports + Sphinx autodoc section + per-extra CI install verification
Diffstat (limited to 'tests')
-rw-r--r--tests/integrations/django.test.py60
-rw-r--r--tests/integrations/fastapi.test.py75
-rw-r--r--tests/integrations/pydantic.test.py67
3 files changed, 202 insertions, 0 deletions
diff --git a/tests/integrations/django.test.py b/tests/integrations/django.test.py
new file mode 100644
index 0000000..11aa835
--- /dev/null
+++ b/tests/integrations/django.test.py
@@ -0,0 +1,60 @@
+"""Tests for :mod:`edify.integrations.django`."""
+
+import sys
+
+import pytest
+
+from edify import Pattern
+from edify.errors.integration import MissingIntegrationDependencyError
+from edify.integrations.django import pattern_validator
+
+_DIGITS_PATTERN = Pattern().start_of_input().one_or_more().digit().end_of_input()
+
+
+def test_pattern_validator_returns_a_regex_validator_pinned_to_the_pattern_source():
+ from django.core.validators import RegexValidator
+
+ validator = pattern_validator(_DIGITS_PATTERN)
+ assert isinstance(validator, RegexValidator)
+ assert validator.regex.pattern == _DIGITS_PATTERN.to_regex_string()
+
+
+def test_pattern_validator_accepts_matching_input_without_raising():
+ validator = pattern_validator(_DIGITS_PATTERN)
+ validator("42")
+
+
+def test_pattern_validator_raises_django_validation_error_on_non_matching_input():
+ from django.core.exceptions import ValidationError
+
+ validator = pattern_validator(_DIGITS_PATTERN)
+ with pytest.raises(ValidationError):
+ validator("abc")
+
+
+def test_pattern_validator_carries_the_default_error_message_reproducing_the_regex():
+ validator = pattern_validator(_DIGITS_PATTERN)
+ assert _DIGITS_PATTERN.to_regex_string() in validator.message
+
+
+def test_pattern_validator_accepts_an_override_message_and_code():
+ validator = pattern_validator(_DIGITS_PATTERN, message="digits only", code="bad_digits")
+ assert validator.message == "digits only"
+ assert validator.code == "bad_digits"
+
+
+def test_pattern_validator_raises_missing_integration_when_django_absent(monkeypatch):
+ monkeypatch.setitem(sys.modules, "django", None)
+ monkeypatch.setitem(sys.modules, "django.core", None)
+ monkeypatch.setitem(sys.modules, "django.core.validators", None)
+ with pytest.raises(MissingIntegrationDependencyError, match="django"):
+ pattern_validator(_DIGITS_PATTERN)
+
+
+def test_missing_integration_error_carries_the_actionable_install_hint(monkeypatch):
+ monkeypatch.setitem(sys.modules, "django", None)
+ monkeypatch.setitem(sys.modules, "django.core", None)
+ monkeypatch.setitem(sys.modules, "django.core.validators", None)
+ with pytest.raises(MissingIntegrationDependencyError) as excinfo:
+ pattern_validator(_DIGITS_PATTERN)
+ assert "pip install edify[django]" in str(excinfo.value)
diff --git a/tests/integrations/fastapi.test.py b/tests/integrations/fastapi.test.py
new file mode 100644
index 0000000..636d78b
--- /dev/null
+++ b/tests/integrations/fastapi.test.py
@@ -0,0 +1,75 @@
+"""Tests for :mod:`edify.integrations.fastapi`."""
+
+import sys
+
+import pytest
+
+from edify import Pattern
+from edify.errors.integration import MissingIntegrationDependencyError
+from edify.integrations.fastapi import pattern_path, pattern_query
+
+_UUID_PATTERN = (
+ Pattern()
+ .start_of_input()
+ .exactly(8)
+ .any_of()
+ .range("0", "9")
+ .range("a", "f")
+ .end()
+ .end_of_input()
+)
+
+
+def test_pattern_query_returns_a_fastapi_query_pinned_to_the_pattern_regex():
+ query_default = pattern_query(_UUID_PATTERN)
+ fastapi_module = _fastapi()
+ assert type(query_default).__name__ == "Query" or isinstance(
+ query_default, fastapi_module.params.Query
+ )
+
+
+def test_pattern_query_forwards_extra_kwargs_to_fastapi_query():
+ query_with_description = pattern_query(_UUID_PATTERN, description="prefix")
+ assert query_with_description.description == "prefix"
+
+
+def test_pattern_query_default_differs_from_an_explicit_default():
+ without_default = pattern_query(_UUID_PATTERN)
+ with_default = pattern_query(_UUID_PATTERN, default="deadbeef")
+ assert without_default.default != with_default.default
+
+
+def test_pattern_query_respects_an_explicit_default_kwarg():
+ query_with_default = pattern_query(_UUID_PATTERN, default="deadbeef")
+ assert query_with_default.default == "deadbeef"
+
+
+def test_pattern_path_returns_a_fastapi_path_pinned_to_the_pattern_regex():
+ path_default = pattern_path(_UUID_PATTERN)
+ fastapi_module = _fastapi()
+ assert isinstance(path_default, fastapi_module.params.Path)
+
+
+def test_pattern_query_raises_missing_integration_when_fastapi_absent(monkeypatch):
+ monkeypatch.setitem(sys.modules, "fastapi", None)
+ with pytest.raises(MissingIntegrationDependencyError, match="fastapi"):
+ pattern_query(_UUID_PATTERN)
+
+
+def test_pattern_path_raises_missing_integration_when_fastapi_absent(monkeypatch):
+ monkeypatch.setitem(sys.modules, "fastapi", None)
+ with pytest.raises(MissingIntegrationDependencyError, match="fastapi"):
+ pattern_path(_UUID_PATTERN)
+
+
+def test_missing_integration_error_carries_the_actionable_install_hint(monkeypatch):
+ monkeypatch.setitem(sys.modules, "fastapi", None)
+ with pytest.raises(MissingIntegrationDependencyError) as excinfo:
+ pattern_query(_UUID_PATTERN)
+ assert "pip install edify[fastapi]" in str(excinfo.value)
+
+
+def _fastapi():
+ import fastapi
+
+ return fastapi
diff --git a/tests/integrations/pydantic.test.py b/tests/integrations/pydantic.test.py
new file mode 100644
index 0000000..da0ff2a
--- /dev/null
+++ b/tests/integrations/pydantic.test.py
@@ -0,0 +1,67 @@
+"""Tests for :mod:`edify.integrations.pydantic`."""
+
+import sys
+
+import pytest
+
+from edify import Pattern
+from edify.errors.integration import MissingIntegrationDependencyError
+from edify.integrations.pydantic import pattern_field, pattern_validator
+
+_DIGITS_PATTERN = Pattern().start_of_input().one_or_more().digit().end_of_input()
+
+
+def test_pattern_validator_accepts_a_matching_string_and_returns_it_unchanged():
+ validate = pattern_validator(_DIGITS_PATTERN)
+ assert validate("42") == "42"
+
+
+def test_pattern_validator_raises_value_error_on_non_matching_input():
+ validate = pattern_validator(_DIGITS_PATTERN)
+ with pytest.raises(ValueError, match="does not match"):
+ validate("abc")
+
+
+def test_pattern_field_returns_an_annotated_str_type_for_pydantic_models():
+ from typing import get_args, get_type_hints
+
+ from pydantic import AfterValidator, BaseModel
+
+ class Payload(BaseModel):
+ value: pattern_field(_DIGITS_PATTERN)
+
+ resolved = get_type_hints(Payload, include_extras=True)["value"]
+ metadata = get_args(resolved)[1:]
+ assert any(isinstance(item, AfterValidator) for item in metadata)
+
+
+def test_pattern_field_is_accepted_by_pydantic_model_validation():
+ from pydantic import BaseModel, ValidationError
+
+ class Payload(BaseModel):
+ value: pattern_field(_DIGITS_PATTERN)
+
+ assert Payload(value="42").value == "42"
+ with pytest.raises(ValidationError):
+ Payload(value="abc")
+
+
+def test_pattern_validator_raises_missing_integration_when_pydantic_absent(monkeypatch):
+ monkeypatch.setitem(sys.modules, "pydantic", None)
+ with pytest.raises(MissingIntegrationDependencyError, match="pydantic"):
+ pattern_validator(_DIGITS_PATTERN)
+
+
+def test_pattern_field_raises_missing_integration_when_pydantic_absent(monkeypatch):
+ monkeypatch.setitem(sys.modules, "pydantic", None)
+ with pytest.raises(MissingIntegrationDependencyError, match="pydantic"):
+ pattern_field(_DIGITS_PATTERN)
+
+
+def test_missing_integration_error_carries_the_actionable_install_hint(monkeypatch):
+ monkeypatch.setitem(sys.modules, "pydantic", None)
+ with pytest.raises(MissingIntegrationDependencyError) as excinfo:
+ pattern_validator(_DIGITS_PATTERN)
+ text = str(excinfo.value)
+ assert "pip install edify[pydantic]" in text
+ assert "= note:" in text