1+ import unittest
2+ from datetime import datetime
3+ from unittest import TestCase
4+
5+ from api .gen_ai .math import (
6+ Calculator ,
7+ DataProcessor ,
8+ StringManipulator ,
9+ add ,
10+ divide ,
11+ factorial ,
12+ fibonacci ,
13+ is_prime ,
14+ merge_dicts ,
15+ parse_date ,
16+ safe_list_access ,
17+ subtract ,
18+ )
19+
20+
21+ class BasicArithmeticTests (TestCase ):
22+ def test_add (self ):
23+ self .assertEqual (add (2 , 3 ), 5 )
24+ self .assertEqual (add (- 1 , 1 ), 0 )
25+ self .assertEqual (add (0 , 0 ), 0 )
26+ self .assertEqual (add (2.5 , 3.5 ), 6.0 )
27+
28+ def test_subtract (self ):
29+ self .assertEqual (subtract (5 , 3 ), 2 )
30+ self .assertEqual (subtract (1 , 1 ), 0 )
31+ self .assertEqual (subtract (0 , 5 ), - 5 )
32+ self .assertEqual (subtract (5.5 , 2.5 ), 3.0 )
33+
34+ def test_divide (self ):
35+ self .assertEqual (divide (6 , 3 ), 2 )
36+ self .assertEqual (divide (5 , 2 ), 2.5 )
37+ self .assertEqual (divide (0 , 5 ), 0 )
38+ self .assertEqual (divide (- 6 , 3 ), - 2 )
39+
40+ def test_divide_by_zero (self ):
41+ with self .assertRaises (ValueError ) as context :
42+ divide (5 , 0 )
43+ self .assertEqual (str (context .exception ), "Division by zero is not allowed" )
44+
45+
46+ class FactorialTests (TestCase ):
47+ def test_factorial_zero (self ):
48+ self .assertEqual (factorial (0 ), 1 )
49+
50+ def test_factorial_one (self ):
51+ self .assertEqual (factorial (1 ), 1 )
52+
53+ def test_factorial_positive (self ):
54+ self .assertEqual (factorial (5 ), 120 )
55+ self .assertEqual (factorial (10 ), 3628800 )
56+
57+ def test_factorial_negative (self ):
58+ with self .assertRaises (ValueError ) as context :
59+ factorial (- 1 )
60+ self .assertEqual (str (context .exception ), "Negative numbers do not have factorials" )
61+
62+
63+ class PrimeTests (TestCase ):
64+ def test_is_prime_negative_and_zero (self ):
65+ self .assertFalse (is_prime (- 5 ))
66+ self .assertFalse (is_prime (0 ))
67+
68+ def test_is_prime_one (self ):
69+ self .assertFalse (is_prime (1 ))
70+
71+ def test_is_prime_two_and_three (self ):
72+ self .assertTrue (is_prime (2 ))
73+ self .assertTrue (is_prime (3 ))
74+
75+ def test_is_prime_regular_cases (self ):
76+ self .assertTrue (is_prime (5 ))
77+ self .assertTrue (is_prime (7 ))
78+ self .assertTrue (is_prime (11 ))
79+ self .assertTrue (is_prime (13 ))
80+ self .assertTrue (is_prime (17 ))
81+ self .assertTrue (is_prime (19 ))
82+ self .assertTrue (is_prime (23 ))
83+
84+ self .assertFalse (is_prime (4 ))
85+ self .assertFalse (is_prime (6 ))
86+ self .assertFalse (is_prime (8 ))
87+ self .assertFalse (is_prime (9 ))
88+ self .assertFalse (is_prime (10 ))
89+
90+ def test_is_prime_larger_numbers (self ):
91+ self .assertTrue (is_prime (97 ))
92+ self .assertFalse (is_prime (100 ))
93+
94+
95+ class FibonacciTests (TestCase ):
96+ def test_fibonacci_zero (self ):
97+ self .assertEqual (fibonacci (0 ), 0 )
98+
99+ def test_fibonacci_one (self ):
100+ self .assertEqual (fibonacci (1 ), 1 )
101+
102+ def test_fibonacci_sequence (self ):
103+ expected_sequence = [0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 ]
104+ for n , expected in enumerate (expected_sequence ):
105+ self .assertEqual (fibonacci (n ), expected )
106+
107+ def test_fibonacci_negative (self ):
108+ with self .assertRaises (ValueError ) as context :
109+ fibonacci (- 1 )
110+ self .assertEqual (str (context .exception ), "n must be a non-negative integer" )
111+
112+
113+ class CalculatorTests (TestCase ):
114+ def setUp (self ):
115+ self .calculator = Calculator ()
116+
117+ def test_add (self ):
118+ self .assertEqual (self .calculator .add (2 , 3 ), 5 )
119+ self .assertEqual (self .calculator .add (- 1 , 1 ), 0 )
120+
121+ def test_subtract (self ):
122+ self .assertEqual (self .calculator .subtract (5 , 3 ), 2 )
123+ self .assertEqual (self .calculator .subtract (1 , 1 ), 0 )
124+
125+ def test_multiply (self ):
126+ self .assertEqual (self .calculator .multiply (2 , 3 ), 6 )
127+ self .assertEqual (self .calculator .multiply (5 , 0 ), 0 )
128+
129+ def test_divide (self ):
130+ self .assertEqual (self .calculator .divide (6 , 3 ), 2 )
131+ self .assertEqual (self .calculator .divide (5 , 2 ), 2.5 )
132+
133+ def test_divide_by_zero (self ):
134+ with self .assertRaises (ValueError ) as context :
135+ self .calculator .divide (5 , 0 )
136+ self .assertEqual (str (context .exception ), "Cannot divide by zero" )
137+
138+ def test_memory_operations (self ):
139+ # Initial memory is 0
140+ self .assertEqual (self .calculator .memory , 0 )
141+
142+ # Store value
143+ self .calculator .store (42 )
144+ self .assertEqual (self .calculator .memory , 42 )
145+
146+ # Recall value
147+ self .assertEqual (self .calculator .recall (), 42 )
148+
149+ # Store new value
150+ self .calculator .store (- 10 )
151+ self .assertEqual (self .calculator .recall (), - 10 )
152+
153+
154+ class StringManipulatorTests (TestCase ):
155+ def test_reverse_string (self ):
156+ self .assertEqual (StringManipulator .reverse_string ("hello" ), "olleh" )
157+ self .assertEqual (StringManipulator .reverse_string ("" ), "" )
158+ self .assertEqual (StringManipulator .reverse_string ("a" ), "a" )
159+ self .assertEqual (StringManipulator .reverse_string ("12345" ), "54321" )
160+
161+ def test_is_palindrome (self ):
162+ # Simple cases
163+ self .assertTrue (StringManipulator .is_palindrome ("racecar" ))
164+ self .assertTrue (StringManipulator .is_palindrome ("madam" ))
165+ self .assertTrue (StringManipulator .is_palindrome ("" ))
166+ self .assertTrue (StringManipulator .is_palindrome ("a" ))
167+ self .assertFalse (StringManipulator .is_palindrome ("hello" ))
168+
169+ # Case insensitivity
170+ self .assertTrue (StringManipulator .is_palindrome ("Madam" ))
171+ self .assertTrue (StringManipulator .is_palindrome ("RaceCar" ))
172+
173+ # Ignoring non-alphanumeric characters
174+ self .assertTrue (StringManipulator .is_palindrome ("A man, a plan, a canal: Panama" ))
175+ self .assertTrue (StringManipulator .is_palindrome ("No 'x' in Nixon" ))
176+
177+
178+ class DataProcessorTests (TestCase ):
179+ def test_constructor_empty_data (self ):
180+ with self .assertRaises (ValueError ) as context :
181+ DataProcessor ([])
182+ self .assertEqual (str (context .exception ), "Data list cannot be empty" )
183+
184+ def test_get_mean (self ):
185+ processor = DataProcessor ([1 , 2 , 3 , 4 , 5 ])
186+ self .assertEqual (processor .get_mean (), 3 )
187+
188+ processor = DataProcessor ([0 , 0 , 0 ])
189+ self .assertEqual (processor .get_mean (), 0 )
190+
191+ processor = DataProcessor ([1.5 , 2.5 , 3.5 ])
192+ self .assertEqual (processor .get_mean (), 2.5 )
193+
194+ def test_get_variance (self ):
195+ processor = DataProcessor ([1 , 2 , 3 , 4 , 5 ])
196+ self .assertEqual (processor .get_variance (), 2.5 )
197+
198+ processor = DataProcessor ([0 , 0 , 0 ])
199+ self .assertEqual (processor .get_variance (), 0 )
200+
201+ def test_get_variance_single_element (self ):
202+ processor = DataProcessor ([42 ])
203+ with self .assertRaises (ValueError ) as context :
204+ processor .get_variance ()
205+ self .assertEqual (str (context .exception ), "At least two data points are required to compute variance" )
206+
207+ def test_normalize (self ):
208+ processor = DataProcessor ([1 , 2 , 3 , 4 , 5 ])
209+ expected = [- 1.2649110640673518 , - 0.6324555320336759 , 0 , 0.6324555320336759 , 1.2649110640673518 ]
210+ normalized = processor .normalize ()
211+ self .assertEqual (len (normalized ), 5 )
212+ for actual , expected_value in zip (normalized , expected ):
213+ self .assertAlmostEqual (actual , expected_value )
214+
215+ def test_normalize_zero_std_dev (self ):
216+ processor = DataProcessor ([2 , 2 , 2 ])
217+ with self .assertRaises (ValueError ) as context :
218+ processor .normalize ()
219+ self .assertEqual (str (context .exception ), "Standard deviation is zero, cannot normalize." )
220+
221+
222+ class DateParsingTests (TestCase ):
223+ def test_parse_date_default_format (self ):
224+ date = parse_date ("2023-01-15" )
225+ self .assertEqual (date .year , 2023 )
226+ self .assertEqual (date .month , 1 )
227+ self .assertEqual (date .day , 15 )
228+
229+ def test_parse_date_custom_format (self ):
230+ date = parse_date ("15/01/2023" , fmt = "%d/%m/%Y" )
231+ self .assertEqual (date .year , 2023 )
232+ self .assertEqual (date .month , 1 )
233+ self .assertEqual (date .day , 15 )
234+
235+ def test_parse_date_invalid_format (self ):
236+ with self .assertRaises (ValueError ) as context :
237+ parse_date ("15-01-2023" )
238+ self .assertEqual (str (context .exception ), "Incorrect date format, should be YYYY-MM-DD" )
239+
240+
241+ class SafeListAccessTests (TestCase ):
242+ def test_safe_list_access_valid_index (self ):
243+ lst = [10 , 20 , 30 , 40 , 50 ]
244+ self .assertEqual (safe_list_access (lst , 2 ), 30 )
245+
246+ def test_safe_list_access_invalid_index (self ):
247+ lst = [10 , 20 , 30 ]
248+ self .assertIsNone (safe_list_access (lst , 10 ))
249+
250+ def test_safe_list_access_custom_default (self ):
251+ lst = [10 , 20 , 30 ]
252+ self .assertEqual (safe_list_access (lst , 10 , default = "Not found" ), "Not found" )
253+
254+
255+ class MergeDictsTests (TestCase ):
256+ def test_merge_dicts_simple (self ):
257+ dict1 = {"a" : 1 , "b" : 2 }
258+ dict2 = {"c" : 3 , "d" : 4 }
259+ result = merge_dicts (dict1 , dict2 )
260+ self .assertEqual (result , {"a" : 1 , "b" : 2 , "c" : 3 , "d" : 4 })
261+
262+ def test_merge_dicts_with_overlap (self ):
263+ dict1 = {"a" : 1 , "b" : 2 }
264+ dict2 = {"b" : 3 , "c" : 4 }
265+ result = merge_dicts (dict1 , dict2 )
266+ self .assertEqual (result , {"a" : 1 , "b" : 3 , "c" : 4 })
267+
268+ def test_merge_dicts_nested (self ):
269+ dict1 = {"a" : 1 , "b" : {"x" : 1 , "y" : 2 }}
270+ dict2 = {"b" : {"y" : 3 , "z" : 4 }, "c" : 5 }
271+ result = merge_dicts (dict1 , dict2 )
272+ self .assertEqual (result , {"a" : 1 , "b" : {"x" : 1 , "y" : 3 , "z" : 4 }, "c" : 5 })
273+
274+ def test_original_dicts_unchanged (self ):
275+ dict1 = {"a" : 1 , "b" : 2 }
276+ dict2 = {"c" : 3 , "d" : 4 }
277+ original_dict1 = dict1 .copy ()
278+ original_dict2 = dict2 .copy ()
279+
280+ merge_dicts (dict1 , dict2 )
281+
282+ self .assertEqual (dict1 , original_dict1 )
283+ self .assertEqual (dict2 , original_dict2 )
0 commit comments