-
-
Notifications
You must be signed in to change notification settings - Fork 359
/
test_converters.py
162 lines (122 loc) · 3.78 KB
/
test_converters.py
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""
Tests for `attr.converters`.
"""
from __future__ import absolute_import
import pytest
import attr
from attr import Factory, attrib
from attr.converters import default_if_none, optional, pipe, to_bool
class TestOptional(object):
"""
Tests for `optional`.
"""
def test_success_with_type(self):
"""
Wrapped converter is used as usual if value is not None.
"""
c = optional(int)
assert c("42") == 42
def test_success_with_none(self):
"""
Nothing happens if None.
"""
c = optional(int)
assert c(None) is None
def test_fail(self):
"""
Propagates the underlying conversion error when conversion fails.
"""
c = optional(int)
with pytest.raises(ValueError):
c("not_an_int")
class TestDefaultIfNone(object):
def test_missing_default(self):
"""
Raises TypeError if neither default nor factory have been passed.
"""
with pytest.raises(TypeError, match="Must pass either"):
default_if_none()
def test_too_many_defaults(self):
"""
Raises TypeError if both default and factory are passed.
"""
with pytest.raises(TypeError, match="but not both"):
default_if_none(True, lambda: 42)
def test_factory_takes_self(self):
"""
Raises ValueError if passed Factory has takes_self=True.
"""
with pytest.raises(ValueError, match="takes_self"):
default_if_none(Factory(list, takes_self=True))
@pytest.mark.parametrize("val", [1, 0, True, False, "foo", "", object()])
def test_not_none(self, val):
"""
If a non-None value is passed, it's handed down.
"""
c = default_if_none("nope")
assert val == c(val)
c = default_if_none(factory=list)
assert val == c(val)
def test_none_value(self):
"""
Default values are returned when a None is passed.
"""
c = default_if_none(42)
assert 42 == c(None)
def test_none_factory(self):
"""
Factories are used if None is passed.
"""
c = default_if_none(factory=list)
assert [] == c(None)
c = default_if_none(default=Factory(list))
assert [] == c(None)
class TestPipe(object):
def test_success(self):
"""
Succeeds if all wrapped converters succeed.
"""
c = pipe(str, to_bool, bool)
assert True is c("True") is c(True)
def test_fail(self):
"""
Fails if any wrapped converter fails.
"""
c = pipe(str, to_bool)
# First wrapped converter fails:
with pytest.raises(ValueError):
c(33)
# Last wrapped converter fails:
with pytest.raises(ValueError):
c("33")
def test_sugar(self):
"""
`pipe(c1, c2, c3)` and `[c1, c2, c3]` are equivalent.
"""
@attr.s
class C(object):
a1 = attrib(default="True", converter=pipe(str, to_bool, bool))
a2 = attrib(default=True, converter=[str, to_bool, bool])
c = C()
assert True is c.a1 is c.a2
class TestToBool(object):
def test_unhashable(self):
"""
Fails if value is unhashable.
"""
with pytest.raises(ValueError, match="Cannot convert value to bool"):
to_bool([])
def test_truthy(self):
"""
Fails if truthy values are incorrectly converted.
"""
assert to_bool("t")
assert to_bool("yes")
assert to_bool("on")
def test_falsy(self):
"""
Fails if falsy values are incorrectly converted.
"""
assert not to_bool("f")
assert not to_bool("no")
assert not to_bool("off")