-
Notifications
You must be signed in to change notification settings - Fork 20
/
testing.py
282 lines (237 loc) · 9.26 KB
/
testing.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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
"LA unit test utility functions."
import numpy as np
from numpy.testing import assert_equal, assert_almost_equal
from la import larry
def assert_larry_equal(actual, desired, msg='', dtype=True, original=None,
iscopy=True):
"""
Assert equality of two larries or two scalars.
If either `actual` or `desired` has a dtype that is inexact, such as
float, then almost-equal is asserted; otherwise, equal is asserted.
However, if both `actual` and `desired` are scalars then almost-equal is
asserted.
Parameters
----------
actual : {larry, scalar}
If you are testing a larry method, for example, then this is the larry
(or scalar) returned by the method.
desired : {larry, scalar}
This larry represents the expected result. If `actual` is not equal
to `desired`, then an AssertionError will be raised.
msg : str
If `actual` is not equal to `desired`, then the string `msg` will
be added to the top of the AssertionError message.
dtype : {True, False}, optional
The default (True) is to assert that the dtype of `actual` is the
same as `desired`. If set to False, the dtype check is skipped.
original : {None, larry}, optional
If no `reference` or `nocopy` are True, then `original` must be a
larry. Continuing the example discussed in `actual`, `original` would
be the larry that was passed to the method.
iscopy : {True, False}, optional
Note: `iscopy` is ignored if `original` is None. If True (default) and
if `original` is not None, then check that `actual` and `desired`
share no references (i.e., are copies). If False and if `original` is
not None, then check that `actual` and `desired` are views of each
other (not copies).
Returns
-------
None
Raises
------
AssertionError
If the two larrys are not equal.
Notes
-----
If either `actual` or `desired` has a dtype that is inexact, such as
float, then almost-equal is asserted; otherwise, equal is asserted.
Examples
--------
>>> from la.util.testing import assert_larry_equal
>>> x = larry([1])
>>> y = larry([1.1], [['a']])
>>> assert_larry_equal(x, y, msg='x, y test')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "la/util/testing.py", line 189, in assert_larry_equal
raise AssertionError, err_msg
AssertionError:
---------------
TEST: x, y test
---------------
-----
LABEL
-----
Items are not equal:
item=0
item=0
ACTUAL: 0
DESIRED: 'a'
------------
X DATA ARRAY
------------
Arrays are not almost equal
(mismatch 100.0%)
x: array([1])
y: array([ 1.1])
-----
DTYPE
-----
Items are not equal:
ACTUAL: dtype('int64')
DESIRED: dtype('float64')
"""
# Initialize
fail = []
# Check input
if dtype not in (True, False):
raise TypeError('dtype must be True or False.')
if iscopy not in (True, False):
raise TypeError('iscopy must be True or False.')
if type(msg) is not str:
raise TypeError('msg must be a string.')
# Function to make section headings
def heading(text):
line = '-' * len(text)
return '\n\n' + line + '\n' + text + '\n' + line + '\n'
# The assert depends on the type of actual and desired
if np.isscalar(actual) and np.isscalar(desired):
# Both actual and desired are scalars
try:
assert_almost_equal(actual, desired)
except AssertionError as err:
fail.append(heading('SCALARS') + str(err))
if dtype:
try:
assert_equal(type(actual), type(desired))
except AssertionError as err:
fail.append(heading('TYPE') + str(err))
elif (type(actual) == larry) + (type(desired) == larry) == 1:
# Only one of actual and desired are larrys; test failed
try:
assert_equal(type(actual), type(desired))
except AssertionError as err:
fail.append(heading('TYPE') + str(err))
else:
# Both actual and desired are larrys
# label
try:
assert_equal(actual.label, desired.label)
except AssertionError as err:
fail.append(heading('LABEL') + str(err))
# Data array, x
try:
# Does one larrys have inexact dtype?
if (issubclass(actual.x.dtype.type, np.inexact) or
issubclass(desired.x.dtype.type, np.inexact)):
# Yes, so check for almost equal
try:
assert_almost_equal(actual.x, desired.x, decimal=13)
except TypeError:
# One of the larrys probably has a weird type like str
assert_equal(actual.x, desired.x)
else:
# No, so check for exactly equal
assert_equal(actual.x, desired.x)
except AssertionError as err:
fail.append(heading('X DATA ARRAY') + str(err))
# dtype
if dtype:
try:
assert_equal(actual.dtype, desired.dtype)
except AssertionError as err:
fail.append(heading('DTYPE') + str(err))
# If original is not None, assert copies or views
if not original is None:
if iscopy:
# Check that the larrys are copies
try:
assert_iscopy(actual, original)
except AssertionError as err:
fail.append(heading('NOT A COPY') + str(err))
else:
# Check that the larrys are views
try:
assert_isview(actual, original)
except AssertionError as err:
text = heading('IS A COPY') + str(err)
fail.append(text)
# Did the test pass?
if len(fail) > 0:
# No
err_msg = ''.join(fail)
err_msg = err_msg.replace('\n', '\n\t')
if len(msg):
err_msg = heading("TEST: " + msg) + err_msg
raise AssertionError(err_msg)
def assert_iscopy(larry1, larry2):
"Return True if there are no shared references"
if not isinstance(larry1, larry):
raise TypeError('Input must be a larry')
if not isinstance(larry2, larry):
raise TypeError('Input must be a larry')
msg = []
if np.may_share_memory(larry1.x, larry2.x):
msg.append('The data arrays share a reference.')
for i in xrange(min(larry1.ndim, larry2.ndim)):
if larry1.label[i] is larry2.label[i]:
msg.append('The labels along axis %d share a reference.' % i)
if len(msg) > 0:
msg.insert(0, '\n')
msg = '\n'.join(msg)
raise AssertionError(msg)
def assert_isview(larry1, larry2):
"Return True if there are only references"
if not isinstance(larry1, larry):
raise TypeError('Input must be a larry')
if not isinstance(larry2, larry):
raise TypeError('Input must be a larry')
msg = []
if not np.may_share_memory(larry1.x, larry2.x):
msg.append('The data arrays do not share a reference.')
for i in xrange(min(larry1.ndim, larry2.ndim)):
if larry1.label[i] is not larry2.label[i]:
text = 'The labels along axis %d does not share a reference.'
msg.append(text % i)
if len(msg) > 0:
msg.insert(0, '\n')
msg = '\n'.join(msg)
raise AssertionError(msg)
# Old-style testing functions -----------------------------------------------
def printfail(theory, practice, header=None):
x = []
if header is not None:
x.append('\n\n%s\n' % header)
x.append('\ntheory\n')
x.append(str(theory))
x.append('\n')
x.append('practice\n')
x.append(str(practice))
x.append('\n')
return ''.join(x)
def noreference(larry1, larry2):
"Return True if there are no shared references"
if not isinstance(larry1, larry):
raise TypeError('Input must be a larry')
if not isinstance(larry2, larry):
raise TypeError('Input must be a larry')
if larry1.ndim != larry2.ndim:
raise ValueError('larrys must have the same dimensions')
out = True
out = out & (larry1.x is not larry2.x)
for i in xrange(larry1.ndim):
out = out & (larry1.label[i] is not larry2.label[i])
return out
def nocopy(larry1, larry2):
"Return True if there are only references"
if not isinstance(larry1, larry):
raise TypeError('Input must be a larry')
if not isinstance(larry2, larry):
raise TypeError('Input must be a larry')
if larry1.ndim != larry2.ndim:
raise ValueError('larrys must have the same dimensions')
out = True
out = out & (larry1.x is larry2.x)
for i in xrange(larry1.ndim):
out = out & (larry1.label[i] is larry2.label[i])
return out