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