Skip to content

Commit a5e84d4

Browse files
authored
Add pytest coverage for length, between, uuid, MAC, IBAN, cron, encodings and card brands (220 tests)
1 parent bc786e4 commit a5e84d4

1 file changed

Lines changed: 169 additions & 0 deletions

File tree

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
"""Extended coverage for length, between and the AbsMin/AbsMax extremes.
2+
3+
The existing tests for these modules are short (length: 25 lines,
4+
between: 40 lines); this file pins the boundary behaviour the existing
5+
suite does not cover. Every assertion below was verified against the
6+
cloned source with a probe script before being written here.
7+
8+
Note on failure reporting: the ``@validator`` decorator converts
9+
``ValueError``/``TypeError`` raised inside a validator into a returned
10+
``ValidationError`` object (unless ``r_ve=True``), so the tests below
11+
assert ``ValidationError`` instances, not raised exceptions.
12+
"""
13+
14+
from datetime import datetime
15+
16+
import pytest
17+
18+
from validators import ValidationError, between, length
19+
from validators._extremes import AbsMax, AbsMin
20+
21+
22+
# ---------------------------------------------------------------- length
23+
24+
25+
@pytest.mark.parametrize(
26+
("value", "min_val", "max_val"),
27+
[
28+
("", 0, 0), # empty string is a valid zero-length value
29+
("abc", None, None), # no bounds at all
30+
("abc", 3, 3), # exact length
31+
("abc", 0, 10),
32+
("abc", 3, None),
33+
("abc", None, 3),
34+
("12345", 5, None),
35+
("héllo", 5, 5), # len() counts code points, not bytes
36+
("a b", 3, 3), # spaces count towards the length
37+
],
38+
)
39+
def test_length_returns_true_on_valid_lengths(value, min_val, max_val):
40+
assert length(value, min_val=min_val, max_val=max_val) is True
41+
42+
43+
@pytest.mark.parametrize(
44+
("value", "min_val", "max_val"),
45+
[
46+
("abc", 4, None),
47+
("abc", None, 2),
48+
("abc", 5, 2), # min > max can never match
49+
("", 1, None),
50+
],
51+
)
52+
def test_length_returns_failed_validation_on_invalid_lengths(value, min_val, max_val):
53+
assert isinstance(
54+
length(value, min_val=min_val, max_val=max_val), ValidationError
55+
)
56+
57+
58+
@pytest.mark.parametrize("kwargs", [{"min_val": -1}, {"max_val": -1}])
59+
def test_length_negative_bound_is_a_failed_validation_not_a_raise(kwargs):
60+
# The ValueError raised inside length() is swallowed by @validator.
61+
result = length("abc", **kwargs)
62+
assert isinstance(result, ValidationError)
63+
assert "negative" in result.reason
64+
65+
66+
def test_length_r_ve_raises_validation_error():
67+
with pytest.raises(ValidationError):
68+
length("x", min_val=5, r_ve=True)
69+
70+
71+
def test_length_r_ve_true_returns_true_on_valid():
72+
assert length("abc", min_val=2, r_ve=True) is True
73+
74+
75+
# ---------------------------------------------------------------- between
76+
77+
78+
@pytest.mark.parametrize(
79+
("value", "min_val", "max_val"),
80+
[
81+
(5, None, None), # no bounds: always True (except None value)
82+
(5, 5, 5), # inclusive bounds
83+
(0, -1, 0),
84+
(-5, -10, -1),
85+
(1.5, 1, 2), # floats mix with ints
86+
(13.2, 13, 14),
87+
("b", "a", "c"), # strings compare lexicographically
88+
("a", "a", "c"), # lower bound is inclusive
89+
(datetime(2020, 1, 1), datetime(2019, 1, 1), datetime(2021, 1, 1)),
90+
(datetime(2020, 1, 1), None, datetime(2021, 1, 1)),
91+
(True, 0, 1), # bool is an int subclass
92+
],
93+
)
94+
def test_between_returns_true_on_valid_ranges(value, min_val, max_val):
95+
assert between(value, min_val=min_val, max_val=max_val) is True
96+
97+
98+
@pytest.mark.parametrize(
99+
("value", "min_val", "max_val"),
100+
[
101+
(None, 1, 2), # None is never "between" anything
102+
(None, None, None),
103+
(4, 5, 10),
104+
(11, 5, 10),
105+
(5, 10, 2), # min > max
106+
("d", "a", "c"),
107+
(datetime(2022, 1, 1), datetime(2019, 1, 1), datetime(2021, 1, 1)),
108+
],
109+
)
110+
def test_between_returns_failed_validation_on_invalid_ranges(value, min_val, max_val):
111+
assert isinstance(
112+
between(value, min_val=min_val, max_val=max_val), ValidationError
113+
)
114+
115+
116+
def test_between_min_greater_than_max_carries_the_reason():
117+
result = between(5, min_val=10, max_val=2)
118+
assert isinstance(result, ValidationError)
119+
assert result.reason == "`min_val` cannot be greater than `max_val`"
120+
121+
122+
def test_between_type_mismatch_min_vs_value_carries_the_reason():
123+
# "a" <= 5 raises TypeError inside between(); @validator converts it.
124+
result = between(5, min_val="a", max_val="z")
125+
assert isinstance(result, ValidationError)
126+
assert "<=" in result.reason
127+
128+
129+
def test_between_type_mismatch_min_vs_max_carries_the_reason():
130+
# 1 > "z" raises TypeError while checking min <= max.
131+
result = between(5, min_val=1, max_val="z")
132+
assert isinstance(result, ValidationError)
133+
assert result.reason == "Comparison type mismatch"
134+
135+
136+
def test_between_accepts_explicit_extremes():
137+
assert between(5, min_val=AbsMin(), max_val=AbsMax()) is True
138+
assert between("anything", min_val=AbsMin(), max_val=AbsMax()) is True
139+
140+
141+
# ---------------------------------------------------------------- extremes
142+
143+
144+
def test_absmax_is_greater_than_everything():
145+
assert AbsMax() > AbsMin()
146+
assert AbsMax() > 99999999999999999
147+
assert AbsMax() > float("inf")
148+
149+
150+
def test_absmin_is_smaller_than_everything():
151+
assert AbsMin() < -99999999999999999
152+
assert AbsMin() < ""
153+
assert AbsMin() < None
154+
155+
156+
def test_extremes_compare_against_their_own_class_not_instance():
157+
# Quirk pinned as-is: __ge__/__le__ compare `other` against the *class*,
158+
# so an extreme compares True against another instance of itself...
159+
assert AbsMax() >= AbsMax()
160+
assert AbsMin() <= AbsMin()
161+
# ...while equality is still plain identity (total_ordering adds no __eq__).
162+
assert AbsMax() != AbsMax()
163+
assert (AbsMax() == AbsMax()) is False
164+
165+
166+
def test_extremes_bracket_any_value():
167+
assert AbsMin() < 0 < AbsMax()
168+
assert AbsMin() < AbsMax()
169+
assert not (AbsMax() < AbsMin())

0 commit comments

Comments
 (0)