1
+ """A small unit testing library for Python."""
2
+
3
+ from typing import Callable , Tuple , Iterable , Type , Any
4
+
5
+ __all__ = [
6
+ "equals" ,
7
+ "not_equals" ,
8
+ "expect" ,
9
+ "raises" ,
10
+ "does_not_raise" ,
11
+ "approximately_equals" ,
12
+ "not_approximately_equals" ,
13
+ "contains" ,
14
+ "does_not_contain" ,
15
+ "is_instance" ,
16
+ "not_is_instance" ,
17
+ "greater" ,
18
+ "less" ,
19
+ ]
20
+
21
+ def equals (
22
+ a : Any ,
23
+ b : Any ,
24
+ message_on_fail : str = "Test failed" ,
25
+ verbose : bool = False ,
26
+ ) -> None :
27
+ """
28
+ Assertion of strict equality.
29
+
30
+ :param a: The first value being compared.
31
+ :param b: The second value being compared.
32
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
33
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
34
+ """
35
+
36
+ if verbose and a == b :
37
+ print ("Test passed" )
38
+
39
+ elif a != b :
40
+ raise AssertionError (message_on_fail + f": expected { a } to equal { b } " )
41
+
42
+ def not_equals (
43
+ a : Any ,
44
+ b : Any ,
45
+ message_on_fail : str = "Test failed" ,
46
+ verbose : bool = False ,
47
+ ) -> None :
48
+ """
49
+ Assertion of strict inequality.
50
+
51
+ :param a: The first value being compared.
52
+ :param b: The second value being compared.
53
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
54
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
55
+ """
56
+
57
+ if verbose and a != b :
58
+ print ("Test passed" )
59
+
60
+ elif a == b :
61
+ raise AssertionError (message_on_fail + f": expected { a } to not equal { b } " )
62
+
63
+ def expect (
64
+ value : Any ,
65
+ message_on_fail : str = "Test failed" ,
66
+ verbose : bool = False ,
67
+ ) -> None :
68
+ """
69
+ Assertion of truthiness.
70
+
71
+ :param value: The value being tested.
72
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
73
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
74
+ """
75
+
76
+ if verbose and value :
77
+ print ("Test passed" )
78
+
79
+ elif not value :
80
+ raise AssertionError (message_on_fail )
81
+
82
+
83
+ # noinspection PyBroadException
84
+ def raises (
85
+ function : Callable [..., Any ],
86
+ exceptions : Tuple [Type [BaseException ], ...] | Type [BaseException ] = (Exception ,),
87
+ message_on_fail = "Test failed" ,
88
+ verbose = False ,
89
+ ) -> None :
90
+ """
91
+ Assertion of a function raising an exception.
92
+
93
+ :param function: The function being tested.
94
+ :param exceptions: The exception type(s) being tested. Default value is (Exception,).
95
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
96
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
97
+ """
98
+
99
+ if not isinstance (exceptions , tuple ):
100
+ exceptions = (exceptions ,)
101
+
102
+ def handle ():
103
+ raise AssertionError (
104
+ message_on_fail
105
+ + ": expected given function to raise "
106
+ + ("" if len (exceptions ) == 1 else "any of the following: " )
107
+ + ", " .join (map (lambda e : e .__name__ , exceptions ))
108
+ )
109
+
110
+ try :
111
+ function ()
112
+
113
+ except exceptions :
114
+ if verbose :
115
+ print ("Test passed" )
116
+
117
+ return None
118
+
119
+ except :
120
+ # handle cases when the exception is not of the expected type
121
+ handle ()
122
+
123
+ else :
124
+ handle ()
125
+
126
+
127
+ # noinspection PyBroadException
128
+ def does_not_raise (
129
+ function : Callable [..., Any ],
130
+ exceptions : Tuple [Type [BaseException ], ...] | Type [BaseException ] = (Exception ,),
131
+ message_on_fail : str = "Test failed" ,
132
+ verbose : bool = False ,
133
+ ) -> None :
134
+ """
135
+ Assertion of a function not raising an exception.
136
+
137
+ :param function: The function being tested.
138
+ :param exceptions: The exception type(s) being tested. Default value is (Exception,).
139
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
140
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
141
+ """
142
+
143
+ if not isinstance (exceptions , tuple ):
144
+ exceptions = (exceptions ,)
145
+
146
+ def handle ():
147
+ raise AssertionError (
148
+ message_on_fail
149
+ + ": expected given function to not raise "
150
+ + ("" if len (exceptions ) == 1 else "any of the following: " )
151
+ + ", " .join (map (lambda e : e .__name__ , exceptions ))
152
+ )
153
+
154
+ try :
155
+ function ()
156
+
157
+ except exceptions :
158
+ handle ()
159
+
160
+ except :
161
+ # handle cases when the exception is not of the expected type
162
+ if verbose :
163
+ print ("Test passed" )
164
+
165
+ else :
166
+ if verbose :
167
+ print ("Test passed" )
168
+
169
+ def approximately_equals (
170
+ a : int | float ,
171
+ b : int | float ,
172
+ margin : int | float ,
173
+ message_on_fail : str = "Test failed" ,
174
+ verbose : bool = False ,
175
+ ) -> None :
176
+ """
177
+ Assertion of approximate equality.
178
+
179
+ :param a: The first value being compared.
180
+ :param b: The second value being compared.
181
+ :param margin: The margin of error allowed for the comparison.
182
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
183
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
184
+ """
185
+
186
+ if verbose and abs (a - b ) <= margin :
187
+ print ("Test passed" )
188
+
189
+ elif abs (a - b ) > margin :
190
+ raise AssertionError (message_on_fail + f": expected { a } to be within { margin } of { b } " )
191
+
192
+ def not_approximately_equals (
193
+ a : int | float ,
194
+ b : int | float ,
195
+ margin : int | float ,
196
+ message_on_fail : str = "Test failed" ,
197
+ verbose : bool = False ,
198
+ ) -> None :
199
+ """
200
+ Assertion of approximate inequality.
201
+
202
+ :param a: The first value being compared.
203
+ :param b: The second value being compared.
204
+ :param margin: The margin of error allowed for the comparison.
205
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
206
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
207
+ """
208
+
209
+ if verbose and abs (a - b ) > margin :
210
+ print ("Test passed" )
211
+
212
+ elif abs (a - b ) <= margin :
213
+ raise AssertionError (message_on_fail + f": expected { a } to not be within { margin } of { b } " )
214
+
215
+ def contains (
216
+ it : Iterable [Any ],
217
+ value : Any ,
218
+ message_on_fail : str = "Test failed" ,
219
+ verbose : bool = False ,
220
+ ) -> None :
221
+ """
222
+ Assertion of the given iterable containing the given value.
223
+
224
+ :param it: The iterable being tested.
225
+ :param value: The value being tested for containment.
226
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
227
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
228
+ """
229
+
230
+ if verbose and value in it :
231
+ print ("Test passed" )
232
+
233
+ elif value not in it :
234
+ raise AssertionError (message_on_fail + f": expected { value } to be in { it } " )
235
+
236
+ def does_not_contain (
237
+ it : Iterable [Any ],
238
+ value : Any ,
239
+ message_on_fail : str = "Test failed" ,
240
+ verbose : bool = False ,
241
+ ) -> None :
242
+ """
243
+ Assertion of the given iterable not containing the given value.
244
+
245
+ :param it: The iterable being tested.
246
+ :param value: The value being tested for containment.
247
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
248
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
249
+ """
250
+
251
+ if verbose and value not in it :
252
+ print ("Test passed" )
253
+
254
+ elif value in it :
255
+ raise AssertionError (message_on_fail + f": expected { value } to not be in { it } " )
256
+
257
+ def is_instance (
258
+ value : Any ,
259
+ types : Type [Any ] | Tuple [Type [Any ], ...],
260
+ message_on_fail : str = "Test failed" ,
261
+ verbose : bool = False ,
262
+ ) -> None :
263
+ """
264
+ Assertion of the given value being an instance of the given type(s) or class(es).
265
+
266
+ :param value: The value being tested.
267
+ :param types: The type(s) or class(es) being tested.
268
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
269
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
270
+ """
271
+ if not isinstance (types , tuple ):
272
+ types = (types ,)
273
+
274
+ if verbose and isinstance (value , types ):
275
+ print ("Test passed" )
276
+
277
+ elif not isinstance (value , types ):
278
+ raise AssertionError (message_on_fail + f": expected { value } to be an instance of { types } " )
279
+
280
+ def not_is_instance (
281
+ value : Any ,
282
+ types : Type [Any ] | Tuple [Type [Any ], ...],
283
+ message_on_fail : str = "Test failed" ,
284
+ verbose : bool = False ,
285
+ ) -> None :
286
+ """
287
+ Assertion of the given value not being an instance of the given type(s) or class(es).
288
+
289
+ :param value: The value being tested.
290
+ :param types: The type(s) or class(es) being tested.
291
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
292
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
293
+ """
294
+ if not isinstance (types , tuple ):
295
+ types = (types ,)
296
+
297
+ if verbose and not isinstance (value , types ):
298
+ print ("Test passed" )
299
+
300
+ elif isinstance (value , types ):
301
+ raise AssertionError (message_on_fail + f": expected { value } to not be an instance of { types } " )
302
+
303
+ def greater (
304
+ value : int | float ,
305
+ comparison : int | float ,
306
+ message_on_fail : str = "Test failed" ,
307
+ verbose : bool = False ,
308
+ ) -> None :
309
+ """
310
+ Assertion of the given value being greater than the given comparison value.
311
+
312
+ :param value: The value being tested.
313
+ :param comparison: The comparison value.
314
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
315
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
316
+ """
317
+
318
+ if verbose and value > comparison :
319
+ print ("Test passed" )
320
+
321
+ elif value <= comparison :
322
+ raise AssertionError (message_on_fail + f": expected { value } to be greater than { comparison } " )
323
+
324
+ def less (
325
+ value : int | float ,
326
+ comparison : int | float ,
327
+ message_on_fail : str = "Test failed" ,
328
+ verbose : bool = False ,
329
+ ) -> None :
330
+ """
331
+ Assertion of the given value being less than the given comparison value.
332
+
333
+ :param value: The value being tested.
334
+ :param comparison: The comparison value.
335
+ :param message_on_fail: Message to display in case of assertion failure. Default value is "Test failed".
336
+ :param verbose: Whether the function should print a message in case of assertion success. Default value is False.
337
+ """
338
+
339
+ if verbose and value < comparison :
340
+ print ("Test passed" )
341
+
342
+ elif value >= comparison :
343
+ raise AssertionError (message_on_fail + f": expected { value } to be less than { comparison } " )
0 commit comments