how to make a calculator: tests and solutions
how to make a calculator 1: tests
the code from calculator/tests/test_calculator.py from how to make a calculator
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 random_first_number = a_random_number()
13 random_second_number = a_random_number()
14
15 def test_addition(self):
16 self.assertEqual(
17 src.calculator.add(
18 self.random_first_number,
19 self.random_second_number
20 ),
21 self.random_first_number+self.random_second_number
22 )
23
24 def test_subtraction(self):
25 self.assertEqual(
26 src.calculator.subtract(
27 self.random_first_number,
28 self.random_second_number
29 ),
30 self.random_first_number-self.random_second_number
31 )
32
33 def test_multiplication(self):
34 self.assertEqual(
35 src.calculator.multiply(
36 self.random_first_number,
37 self.random_second_number
38 ),
39 self.random_first_number*self.random_second_number
40 )
41
42 def test_division(self):
43 self.assertEqual(
44 src.calculator.divide(
45 self.random_first_number,
46 self.random_second_number
47 ),
48 self.random_first_number/self.random_second_number
49 )
50
51
52# Exceptions seen
53# AssertionError
54# NameError
55# AttributeError
56# TypeError
how to make a calculator 1: solutions
the solutions in calculator/src/calculator.py from how to make a calculator
1def add(first_input, second_input):
2 return first_input + second_input
3
4
5def subtract(first_input, second_input):
6 return first_input - second_input
7
8
9def multiply(first_input, second_input):
10 return first_input * second_input
11
12
13def divide(first_input, second_input):
14 return first_input / second_input
how to make a calculator 2: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 2
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 random_first_number = a_random_number()
13 random_second_number = a_random_number()
14
15 def test_addition(self):
16 self.assertEqual(
17 src.calculator.add(
18 self.random_first_number,
19 self.random_second_number
20 ),
21 self.random_first_number+self.random_second_number
22 )
23
24 def test_subtraction(self):
25 self.assertEqual(
26 src.calculator.subtract(
27 self.random_first_number,
28 self.random_second_number
29 ),
30 self.random_first_number-self.random_second_number
31 )
32
33 def test_multiplication(self):
34 self.assertEqual(
35 src.calculator.multiply(
36 self.random_first_number,
37 self.random_second_number
38 ),
39 self.random_first_number*self.random_second_number
40 )
41
42 def test_division(self):
43 self.assertEqual(
44 src.calculator.divide(
45 self.random_first_number,
46 self.random_second_number
47 ),
48 self.random_first_number/self.random_second_number
49 )
50 with self.assertRaises(ZeroDivisionError):
51 src.calculator.divide(self.random_first_number, 0)
52
53
54# Exceptions seen
55# AssertionError
56# NameError
57# AttributeError
58# TypeError
how to make a calculator 3: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 3
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 random_first_number = a_random_number()
13 random_second_number = a_random_number()
14
15 def test_addition(self):
16 self.assertEqual(
17 src.calculator.add(
18 self.random_first_number,
19 self.random_second_number
20 ),
21 self.random_first_number+self.random_second_number
22 )
23
24 def test_subtraction(self):
25 self.assertEqual(
26 src.calculator.subtract(
27 self.random_first_number,
28 self.random_second_number
29 ),
30 self.random_first_number-self.random_second_number
31 )
32
33 def test_multiplication(self):
34 self.assertEqual(
35 src.calculator.multiply(
36 self.random_first_number,
37 self.random_second_number
38 ),
39 self.random_first_number*self.random_second_number
40 )
41
42 def test_division(self):
43 try:
44 self.assertEqual(
45 src.calculator.divide(
46 self.random_first_number,
47 self.random_second_number
48 ),
49 self.random_first_number/self.random_second_number
50 )
51 except ZeroDivisionError:
52 self.assertEqual(
53 src.calculator.divide(self.random_first_number, 0),
54 'brmph?! I cannot divide by 0. Try again...'
55 )
56
57
58# Exceptions seen
59# AssertionError
60# NameError
61# AttributeError
62# TypeError
how to make a calculator 3: solutions
the solutions in calculator/src/calculator.py from how to make a calculator 3
1def subtract(first_input, second_input):
2 return first_input - second_input
3
4
5def multiply(first_input, second_input):
6 return first_input * second_input
7
8
9def divide(first_input, second_input):
10 try:
11 return first_input / second_input
12 except ZeroDivisionError:
13 return 'brmph?! I cannot divide by 0. Try again...'
14
15
16def add(first_input, second_input):
17 return first_input + second_input
how to make a calculator 4: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 4
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 random_first_number = a_random_number()
13 random_second_number = a_random_number()
14
15 def test_addition(self):
16 self.assertEqual(
17 src.calculator.add(
18 self.random_first_number,
19 self.random_second_number
20 ),
21 self.random_first_number+self.random_second_number
22 )
23
24 def test_subtraction(self):
25 self.assertEqual(
26 src.calculator.subtract(
27 self.random_first_number,
28 self.random_second_number
29 ),
30 self.random_first_number-self.random_second_number
31 )
32
33 def test_multiplication(self):
34 self.assertEqual(
35 src.calculator.multiply(
36 self.random_first_number,
37 self.random_second_number
38 ),
39 self.random_first_number*self.random_second_number
40 )
41
42 def test_division(self):
43 try:
44 self.assertEqual(
45 src.calculator.divide(
46 self.random_first_number,
47 self.random_second_number
48 ),
49 self.random_first_number/self.random_second_number
50 )
51 except ZeroDivisionError:
52 self.assertEqual(
53 src.calculator.divide(self.random_first_number, 0),
54 'brmph?! I cannot divide by 0. Try again...'
55 )
56
57 def test_calculator_sends_message_when_input_is_not_a_number(self):
58 error_message = 'brmph?! Numbers only. Try again...'
59
60 self.assertEqual(
61 src.calculator.add(None, None),
62 error_message
63 )
64 self.assertEqual(
65 src.calculator.divide(None, None),
66 error_message
67 )
68 self.assertEqual(
69 src.calculator.multiply(None, None),
70 error_message
71 )
72 self.assertEqual(
73 src.calculator.subtract(None, None),
74 error_message
75 )
76 self.assertEqual(
77 src.calculator.add('1', '1'),
78 error_message
79 )
80 self.assertEqual(
81 src.calculator.divide('1', '1'),
82 error_message
83 )
84 self.assertEqual(
85 src.calculator.multiply('1', '1'),
86 error_message
87 )
88 self.assertEqual(
89 src.calculator.subtract('1', '1'),
90 error_message
91 )
92
93
94# Exceptions seen
95# AssertionError
96# NameError
97# AttributeError
98# TypeError
how to make a calculator 4: solutions
the solutions in calculator/src/calculator.py from how to make a calculator 4
1def numbers_only(function):
2 def decorator(first_input, second_input):
3 error_message = 'brmph?! Numbers only. Try again...'
4 if first_input is None or second_input is None:
5 return error_message
6 else:
7 try:
8 return function(first_input, second_input)
9 except TypeError:
10 return error_message
11 return decorator
12
13
14@numbers_only
15def subtract(first_input, second_input):
16 return first_input - second_input
17
18
19@numbers_only
20def multiply(first_input, second_input):
21 return first_input * second_input
22
23
24@numbers_only
25def divide(first_input, second_input):
26 try:
27 return first_input / second_input
28 except ZeroDivisionError:
29 return 'brmph?! I cannot divide by 0. Try again...'
30
31
32@numbers_only
33def add(first_input, second_input):
34 if (
35 isinstance(first_input, str)
36 or
37 isinstance(second_input, str)
38 ):
39 return 'brmph?! Numbers only. Try again...'
40 else:
41 return first_input + second_input
how to make a calculator 5: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 5
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 random_first_number = a_random_number()
13 random_second_number = a_random_number()
14
15 def test_addition(self):
16 self.assertEqual(
17 src.calculator.add(
18 self.random_first_number,
19 self.random_second_number
20 ),
21 self.random_first_number+self.random_second_number
22 )
23
24 def test_subtraction(self):
25 self.assertEqual(
26 src.calculator.subtract(
27 self.random_first_number,
28 self.random_second_number
29 ),
30 self.random_first_number-self.random_second_number
31 )
32
33 def test_multiplication(self):
34 self.assertEqual(
35 src.calculator.multiply(
36 self.random_first_number,
37 self.random_second_number
38 ),
39 self.random_first_number*self.random_second_number
40 )
41
42 def test_division(self):
43 try:
44 self.assertEqual(
45 src.calculator.divide(
46 self.random_first_number,
47 self.random_second_number
48 ),
49 self.random_first_number/self.random_second_number
50 )
51 except ZeroDivisionError:
52 self.assertEqual(
53 src.calculator.divide(self.random_first_number, 0),
54 'brmph?! I cannot divide by 0. Try again...'
55 )
56
57 def test_calculator_sends_message_when_input_is_not_a_number(self):
58 error_message = 'brmph?! Numbers only. Try again...'
59
60 self.assertEqual(
61 src.calculator.add(None, None),
62 error_message
63 )
64 self.assertEqual(
65 src.calculator.divide(None, None),
66 error_message
67 )
68 self.assertEqual(
69 src.calculator.multiply(None, None),
70 error_message
71 )
72 self.assertEqual(
73 src.calculator.subtract(None, None),
74 error_message
75 )
76 self.assertEqual(
77 src.calculator.add('1', '1'),
78 error_message
79 )
80 self.assertEqual(
81 src.calculator.divide('1', '1'),
82 error_message
83 )
84 self.assertEqual(
85 src.calculator.multiply('1', '1'),
86 error_message
87 )
88 self.assertEqual(
89 src.calculator.subtract('1', '1'),
90 error_message
91 )
92
93 a_list = [0, 1, 2, 3]
94
95 self.assertEqual(
96 src.calculator.add(a_list, 0),
97 error_message
98 )
99 self.assertEqual(
100 src.calculator.divide(a_list, 1),
101 error_message
102 )
103 self.assertEqual(
104 src.calculator.multiply(a_list, 2),
105 error_message
106 )
107 self.assertEqual(
108 src.calculator.subtract(a_list, 3),
109 error_message
110 )
111
112 def test_calculator_w_list_items(self):
113 two_numbers = [
114 self.random_first_number,
115 self.random_second_number
116 ]
117
118 self.assertEqual(
119 src.calculator.add(
120 two_numbers[0],
121 two_numbers[1]
122 ),
123 self.random_first_number+self.random_second_number
124 )
125 self.assertEqual(
126 src.calculator.divide(
127 two_numbers[-2],
128 two_numbers[-1]
129 ),
130 self.random_first_number/self.random_second_number
131 )
132 self.assertEqual(
133 src.calculator.multiply(
134 two_numbers[1],
135 two_numbers[-1]
136 ),
137 self.random_second_number*self.random_second_number
138 )
139 self.assertEqual(
140 src.calculator.subtract(
141 two_numbers[-2],
142 two_numbers[0]
143 ),
144 self.random_first_number-self.random_first_number
145 )
146 self.assertEqual(
147 src.calculator.add(*two_numbers),
148 self.random_first_number+self.random_second_number
149 )
150 self.assertEqual(
151 src.calculator.divide(*two_numbers),
152 self.random_first_number/self.random_second_number
153 )
154 self.assertEqual(
155 src.calculator.multiply(*two_numbers),
156 self.random_first_number*self.random_second_number
157 )
158 self.assertEqual(
159 src.calculator.subtract(*two_numbers),
160 self.random_first_number-self.random_second_number
161 )
162
163 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
164 not_two_numbers = [0, 1, 2]
165
166 with self.assertRaises(TypeError):
167 src.calculator.add(*not_two_numbers)
168 with self.assertRaises(TypeError):
169 src.calculator.divide(*not_two_numbers)
170 with self.assertRaises(TypeError):
171 src.calculator.multiply(*not_two_numbers)
172 with self.assertRaises(TypeError):
173 src.calculator.subtract(*not_two_numbers)
174
175
176# Exceptions seen
177# AssertionError
178# NameError
179# AttributeError
180# TypeError
how to make a calculator 5: solutions
the solutions in calculator/src/calculator.py from how to make a calculator 5
1def numbers_only(function):
2 def wrapper(first_input, second_input):
3 good_types = (int, float)
4 error_message = 'brmph?! Numbers only. Try again...'
5
6 if not (isinstance(first_input, good_types) and isinstance(second_input, good_types)):
7 return error_message
8 else:
9 try:
10 return function(first_input, second_input)
11 except TypeError:
12 return error_message
13 return wrapper
14
15
16@numbers_only
17def subtract(first_input, second_input):
18 return first_input - second_input
19
20
21@numbers_only
22def multiply(first_input, second_input):
23 return first_input * second_input
24
25
26@numbers_only
27def divide(first_input, second_input):
28 try:
29 return first_input / second_input
30 except ZeroDivisionError:
31 return 'brmph?! I cannot divide by 0. Try again...'
32
33
34@numbers_only
35def add(first_input, second_input):
36 return first_input + second_input
how to make a calculator 6: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 6
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 def setUp(self):
13 self.random_first_number = a_random_number()
14 self.random_second_number = a_random_number()
15
16 def test_addition(self):
17 self.assertEqual(
18 src.calculator.add(
19 self.random_first_number,
20 self.random_second_number
21 ),
22 self.random_first_number+self.random_second_number
23 )
24
25 def test_subtraction(self):
26 self.assertEqual(
27 src.calculator.subtract(
28 self.random_first_number,
29 self.random_second_number
30 ),
31 self.random_first_number-self.random_second_number
32 )
33
34 def test_multiplication(self):
35 self.assertEqual(
36 src.calculator.multiply(
37 self.random_first_number,
38 self.random_second_number
39 ),
40 self.random_first_number*self.random_second_number
41 )
42
43 def test_division(self):
44 try:
45 self.assertEqual(
46 src.calculator.divide(
47 self.random_first_number,
48 self.random_second_number
49 ),
50 self.random_first_number/self.random_second_number
51 )
52 except ZeroDivisionError:
53 self.assertEqual(
54 src.calculator.divide(self.random_first_number, 0),
55 'brmph?! I cannot divide by 0. Try again...'
56 )
57
58 def test_calculator_w_list_items(self):
59 two_numbers = [
60 self.random_first_number,
61 self.random_second_number
62 ]
63
64 self.assertEqual(
65 src.calculator.add(
66 two_numbers[0],
67 two_numbers[1]
68 ),
69 self.random_first_number+self.random_second_number
70 )
71 self.assertEqual(
72 src.calculator.divide(
73 two_numbers[-2],
74 two_numbers[-1]
75 ),
76 self.random_first_number/self.random_second_number
77 )
78 self.assertEqual(
79 src.calculator.multiply(
80 two_numbers[1],
81 two_numbers[-1]
82 ),
83 self.random_second_number*self.random_second_number
84 )
85 self.assertEqual(
86 src.calculator.subtract(
87 two_numbers[-2],
88 two_numbers[0]
89 ),
90 self.random_first_number-self.random_first_number
91 )
92 self.assertEqual(
93 src.calculator.add(*two_numbers),
94 self.random_first_number+self.random_second_number
95 )
96 self.assertEqual(
97 src.calculator.divide(*two_numbers),
98 self.random_first_number/self.random_second_number
99 )
100 self.assertEqual(
101 src.calculator.multiply(*two_numbers),
102 self.random_first_number*self.random_second_number
103 )
104 self.assertEqual(
105 src.calculator.subtract(*two_numbers),
106 self.random_first_number-self.random_second_number
107 )
108
109 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
110 not_two_numbers = [0, 1, 2]
111
112 with self.assertRaises(TypeError):
113 src.calculator.add(*not_two_numbers)
114 with self.assertRaises(TypeError):
115 src.calculator.divide(*not_two_numbers)
116 with self.assertRaises(TypeError):
117 src.calculator.multiply(*not_two_numbers)
118 with self.assertRaises(TypeError):
119 src.calculator.subtract(*not_two_numbers)
120
121 def test_calculator_sends_message_when_input_is_not_a_number(self):
122 error_message = 'brmph?! Numbers only. Try again...'
123
124 [
125 self.assertEqual(
126 src.calculator.add(data_type, a_random_number()),
127 error_message
128 ) for data_type in (
129 None,
130 True, False,
131 str(), 'text',
132 tuple(), (0, 1, 2, 'n'),
133 list(), [0, 1, 2, 'n'],
134 set(), {0, 1, 2, 'n'},
135 dict(), {'key': 'value'},
136 )
137 ]
138
139 for data_type in (
140 None,
141 True, False,
142 str(), 'text',
143 tuple(), (0, 1, 2, 'n'),
144 list(), [0, 1, 2, 'n'],
145 set(), {0, 1, 2, 'n'},
146 dict(), {'key': 'value'},
147 ):
148 with self.subTest(data_type=data_type):
149 self.assertEqual(
150 src.calculator.add(
151 data_type, a_random_number()
152 ),
153 error_message
154 )
155 self.assertEqual(
156 src.calculator.divide(
157 data_type, a_random_number()
158 ),
159 error_message
160 )
161 self.assertEqual(
162 src.calculator.multiply(
163 data_type, a_random_number()
164 ),
165 error_message
166 )
167 self.assertEqual(
168 src.calculator.subtract(
169 data_type, a_random_number()
170 ),
171 error_message
172 )
173
174
175# Exceptions seen
176# AssertionError
177# NameError
178# AttributeError
179# TypeError
how to make a calculator 6: solutions
the solutions in calculator/src/calculator.py from how to make a calculator 5
1def numbers_only(function):
2 def decorator(first_input, second_input):
3 bad_data_types = (str, list, bool)
4 error_message = 'brmph?! Numbers only. Try again...'
5
6 for value in (first_input, second_input):
7 if (
8 value is None
9 or
10 isinstance(value, bad_data_types)
11 ):
12 return error_message
13
14 try:
15 return function(first_input, second_input)
16 except TypeError:
17 return error_message
18 return decorator
19
20
21@numbers_only
22def subtract(first_input, second_input):
23 return first_input - second_input
24
25
26@numbers_only
27def multiply(first_input, second_input):
28 return first_input * second_input
29
30
31@numbers_only
32def divide(first_input, second_input):
33 try:
34 return first_input / second_input
35 except ZeroDivisionError:
36 return 'brmph?! I cannot divide by 0. Try again...'
37
38
39@numbers_only
40def add(first_input, second_input):
41 return first_input + second_input
how to make a calculator 7: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 7
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 def setUp(self):
13 self.random_first_number = a_random_number()
14 self.random_second_number = a_random_number()
15
16 x = self.random_first_number
17 y = self.random_second_number
18
19 try:
20 division_result = x / y
21 except ZeroDivisionError:
22 division_result = 'brmph?! I cannot divide by 0. Try again...'
23
24 self.arithmetic_tests = {
25 'addition': {
26 'function': src.calculator.add,
27 'expectation': x+y,
28 },
29 'subtraction': {
30 'function': src.calculator.subtract,
31 'expectation': x-y,
32 },
33 'division': {
34 'function': src.calculator.divide,
35 'expectation': division_result,
36 },
37 'multiplication': {
38 'function': src.calculator.multiply,
39 'expectation': x*y,
40 }
41 }
42
43 def test_calculator_w_list_items(self):
44 # two_numbers = [
45 # self.random_first_number,
46 # self.random_second_number
47 # ]
48 a_dictionary = {
49 'x': self.random_first_number,
50 'y': self.random_second_number
51 }
52 two_numbers = list(a_dictionary.values())
53
54 for operation in self.arithmetic_tests:
55 with self.subTest(operation=operation):
56 self.assertEqual(
57 self.arithmetic_tests[operation]['function'](
58 *two_numbers
59 ),
60 self.arithmetic_tests[operation]['expectation']
61 )
62
63 self.assertEqual(
64 src.calculator.add(
65 two_numbers[0],
66 two_numbers[1]
67 ),
68 self.random_first_number+self.random_second_number
69 )
70 self.assertEqual(
71 src.calculator.divide(
72 two_numbers[-2],
73 two_numbers[-1]
74 ),
75 self.random_first_number/self.random_second_number
76 )
77 self.assertEqual(
78 src.calculator.multiply(
79 two_numbers[1],
80 two_numbers[-1]
81 ),
82 self.random_second_number*self.random_second_number
83 )
84 self.assertEqual(
85 src.calculator.subtract(
86 two_numbers[-2],
87 two_numbers[0]
88 ),
89 self.random_first_number-self.random_first_number
90 )
91
92 def test_calculator_w_dictionary_items(self):
93 two_numbers = {
94 'first_input': self.random_first_number,
95 'second_input': self.random_second_number,
96 }
97
98 for operation in self.arithmetic_tests:
99 with self.subTest(operation=operation):
100 self.assertEqual(
101 self.arithmetic_tests[operation]['function'](
102 **two_numbers
103 ),
104 self.arithmetic_tests[operation]['expectation']
105 )
106
107 self.assertEqual(
108 src.calculator.add(
109 two_numbers['first_input'],
110 two_numbers['second_input']
111 ),
112 self.random_first_number+self.random_second_number
113 )
114 self.assertEqual(
115 src.calculator.divide(
116 two_numbers['first_input'],
117 two_numbers['second_input']
118 ),
119 self.random_first_number/self.random_second_number
120 )
121 self.assertEqual(
122 src.calculator.multiply(
123 two_numbers['second_input'],
124 two_numbers['second_input']
125 ),
126 self.random_second_number*self.random_second_number
127 )
128 self.assertEqual(
129 src.calculator.subtract(
130 two_numbers['first_input'],
131 two_numbers['first_input']
132 ),
133 self.random_first_number-self.random_first_number
134 )
135
136 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
137 for operation in self.arithmetic_tests:
138 with (
139 self.subTest(operation=operation),
140 self.assertRaises(TypeError),
141 ):
142 self.arithmetic_tests[operation]['function'](
143 [0, 1, 2]
144 )
145
146 def test_calculator_sends_message_when_input_is_not_a_number(self):
147 for bad_input in (
148 None,
149 True, False,
150 str(), 'text',
151 tuple(), (0, 1, 2, 'n'),
152 list(), [0, 1, 2, 'n'],
153 set(), {0, 1, 2, 'n'},
154 dict(), {'key': 'value'},
155 ):
156 for operation in self.arithmetic_tests:
157 with self.subTest(
158 operation=operation,
159 bad_input=bad_input,
160 ):
161 self.assertEqual(
162 self.arithmetic_tests[operation]['function'](
163 bad_input, a_random_number()
164 ),
165 'brmph?! Numbers only. Try again...'
166 )
167
168 def test_calculator_functions(self):
169 for operation in self.arithmetic_tests:
170 with self.subTest(operation=operation):
171 self.assertEqual(
172 self.arithmetic_tests[operation]['function'](
173 self.random_first_number,
174 self.random_second_number
175 ),
176 self.arithmetic_tests[operation]['expectation']
177 )
178
179
180# Exceptions seen
181# AssertionError
182# NameError
183# AttributeError
184# TypeError
185# KeyError
how to make a calculator 8: tests
the code from calculator/tests/test_calculator.py from how to make a calculator 8
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 @staticmethod
13 def get_division_result(x, y):
14 try:
15 return x / y
16 except ZeroDivisionError:
17 return 'brmph?! I cannot divide by 0. Try again...'
18
19 def setUp(self):
20 self.random_first_number = a_random_number()
21 self.random_second_number = a_random_number()
22
23 x = self.random_first_number
24 y = self.random_second_number
25
26 self.calculator_tests = {
27 'add': x+y,
28 'subtract': x-y,
29 'multiply': x*y,
30 'divide': self.get_division_result(x, y)
31 }
32
33 def test_calculator_w_list_items(self):
34 # two_numbers = [
35 # self.random_first_number,
36 # self.random_second_number
37 # ]
38 a_dictionary = {
39 'x': self.random_first_number,
40 'y': self.random_second_number
41 }
42 two_numbers = list(a_dictionary.values())
43
44 for operation in self.calculator_tests:
45 with self.subTest(operation=operation):
46 self.assertEqual(
47 src.calculator.__getattribute__(operation)(
48 *two_numbers
49 ),
50 self.calculator_tests[operation]
51 )
52
53 self.assertEqual(
54 src.calculator.add(
55 two_numbers[0],
56 two_numbers[1]
57 ),
58 self.random_first_number+self.random_second_number
59 )
60 self.assertEqual(
61 src.calculator.divide(
62 two_numbers[-2],
63 two_numbers[-1]
64 ),
65 self.random_first_number/self.random_second_number
66 )
67 self.assertEqual(
68 src.calculator.multiply(
69 two_numbers[1],
70 two_numbers[-1]
71 ),
72 self.random_second_number*self.random_second_number
73 )
74 self.assertEqual(
75 src.calculator.subtract(
76 two_numbers[-2],
77 two_numbers[0]
78 ),
79 self.random_first_number-self.random_first_number
80 )
81
82 def test_calculator_w_dictionary_items(self):
83 two_numbers = {
84 'first_input': self.random_first_number,
85 'second_input': self.random_second_number,
86 }
87
88 for operation in self.calculator_tests:
89 with self.subTest(operation=operation):
90 self.assertEqual(
91 src.calculator.__getattribute__(operation)(
92 **two_numbers
93 ),
94 self.calculator_tests[operation]
95 )
96
97 self.assertEqual(
98 src.calculator.add(
99 two_numbers['first_input'],
100 two_numbers['second_input']
101 ),
102 self.random_first_number+self.random_second_number
103 )
104 self.assertEqual(
105 src.calculator.divide(
106 two_numbers['first_input'],
107 two_numbers['second_input']
108 ),
109 self.random_first_number/self.random_second_number
110 )
111 self.assertEqual(
112 src.calculator.multiply(
113 two_numbers['second_input'],
114 two_numbers['second_input']
115 ),
116 self.random_second_number*self.random_second_number
117 )
118 self.assertEqual(
119 src.calculator.subtract(
120 two_numbers['first_input'],
121 two_numbers['first_input']
122 ),
123 self.random_first_number-self.random_first_number
124 )
125
126 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
127 for operation in self.calculator_tests:
128 with (
129 self.subTest(operation=operation),
130 self.assertRaises(TypeError),
131 ):
132 src.calculator.__getattribute__(operation)(
133 [0, 1, 2]
134 )
135
136 def test_calculator_sends_message_when_input_is_not_a_number(self):
137 for bad_input in (
138 None,
139 True, False,
140 str(), 'text',
141 tuple(), (0, 1, 2, 'n'),
142 list(), [0, 1, 2, 'n'],
143 set(), {0, 1, 2, 'n'},
144 dict(), {'key': 'value'},
145 ):
146 for operation in self.calculator_tests:
147 with self.subTest(
148 operation=operation,
149 bad_input=bad_input,
150 ):
151 self.assertEqual(
152 src.calculator.__getattribute__(operation)(
153 bad_input, a_random_number()
154 ),
155 'brmph?! Numbers only. Try again...'
156 )
157
158 def test_calculator_functions(self):
159 for operation in self.calculator_tests:
160 with self.subTest(operation=operation):
161 self.assertEqual(
162 src.calculator.__getattribute__(operation)(
163 self.random_first_number,
164 self.random_second_number
165 ),
166 self.calculator_tests[operation]
167 )
168
169
170# Exceptions seen
171# AssertionError
172# NameError
173# AttributeError
174# TypeError
175# KeyError
how to make a calculator 9: tests
the code from calculator/tests/test_calculator_website.py from how to make a calculator 9
1import src.website
2import tests.test_calculator
3import unittest
4
5
6class TestCalculatorWebsite(unittest.TestCase):
7
8 def setUp(self):
9 self.client = src.website.app.test_client()
10 self.x = tests.test_calculator.a_random_number()
11
12 def test_home_page(self):
13 response = self.client.get('/')
14 self.assertEqual(response.status_code, 200)
15 self.assertIn(
16 b'<h1>Calculator</h1>',
17 response.data
18 )
19
20 def test_calculations(self):
21 y = tests.test_calculator.a_random_number()
22
23 operations = {
24 'add': '+',
25 'subtract': '-',
26 'divide': '/',
27 'multiply': '*',
28 }
29
30 for operation in operations:
31 with self.subTest(operation=operation):
32 response = self.client.post(
33 '/calculate',
34 data={
35 'first_input': self.x,
36 'second_input': y,
37 'operation': operation,
38 }
39 )
40 self.assertEqual(response.status_code, 200)
41
42 function = src.calculator.__getattribute__(
43 operation
44 )
45 result = function(self.x, y)
46 self.assertEqual(
47 response.data.decode(),
48 (
49 f'<h2>{self.x} {operations[operation]} {y} '
50 f'= {result}</h2>'
51 )
52 )
53
54 def test_website_handling_zero_division_error(self):
55 response = self.client.post(
56 '/calculate',
57 data={
58 'first_input': self.x,
59 'second_input': 0,
60 'operation': 'divide',
61 }
62 )
63 self.assertEqual(
64 response.data.decode(),
65 (
66 f'<h2>{self.x} / 0.0 = '
67 'brmph?! I cannot divide by 0. Try again...</h2>'
68 )
69 )
70
71
72# Exceptions seen
73# NameError
74# ModuleNotFoundError
75# AttributeError
76# AssertionError
77# jinja2.exceptions.TemplateNotFound
78# SyntaxError
the code from calculator/tests/test_calculator.py from how to make a calculator 9
1import random
2import src.calculator
3import unittest
4
5
6def a_random_number():
7 return random.triangular(-1000.0, 1000.0)
8
9
10class TestCalculator(unittest.TestCase):
11
12 @staticmethod
13 def get_division_result(x, y):
14 try:
15 return x / y
16 except ZeroDivisionError:
17 return 'brmph?! I cannot divide by 0. Try again...'
18
19 def setUp(self):
20 self.random_first_number = a_random_number()
21 self.random_second_number = a_random_number()
22
23 x = self.random_first_number
24 y = self.random_second_number
25
26 self.calculator_tests = {
27 'add': x+y,
28 'subtract': x-y,
29 'multiply': x*y,
30 'divide': self.get_division_result(x, y)
31 }
32
33 def test_calculator_w_list_items(self):
34 # two_numbers = [
35 # self.random_first_number,
36 # self.random_second_number
37 # ]
38 a_dictionary = {
39 'x': self.random_first_number,
40 'y': self.random_second_number
41 }
42 two_numbers = list(a_dictionary.values())
43
44 for operation in self.calculator_tests:
45 with self.subTest(operation=operation):
46 self.assertEqual(
47 src.calculator.__getattribute__(operation)(
48 *two_numbers
49 ),
50 self.calculator_tests[operation]
51 )
52
53 self.assertEqual(
54 src.calculator.add(
55 two_numbers[0],
56 two_numbers[1]
57 ),
58 self.random_first_number+self.random_second_number
59 )
60 self.assertEqual(
61 src.calculator.divide(
62 two_numbers[-2],
63 two_numbers[-1]
64 ),
65 self.random_first_number/self.random_second_number
66 )
67 self.assertEqual(
68 src.calculator.multiply(
69 two_numbers[1],
70 two_numbers[-1]
71 ),
72 self.random_second_number*self.random_second_number
73 )
74 self.assertEqual(
75 src.calculator.subtract(
76 two_numbers[-2],
77 two_numbers[0]
78 ),
79 self.random_first_number-self.random_first_number
80 )
81
82 def test_calculator_w_dictionary_items(self):
83 two_numbers = {
84 'first_input': self.random_first_number,
85 'second_input': self.random_second_number,
86 }
87
88 for operation in self.calculator_tests:
89 with self.subTest(operation=operation):
90 self.assertEqual(
91 src.calculator.__getattribute__(operation)(
92 **two_numbers
93 ),
94 self.calculator_tests[operation]
95 )
96
97 self.assertEqual(
98 src.calculator.add(
99 two_numbers['first_input'],
100 two_numbers['second_input']
101 ),
102 self.random_first_number+self.random_second_number
103 )
104 self.assertEqual(
105 src.calculator.divide(
106 two_numbers['first_input'],
107 two_numbers['second_input']
108 ),
109 self.random_first_number/self.random_second_number
110 )
111 self.assertEqual(
112 src.calculator.multiply(
113 two_numbers['second_input'],
114 two_numbers['second_input']
115 ),
116 self.random_second_number*self.random_second_number
117 )
118 self.assertEqual(
119 src.calculator.subtract(
120 two_numbers['first_input'],
121 two_numbers['first_input']
122 ),
123 self.random_first_number-self.random_first_number
124 )
125
126 def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
127 for operation in self.calculator_tests:
128 with (
129 self.subTest(operation=operation),
130 self.assertRaises(TypeError),
131 ):
132 src.calculator.__getattribute__(operation)(
133 [0, 1, 2]
134 )
135
136 def test_calculator_sends_message_when_inputs_are_not_numbers(self):
137 for bad_input in (
138 None,
139 True, False,
140 str(), 'text',
141 tuple(), (0, 1, 2, 'n'),
142 list(), [0, 1, 2, 'n'],
143 set(), {0, 1, 2, 'n'},
144 dict(), {'key': 'value'},
145 ):
146 for operation in self.calculator_tests:
147 with self.subTest(
148 operation=operation,
149 bad_input=bad_input,
150 ):
151 self.assertEqual(
152 src.calculator.__getattribute__(operation)(
153 bad_input, a_random_number()
154 ),
155 'brmph?! Numbers only. Try again...'
156 )
157 self.assertEqual(
158 src.calculator.__getattribute__(operation)(
159 a_random_number(), bad_input
160 ),
161 'brmph?! Numbers only. Try again...'
162 )
163
164 def test_calculator_functions(self):
165 for operation in self.calculator_tests:
166 with self.subTest(operation=operation):
167 self.assertEqual(
168 src.calculator.__getattribute__(operation)(
169 self.random_first_number,
170 self.random_second_number
171 ),
172 self.calculator_tests[operation]
173 )
174
175
176# Exceptions seen
177# AssertionError
178# NameError
179# AttributeError
180# TypeError
181# KeyError
how to make a calculator 9: solutions
the code from calculator/src/calculator.py from how to make a calculator 9
1def check_input(function):
2 def wrapper(first_input, second_input):
3 if isinstance(
4 first_input,
5 (dict, set, list, tuple, str, bool)
6 ) or first_input is None:
7 return 'brmph?! Numbers only. Try again...'
8 return function(first_input, second_input)
9 return wrapper
10
11
12@check_input
13def add(first_input, second_input):
14 return first_input + second_input
15
16
17@check_input
18def divide(first_input, second_input):
19 try:
20 return first_input / second_input
21 except ZeroDivisionError:
22 return 'brmph?! I cannot divide by 0. Try again...'
23
24
25@check_input
26def multiply(first_input, second_input):
27 return first_input * second_input
28
29
30@check_input
31def subtract(first_input, second_input):
32 return first_input - second_input
the code from calculator/src/website.py from how to make a calculator 9
1import pathlib
2import sys
3sys.path.insert(
4 0, str(pathlib.Path(__file__).resolve().parent)
5)
6
7import calculator
8import flask
9
10
11app = flask.Flask(__name__)
12
13
14@app.route('/')
15def home():
16 return flask.render_template('index.html')
17
18
19@app.route('/calculate', methods=['POST'])
20def calculate():
21 first_input = flask.request.form.get('first_input')
22 first_input = float(first_input)
23 second_input = flask.request.form.get('second_input')
24 second_input = float(second_input)
25 operation = flask.request.form.get('operation')
26
27 operations = {
28 'add': '+',
29 'subtract': '-',
30 'divide': '/',
31 'multiply': '*',
32 }
33
34 result = calculator.__getattribute__(operation)(
35 first_input, second_input
36 )
37 return (
38 f'<h2>{first_input} {operations[operation]} {second_input} '
39 f'= {result}</h2>'
40 )
how to make a calculator 10: part 1: tests
the code from calculator/tests/test_streamlit_calculator.py from how to make a calculator 10: part 1
how to make a calculator 10: part 1: solutions
the code from calculator/src/streamlit_calculator.py from how to make a calculator 10: part 1
how to make a calculator 10: part 2: tests and solutions
the code from calculator/tests/test_streamlit_calculator.py from how to make a calculator 10: part 2
how to make a calculator 10: part 2: solutions
the code from calculator/src/streamlit_calculator.py from how to make a calculator 10: part 2
how to make a calculator 10: part 3: tests
the code from calculator/tests/test_streamlit_calculator.py from how to make a calculator 10: part 3
how to make a calculator 10: part 3: solutions
the code from calculator/src/streamlit_calculator.py from how to make a calculator 10: part 3
how to make a calculator 10: part 4: tests
the code from calculator/tests/test_streamlit_calculator.py from how to make a calculator 10: part 4
how to make a calculator 10: part 4: solutions
the code from calculator/src/streamlit_calculator.py from how to make a calculator 10: part 4