Skip to main content

tests/test_validate_type.py

1"""
2Tests for ``javascript_data_files.validate_type``.
3"""
5import typing
7import pytest
8from pydantic import ValidationError
10from javascript_data_files.validate_type import validate_type
13Shape = typing.TypedDict("Shape", {"colour": str, "sides": int})
14Circle = typing.TypedDict("Circle", {"colour": str, "radius": int})
17@pytest.mark.parametrize(
18 "data",
19 [
20 {"colour": "red"},
21 {"sides": 4},
22 {"colour": "red", "sides": "four"},
23 {"colour": (255, 0, 0), "sides": 4},
24 {"colour": "red", "sides": 4, "angle": 36},
25 ],
27def test_validate_type_flags_incorrect_data(data: typing.Any) -> None:
28 """
29 If you pass data that doesn't match the model to ``validate_type``,
30 it throws a ``ValidationError``.
31 """
32 with pytest.raises(ValidationError):
33 validate_type(data, model=Shape)
36def test_validate_type_allows_valid_data() -> None:
37 """
38 If you pass data which matches the model to ``validate_type``,
39 it passes without exception.
40 """
41 validate_type({"colour": "red", "sides": 4}, model=Shape)
44def test_validate_type_supports_builtin_list() -> None:
45 """
46 You can validate a list with ``validate_type``.
47 """
48 validate_type([1, 2, 3], model=list[int])
51def test_validate_type_supports_builtin_type() -> None:
52 """
53 You can validate a list with ``validate_type``.
54 """
55 validate_type(1, model=int)
58@pytest.mark.parametrize(
59 "data", [{"colour": "red", "sides": 4}, {"colour": "blue", "radius": 3}]
61def test_validate_type_supports_union_type(data: typing.Any) -> None:
62 """
63 You can validate a type which is a union of two TypedDict's.
64 """
65 validate_type(data, model=Shape | Circle) # type: ignore
68@pytest.mark.parametrize(
69 "data",
70 [
71 {"colour": "red", "sides": 4, "name": "square"},
72 {"colour": "red", "sides": 4, "stroke": "black", "depth": 3},
73 ],
75def test_validate_type_rejects_extra_fields(data: typing.Any) -> None:
76 """
77 Adding extra keys to a TypedDict is a validation error.
78 """
79 with pytest.raises(ValidationError):
80 validate_type(data, model=Shape)
83@pytest.mark.parametrize(
84 "data",
85 [
86 {"colour": "red", "sides": 4, "name": "square"},
87 {"colour": "red", "sides": 4, "stroke": "black", "depth": 3},
88 ],
90def test_validate_type_of_union_rejects_extra_fields(data: typing.Any) -> None:
91 """
92 Adding extra keys to a Union of TypedDict's is a validation error.
93 """
94 with pytest.raises(ValidationError):
95 validate_type(data, model=Shape | Circle) # type: ignore
98def test_validate_type_does_not_change_data() -> None:
99 """
100 Check that ``validate_type`` does not change the value, merely make
101 assertions about the type.
103 This is a regression test for a bug I encountered in my bookmarks
104 project -- notice that `s` does not really conform to either type.
106 * If it's UncolouredShape, it shouldn't have a "type"
107 * If it's ColouredShape, it should have a "colour"
109 This appears to be caused by a bug in Pydantic, see
110 https://github.com/pydantic/pydantic/issues/11328
112 """
114 class UncolouredShape(typing.TypedDict):
115 sides: int
117 class ColouredShape(typing.TypedDict):
118 sides: str
119 colour: str
120 type: typing.Literal["coloured_shape"]
122 Shape = UncolouredShape | ColouredShape
124 s = {
125 "sides": 5,
126 "type": "coloured_shape",
127 }
129 with pytest.raises(ValidationError):
130 assert validate_type(s, model=Shape) == s # type: ignore