aboutsummaryrefslogtreecommitdiff
path: root/tests/integrations/pydantic.test.py
blob: a3c31646a5de17d9a0a2856dcd2e01523bd644f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
"""Tests for :mod:`edify.integrations.pydantic`."""

from typing import Annotated

import pytest
from pydantic import AfterValidator, BaseModel, ValidationError

from edify import Pattern
from edify.errors.integration import PatternDidNotMatchError
from edify.integrations.pydantic import 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_pattern_did_not_match_on_non_matching_input():
    validate = pattern_validator(_DIGITS_PATTERN)
    with pytest.raises(PatternDidNotMatchError, match="does not match"):
        validate("abc")


def test_pattern_did_not_match_error_is_a_value_error_subclass():
    assert issubclass(PatternDidNotMatchError, ValueError)


def test_pattern_did_not_match_error_carries_source_and_value():
    validate = pattern_validator(_DIGITS_PATTERN)
    with pytest.raises(PatternDidNotMatchError) as excinfo:
        validate("abc")
    assert excinfo.value.source == _DIGITS_PATTERN.to_regex_string()
    assert excinfo.value.value == "abc"


def test_pattern_validator_composes_into_pydantic_model_field_via_annotated_after_validator():
    validator_callable = pattern_validator(_DIGITS_PATTERN)

    class Payload(BaseModel):
        value: Annotated[str, AfterValidator(validator_callable)]

    assert Payload(value="42").value == "42"
    with pytest.raises(ValidationError):
        Payload(value="abc")