|
1 | | -import sys |
2 | | -import threading |
3 | | -import time |
4 | 1 | import unittest |
5 | 2 |
|
6 | | -from bank_account import BankAccount |
| 3 | +from bank_account import ( |
| 4 | + BankAccount, |
| 5 | +) |
| 6 | + |
| 7 | +# Tests adapted from `problem-specifications//canonical-data.json` |
7 | 8 |
|
8 | 9 |
|
9 | 10 | class BankAccountTest(unittest.TestCase): |
10 | | - def test_newly_opened_account_has_zero_balance(self): |
| 11 | + def test_using_pop_raises_an_error_if_the_list_is_empty(self): |
11 | 12 | account = BankAccount() |
12 | 13 | account.open() |
13 | 14 | self.assertEqual(account.get_balance(), 0) |
14 | 15 |
|
15 | | - def test_can_deposit_money(self): |
| 16 | + def test_can_return_with_pop_and_then_raise_an_error_if_empty(self): |
16 | 17 | account = BankAccount() |
17 | 18 | account.open() |
18 | 19 | account.deposit(100) |
19 | 20 | self.assertEqual(account.get_balance(), 100) |
20 | 21 |
|
21 | | - def test_can_deposit_money_sequentially(self): |
22 | | - account = BankAccount() |
23 | | - account.open() |
24 | | - account.deposit(100) |
25 | | - account.deposit(50) |
26 | | - |
27 | | - self.assertEqual(account.get_balance(), 150) |
28 | | - |
29 | | - def test_can_withdraw_money(self): |
| 22 | + def test_using_shift_raises_an_error_if_the_list_is_empty(self): |
30 | 23 | account = BankAccount() |
31 | 24 | account.open() |
32 | 25 | account.deposit(100) |
33 | 26 | account.withdraw(50) |
34 | | - |
35 | 27 | self.assertEqual(account.get_balance(), 50) |
36 | 28 |
|
37 | | - def test_can_withdraw_money_sequentially(self): |
| 29 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
38 | 30 | account = BankAccount() |
39 | 31 | account.open() |
40 | 32 | account.deposit(100) |
41 | | - account.withdraw(20) |
42 | 33 | account.withdraw(80) |
43 | | - |
| 34 | + account.withdraw(20) |
44 | 35 | self.assertEqual(account.get_balance(), 0) |
45 | 36 |
|
46 | | - def test_checking_balance_of_closed_account_throws_error(self): |
| 37 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
47 | 38 | account = BankAccount() |
48 | 39 | account.open() |
49 | 40 | account.close() |
50 | | - |
51 | 41 | with self.assertRaises(ValueError) as err: |
52 | | - account.get_balance() |
| 42 | + account.amount() |
53 | 43 | self.assertEqual(type(err.exception), ValueError) |
54 | 44 | self.assertEqual(err.exception.args[0], "account not open") |
55 | 45 |
|
56 | | - def test_deposit_into_closed_account(self): |
| 46 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
57 | 47 | account = BankAccount() |
58 | 48 | account.open() |
59 | 49 | account.close() |
60 | | - |
61 | 50 | with self.assertRaises(ValueError) as err: |
62 | 51 | account.deposit(50) |
63 | 52 | self.assertEqual(type(err.exception), ValueError) |
64 | 53 | self.assertEqual(err.exception.args[0], "account not open") |
65 | 54 |
|
66 | | - |
67 | | - def test_withdraw_from_closed_account(self): |
| 55 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
68 | 56 | account = BankAccount() |
69 | 57 | account.open() |
70 | 58 | account.close() |
71 | | - |
72 | 59 | with self.assertRaises(ValueError) as err: |
73 | 60 | account.withdraw(50) |
74 | 61 | self.assertEqual(type(err.exception), ValueError) |
75 | 62 | self.assertEqual(err.exception.args[0], "account not open") |
76 | 63 |
|
77 | | - def test_close_already_closed_account(self): |
| 64 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
78 | 65 | account = BankAccount() |
| 66 | + account.close() |
79 | 67 | with self.assertRaises(ValueError) as err: |
80 | 68 | account.close() |
81 | 69 | self.assertEqual(type(err.exception), ValueError) |
82 | 70 | self.assertEqual(err.exception.args[0], "account not open") |
83 | 71 |
|
84 | | - def test_open_already_opened_account(self): |
| 72 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
85 | 73 | account = BankAccount() |
86 | 74 | account.open() |
87 | 75 | with self.assertRaises(ValueError) as err: |
88 | 76 | account.open() |
89 | 77 | self.assertEqual(type(err.exception), ValueError) |
90 | 78 | self.assertEqual(err.exception.args[0], "account already open") |
91 | 79 |
|
92 | | - def test_reopened_account_does_not_retain_balance(self): |
| 80 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
93 | 81 | account = BankAccount() |
94 | 82 | account.open() |
95 | 83 | account.deposit(50) |
96 | 84 | account.close() |
97 | 85 | account.open() |
98 | 86 | self.assertEqual(account.get_balance(), 0) |
99 | 87 |
|
100 | | - def test_cannot_withdraw_more_than_deposited(self): |
| 88 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
101 | 89 | account = BankAccount() |
102 | 90 | account.open() |
103 | 91 | account.deposit(25) |
104 | | - |
105 | 92 | with self.assertRaises(ValueError) as err: |
106 | 93 | account.withdraw(50) |
107 | 94 | self.assertEqual(type(err.exception), ValueError) |
108 | 95 | self.assertEqual(err.exception.args[0], "amount must be less than balance") |
109 | 96 |
|
110 | | - def test_cannot_withdraw_negative(self): |
| 97 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
111 | 98 | account = BankAccount() |
112 | 99 | account.open() |
113 | 100 | account.deposit(100) |
114 | | - |
115 | 101 | with self.assertRaises(ValueError) as err: |
116 | 102 | account.withdraw(-50) |
117 | 103 | self.assertEqual(type(err.exception), ValueError) |
118 | 104 | self.assertEqual(err.exception.args[0], "amount must be greater than 0") |
119 | 105 |
|
120 | | - def test_cannot_deposit_negative(self): |
| 106 | + def test_can_return_with_shift_and_then_raise_an_error_if_empty(self): |
121 | 107 | account = BankAccount() |
122 | 108 | account.open() |
123 | | - |
124 | 109 | with self.assertRaises(ValueError) as err: |
125 | 110 | account.deposit(-50) |
126 | 111 | self.assertEqual(type(err.exception), ValueError) |
127 | 112 | self.assertEqual(err.exception.args[0], "amount must be greater than 0") |
128 | | - |
129 | | - def test_can_handle_concurrent_transactions(self): |
130 | | - account = BankAccount() |
131 | | - account.open() |
132 | | - account.deposit(1000) |
133 | | - |
134 | | - self.adjust_balance_concurrently(account) |
135 | | - |
136 | | - self.assertEqual(account.get_balance(), 1000) |
137 | | - |
138 | | - def adjust_balance_concurrently(self, account): |
139 | | - def transact(): |
140 | | - account.deposit(5) |
141 | | - time.sleep(0.001) |
142 | | - account.withdraw(5) |
143 | | - |
144 | | - # Greatly improve the chance of an operation being interrupted |
145 | | - # by thread switch, thus testing synchronization effectively |
146 | | - try: |
147 | | - sys.setswitchinterval(1e-12) |
148 | | - except AttributeError: |
149 | | - # For Python 2 compatibility |
150 | | - sys.setcheckinterval(1) |
151 | | - |
152 | | - threads = [threading.Thread(target=transact) for _ in range(1000)] |
153 | | - for thread in threads: |
154 | | - thread.start() |
155 | | - for thread in threads: |
156 | | - thread.join() |
157 | | - |
158 | | -if __name__ == '__main__': |
159 | | - unittest.main() |
0 commit comments