diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Account.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Account.java new file mode 100644 index 000000000..3e9ac5315 --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Account.java @@ -0,0 +1,20 @@ +package com.codedifferently.lesson17.bank; + +import com.codedifferently.lesson17.bank.exceptions.InsufficientFundsException; +import java.util.Set; + +public interface Account { + String getAccountNumber(); + + Set getOwners(); + + void deposit(double amount); + + void withdraw(double amount) throws InsufficientFundsException; + + double getBalance(); + + void closeAccount(); + + boolean isClosed(); +} diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CheckingAccount.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CheckingAccount.java index 5d8aeb74d..7a0b8c807 100644 --- a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CheckingAccount.java +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CheckingAccount.java @@ -4,7 +4,7 @@ import java.util.Set; /** Represents a checking account. */ -public class CheckingAccount { +public class CheckingAccount implements Account { private final Set owners; private final String accountNumber; @@ -30,6 +30,7 @@ public CheckingAccount(String accountNumber, Set owners, double initia * * @return The account number. */ + @Override public String getAccountNumber() { return accountNumber; } @@ -39,6 +40,7 @@ public String getAccountNumber() { * * @return The owners of the account. */ + @Override public Set getOwners() { return owners; } @@ -48,6 +50,7 @@ public Set getOwners() { * * @param amount The amount to deposit. */ + @Override public void deposit(double amount) throws IllegalStateException { if (isClosed()) { throw new IllegalStateException("Cannot deposit to a closed account"); @@ -64,6 +67,7 @@ public void deposit(double amount) throws IllegalStateException { * @param amount * @throws InsufficientFundsException */ + @Override public void withdraw(double amount) throws InsufficientFundsException { if (isClosed()) { throw new IllegalStateException("Cannot withdraw from a closed account"); @@ -82,11 +86,13 @@ public void withdraw(double amount) throws InsufficientFundsException { * * @return The balance of the account. */ + @Override public double getBalance() { return balance; } /** Closes the account. */ + @Override public void closeAccount() throws IllegalStateException { if (balance > 0) { throw new IllegalStateException("Cannot close account with a positive balance"); @@ -99,6 +105,7 @@ public void closeAccount() throws IllegalStateException { * * @return True if the account is closed, otherwise false. */ + @Override public boolean isClosed() { return !isActive; } diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java new file mode 100644 index 000000000..0c15a9b1d --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java @@ -0,0 +1,96 @@ +package com.codedifferently.lesson17.bank; + +import com.codedifferently.lesson17.bank.exceptions.InsufficientFundsException; +import java.util.Set; + +public class SavingsAccount implements Account { + + private final Set owners; + private final String accountNumber; + private double balance; + private boolean isActive; + + public SavingsAccount(String accountNumber, Set owners, double initialBalance) { + this.accountNumber = accountNumber; + this.owners = owners; + this.balance = initialBalance; + this.isActive = true; + } + + @Override + public String getAccountNumber() { + return accountNumber; + } + + @Override + public Set getOwners() { + return owners; + } + + @Override + public void deposit(double amount) { + if (isClosed()) { + throw new IllegalStateException("Cannot deposit to a closed account"); + } + if (amount <= 0) { + throw new IllegalArgumentException("Deposit amount must be positive"); + } + balance += amount; + } + + @Override + public void withdraw(double amount) throws InsufficientFundsException { + if (isClosed()) { + throw new IllegalStateException("Cannot withdraw from a closed account"); + } + if (amount <= 0) { + throw new IllegalArgumentException("Withdrawal amount must be positive"); + } + if (balance < amount) { + throw new InsufficientFundsException("Account does not have enough funds for withdrawal"); + } + balance -= amount; + } + + @Override + public double getBalance() { + return balance; + } + + @Override + public void closeAccount() { + if (balance > 0) { + throw new IllegalStateException("Cannot close account with a positive balance"); + } + isActive = false; + } + + @Override + public boolean isClosed() { + return !isActive; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SavingsAccount other = (SavingsAccount) obj; + return accountNumber.equals(other.accountNumber) + && Double.compare(other.balance, balance) == 0 + && isActive == other.isActive + && owners.equals(other.owners); + } + + @Override + public int hashCode() { + int result = accountNumber.hashCode(); + result = 31 * result + Double.hashCode(balance); + result = 31 * result + Boolean.hashCode(isActive); + result = 31 * result + owners.hashCode(); + return result; + } +} diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java new file mode 100644 index 000000000..c5a743cba --- /dev/null +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java @@ -0,0 +1,98 @@ +package com.codedifferently.lesson17.bank; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.codedifferently.lesson17.bank.exceptions.InsufficientFundsException; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SavingsAccountTest { + + private SavingsAccount savingsAccount; + private Set accountOwners; + + @BeforeEach + void setUp() { + accountOwners = new HashSet<>(); + accountOwners.add(new Customer(UUID.randomUUID(), "John Doe")); + savingsAccount = new SavingsAccount("987654321", accountOwners, 200.0); + } + + @Test + void shouldReturnAccountNumber() { + assertEquals("987654321", savingsAccount.getAccountNumber()); + } + + @Test + void shouldReturnAccountOwners() { + assertEquals(accountOwners, savingsAccount.getOwners()); + } + + @Test + void shouldDepositFundsSuccessfully() { + savingsAccount.deposit(100.0); + assertEquals(300.0, savingsAccount.getBalance()); + } + + @Test + void shouldThrowExceptionForNegativeDeposit() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> savingsAccount.deposit(-20.0)); + } + + @Test + void shouldWithdrawFundsSuccessfully() { + savingsAccount.withdraw(50.0); + assertEquals(150.0, savingsAccount.getBalance()); + } + + @Test + void shouldThrowExceptionForNegativeWithdrawalAmount() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> savingsAccount.withdraw(-10.0)) + .withMessage("Withdrawal amount must be positive"); + } + + @Test + void shouldThrowExceptionForInsufficientBalance() { + assertThatExceptionOfType(InsufficientFundsException.class) + .isThrownBy(() -> savingsAccount.withdraw(500.0)) + .withMessage("Account does not have enough funds for withdrawal"); + } + + @Test + void shouldReturnBalance() { + assertEquals(200.0, savingsAccount.getBalance()); + } + + @Test + void shouldThrowExceptionWhenClosingAccountWithPositiveBalance() { + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> savingsAccount.closeAccount()); + } + + @Test + void shouldBeClosedAfterWithdrawAndClose() { + savingsAccount.withdraw(200.0); + savingsAccount.closeAccount(); + assertTrue(savingsAccount.isClosed()); + } + + @Test + void shouldCheckEqualityAndHashCode() { + Set owners = new HashSet<>(); + owners.add(new Customer(UUID.randomUUID(), "John Doe")); + + SavingsAccount account1 = new SavingsAccount("987654321", owners, 200.0); + SavingsAccount account2 = new SavingsAccount("987654321", owners, 200.0); + + assertEquals(account1, account2); + + assertEquals(account1.hashCode(), account2.hashCode()); + } +}