From 4e334774bd2a54597cdc18068894594bb39924ff Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 9 Oct 2024 17:03:40 +0200 Subject: [PATCH] Sync bank-account (#815) [no important files changed] --- .../bank-account/.docs/instructions.md | 2 +- .../practice/bank-account/.meta/example.php | 22 -- .../practice/bank-account/.meta/tests.toml | 63 +++++ .../practice/bank-account/BankAccountTest.php | 263 +++++++++++------- 4 files changed, 221 insertions(+), 129 deletions(-) create mode 100644 exercises/practice/bank-account/.meta/tests.toml diff --git a/exercises/practice/bank-account/.docs/instructions.md b/exercises/practice/bank-account/.docs/instructions.md index 0955520b..7398fbea 100644 --- a/exercises/practice/bank-account/.docs/instructions.md +++ b/exercises/practice/bank-account/.docs/instructions.md @@ -3,7 +3,7 @@ Your task is to implement bank accounts supporting opening/closing, withdrawals, and deposits of money. As bank accounts can be accessed in many different ways (internet, mobile phones, automatic charges), your bank software must allow accounts to be safely accessed from multiple threads/processes (terminology depends on your programming language) in parallel. -For example, there may be many deposits and withdrawals occurring in parallel; you need to ensure there is no [race conditions][wikipedia] between when you read the account balance and set the new balance. +For example, there may be many deposits and withdrawals occurring in parallel; you need to ensure there are no [race conditions][wikipedia] between when you read the account balance and set the new balance. It should be possible to close an account; operations against a closed account must fail. diff --git a/exercises/practice/bank-account/.meta/example.php b/exercises/practice/bank-account/.meta/example.php index ea588072..7ca7f43e 100644 --- a/exercises/practice/bank-account/.meta/example.php +++ b/exercises/practice/bank-account/.meta/example.php @@ -1,27 +1,5 @@ . - * - * To disable strict typing, comment out the directive below. - */ - declare(strict_types=1); class BankAccount diff --git a/exercises/practice/bank-account/.meta/tests.toml b/exercises/practice/bank-account/.meta/tests.toml new file mode 100644 index 00000000..6a8fa608 --- /dev/null +++ b/exercises/practice/bank-account/.meta/tests.toml @@ -0,0 +1,63 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[983a1528-4ceb-45e5-8257-8ce01aceb5ed] +description = "Newly opened account has zero balance" + +[e88d4ec3-c6bf-4752-8e59-5046c44e3ba7] +description = "Single deposit" + +[3d9147d4-63f4-4844-8d2b-1fee2e9a2a0d] +description = "Multiple deposits" + +[08f1af07-27ae-4b38-aa19-770bde558064] +description = "Withdraw once" + +[6f6d242f-8c31-4ac6-8995-a90d42cad59f] +description = "Withdraw twice" + +[45161c94-a094-4c77-9cec-998b70429bda] +description = "Can do multiple operations sequentially" + +[f9facfaa-d824-486e-8381-48832c4bbffd] +description = "Cannot check balance of closed account" + +[7a65ba52-e35c-4fd2-8159-bda2bde6e59c] +description = "Cannot deposit into closed account" + +[a0a1835d-faae-4ad4-a6f3-1fcc2121380b] +description = "Cannot deposit into unopened account" + +[570dfaa5-0532-4c1f-a7d3-0f65c3265608] +description = "Cannot withdraw from closed account" + +[c396d233-1c49-4272-98dc-7f502dbb9470] +description = "Cannot close an account that was not opened" + +[c06f534f-bdc2-4a02-a388-1063400684de] +description = "Cannot open an already opened account" + +[0722d404-6116-4f92-ba3b-da7f88f1669c] +description = "Reopened account does not retain balance" + +[ec42245f-9361-4341-8231-a22e8d19c52f] +description = "Cannot withdraw more than deposited" + +[4f381ef8-10ef-4507-8e1d-0631ecc8ee72] +description = "Cannot withdraw negative" + +[d45df9ea-1db0-47f3-b18c-d365db49d938] +description = "Cannot deposit negative" + +[ba0c1e0b-0f00-416f-8097-a7dfc97871ff] +description = "Can handle concurrent transactions" +include = false +comment = "PHP does not support concurrency (on a level we expect students to work in)" diff --git a/exercises/practice/bank-account/BankAccountTest.php b/exercises/practice/bank-account/BankAccountTest.php index 8c932a1e..86293c67 100644 --- a/exercises/practice/bank-account/BankAccountTest.php +++ b/exercises/practice/bank-account/BankAccountTest.php @@ -1,173 +1,224 @@ . - * - * To disable strict typing, comment out the directive below. - */ - declare(strict_types=1); class BankAccountTest extends PHPUnit\Framework\TestCase { - private BankAccount $bankAccount; - public static function setUpBeforeClass(): void { require_once 'BankAccount.php'; } - protected function setUp(): void - { - $this->bankAccount = new BankAccount(); - } - - public function testOpenNewAccount(): void + /** + * uuid: 983a1528-4ceb-45e5-8257-8ce01aceb5ed + * @testdox Newly opened account has zero balance + */ + public function testNewlyOpenedAccountHasZeroBalance(): void { - $this->bankAccount->open(); - $this->assertEquals(0, $this->bankAccount->balance()); + $subject = new BankAccount(); + $subject->open(); + $this->assertEquals(0, $subject->balance()); } + /** + * uuid: e88d4ec3-c6bf-4752-8e59-5046c44e3ba7 + * @testdox Single deposit + */ public function testSingleDeposit(): void { - $this->bankAccount->open(); - $this->bankAccount->deposit(100); - $this->assertEquals(100, $this->bankAccount->balance()); + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(100); + $this->assertEquals(100, $subject->balance()); } + /** + * uuid: 3d9147d4-63f4-4844-8d2b-1fee2e9a2a0d + * @testdox Multiple deposits + */ public function testMultipleDeposits(): void { - $this->bankAccount->open(); - $this->bankAccount->deposit(100); - $this->bankAccount->deposit(50); - $this->assertEquals(150, $this->bankAccount->balance()); - } - - public function testSingleWithdraw(): void - { - $this->bankAccount->open(); - $this->bankAccount->deposit(100); - $this->bankAccount->withdraw(75); - $this->assertEquals(25, $this->bankAccount->balance()); - } - - public function testMultipleWithdraws(): void - { - $this->bankAccount->open(); - $this->bankAccount->deposit(100); - $this->bankAccount->withdraw(80); - $this->bankAccount->withdraw(20); - $this->assertEquals(0, $this->bankAccount->balance()); - } - - public function testMultipleOperations(): void - { - $this->bankAccount->open(); - $this->bankAccount->deposit(100); - $this->bankAccount->deposit(110); - $this->bankAccount->withdraw(200); - $this->bankAccount->deposit(60); - $this->bankAccount->withdraw(50); - $this->assertEquals(20, $this->bankAccount->balance()); - } - - public function testNoBalanceForClosedAccounts() - { - $this->bankAccount->open(); - $this->bankAccount->close(); + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(100); + $subject->deposit(50); + $this->assertEquals(150, $subject->balance()); + } + + /** + * uuid: 08f1af07-27ae-4b38-aa19-770bde558064 + * @testdox Withdraw once + */ + public function testWithdrawOnce(): void + { + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(100); + $subject->withdraw(75); + $this->assertEquals(25, $subject->balance()); + } + + /** + * uuid: 6f6d242f-8c31-4ac6-8995-a90d42cad59f + * @testdox Withdraw twice + */ + public function testWithdrawTwice(): void + { + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(100); + $subject->withdraw(80); + $subject->withdraw(20); + $this->assertEquals(0, $subject->balance()); + } + + /** + * uuid: 45161c94-a094-4c77-9cec-998b70429bda + * @testdox Can do multiple operations sequentially + */ + public function testCanDoMultipleOperationsSequentially(): void + { + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(100); + $subject->deposit(110); + $subject->withdraw(200); + $subject->deposit(60); + $subject->withdraw(50); + $this->assertEquals(20, $subject->balance()); + } + + /** + * uuid: f9facfaa-d824-486e-8381-48832c4bbffd + * @testdox Cannot check balance of closed account + */ + public function testCannotCheckBalanceOfClosedAccount(): void + { + $subject = new BankAccount(); + $subject->open(); + $subject->close(); $this->expectException(Exception::class); $this->expectExceptionMessage('account not open'); - $this->bankAccount->balance(); + $subject->balance(); } - public function testNoDepositsForClosedAccounts() + /** + * uuid: 7a65ba52-e35c-4fd2-8159-bda2bde6e59c + * @testdox Cannot deposit into closed account + */ + public function testCannotDepositIntoClosedAccount(): void { - $this->bankAccount->open(); - $this->bankAccount->close(); + $subject = new BankAccount(); + $subject->open(); + $subject->close(); $this->expectException(Exception::class); $this->expectExceptionMessage('account not open'); - $this->bankAccount->deposit(50); + $subject->deposit(50); } - public function testNoDepositsForUnOpenedAccounts() + /** + * uuid: a0a1835d-faae-4ad4-a6f3-1fcc2121380b + * @testdox Cannot deposit into unopened account + */ + public function testCannotDepositIntoUnopenedAccount(): void { + $subject = new BankAccount(); $this->expectException(Exception::class); $this->expectExceptionMessage('account not open'); - $this->bankAccount->deposit(50); + $subject->deposit(50); } - public function testNoWithdrawsFromClosedAccounts() + /** + * uuid: 570dfaa5-0532-4c1f-a7d3-0f65c3265608 + * @testdox Cannot withdraw from closed account + */ + public function testCannotWithdrawFromClosedAccount(): void { - $this->bankAccount->open(); - $this->bankAccount->close(); + $subject = new BankAccount(); + $subject->open(); + $subject->close(); $this->expectException(Exception::class); $this->expectExceptionMessage('account not open'); - $this->bankAccount->withdraw(50); + $subject->withdraw(50); } - public function testCannotCloseUnOpenedAccounts() + /** + * uuid: c396d233-1c49-4272-98dc-7f502dbb9470 + * @testdox Cannot close an account that was not opened + */ + public function testCannotCloseAnAccountThatWasNotOpened(): void { + $subject = new BankAccount(); $this->expectException(Exception::class); $this->expectExceptionMessage('account not open'); - $this->bankAccount->close(); + $subject->close(); } - public function testCannotOpenExistingAccount() + /** + * uuid: c06f534f-bdc2-4a02-a388-1063400684de + * @testdox Cannot open an already opened account + */ + public function testCannotOpenAnAlreadyOpenedAccount(): void { - $this->bankAccount->open(); + $subject = new BankAccount(); + $subject->open(); $this->expectException(Exception::class); $this->expectExceptionMessage('account already open'); - $this->bankAccount->open(); + $subject->open(); } - public function testReopenedAccountDoesNotKeepBalance() + /** + * uuid: 0722d404-6116-4f92-ba3b-da7f88f1669c + * @testdox Reopened account does not retain balance + */ + public function testReopenedAccountDoesNotRetainBalance(): void { - $this->bankAccount->open(); - $this->bankAccount->deposit(50); - $this->bankAccount->close(); - $this->bankAccount->open(); - $this->assertEquals(0, $this->bankAccount->balance()); + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(50); + $subject->close(); + $subject->open(); + $this->assertEquals(0, $subject->balance()); } - public function testCannotWithdrawMoreThanDeposited() + /** + * uuid: ec42245f-9361-4341-8231-a22e8d19c52f + * @testdox Cannot withdraw more than deposited + */ + public function testCannotWithdrawMoreThanDeposited(): void { - $this->bankAccount->open(); - $this->bankAccount->deposit(25); + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(25); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('amount must be less than balance'); - $this->bankAccount->withdraw(50); + $subject->withdraw(50); } - public function testCannotWithdrawNegativeAmount() + /** + * uuid: 4f381ef8-10ef-4507-8e1d-0631ecc8ee72 + * @testdox Cannot withdraw negative + */ + public function testCannotWithdrawNegative(): void { - $this->bankAccount->open(); - $this->bankAccount->deposit(100); + $subject = new BankAccount(); + $subject->open(); + $subject->deposit(100); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('amount must be greater than 0'); - $this->bankAccount->withdraw(-50); + $subject->withdraw(-50); } - public function testCannotDepositNegativeAmount() + /** + * uuid: d45df9ea-1db0-47f3-b18c-d365db49d938 + * @testdox Cannot deposit negative + */ + public function testCannotDepositNegative(): void { - $this->bankAccount->open(); + $subject = new BankAccount(); + $subject->open(); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('amount must be greater than 0'); - $this->bankAccount->deposit(-50); + $subject->deposit(-50); } }