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