diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/MoneyOrder.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/MoneyOrder.java new file mode 100644 index 000000000..cf64d93bd --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/MoneyOrder.java @@ -0,0 +1,83 @@ +package com.codedifferently.lesson17.bank; + +import com.codedifferently.lesson17.bank.exceptions.MoneyOrderVoidedException; + +/** Represents a check. */ +public class MoneyOrder { + + private final String moneyOrderNumber; + private final double amount; + private final CheckingAccount account; + private boolean isVoided = false; + + /** + * Creates a new check. + * + * @param moneyOrderNumber The check number. + * @param amount The amount of the check. + * @param account The account the check is drawn on. + */ + public MoneyOrder(String moneyOrderNumber, double amount, CheckingAccount account) { + if (amount < 0) { + throw new IllegalArgumentException("Money Order amount must be positive"); + } + this.moneyOrderNumber = moneyOrderNumber; + this.account = account; + account.withdraw(amount); + this.amount = amount; + } + + /** + * Gets the voided status of the check. + * + * @return True if the check is voided, and false otherwise. + */ + public boolean getIsVoided() { + return isVoided; + } + + /** Voids the MoneyOrder. */ + public void voidMoneyOrder() { + isVoided = true; + } + + /** + * Deposits the money order into an account. + * + * @param toAccount The account to deposit the money order into. + */ + public void depositFunds(CheckingAccount toAccount) { + if (isVoided) { + throw new MoneyOrderVoidedException("Money order is voided"); + } + account.withdraw(amount); + toAccount.deposit(amount); + voidMoneyOrder(); + } + + @Override + public int hashCode() { + return moneyOrderNumber.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MoneyOrder other) { + return moneyOrderNumber.equals(other.moneyOrderNumber); + } + return false; + } + + @Override + public String toString() { + return "Money Order{" + + "money Order Number='" + + moneyOrderNumber + + '\'' + + ", amount=" + + amount + + ", account=" + + account.getAccountNumber() + + '}'; + } +} diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingAccount.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingAccount.java new file mode 100644 index 000000000..c7287a38c --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingAccount.java @@ -0,0 +1,111 @@ +package com.codedifferently.lesson17.bank; + +import java.util.Set; + +/** Represents a saving account. */ +public class SavingAccount { + + private final Set owners; + private final String accountNumber; + private double balance; + private boolean isActive; + + /** + * Creates a new saving account. + * + * @param accountNumber The account number. + * @param owners The owners of the account. + * @param initialBalance The initial balance of the account. + */ + public SavingAccount(String accountNumber, Set owners, double initialBalance) { + this.accountNumber = accountNumber; + this.owners = owners; + this.balance = initialBalance; + isActive = true; + } + + /** + * Gets the account number. + * + * @return The account number. + */ + public String getAccountNumber() { + return accountNumber; + } + + /** + * Gets the owners of the account. + * + * @return The owners of the account. + */ + public Set getOwners() { + return owners; + } + + /** + * Deposits funds into the account. + * + * @param amount The amount to deposit. + */ + public void deposit(double amount) throws IllegalStateException { + if (isClosed()) { + throw new IllegalStateException("Cannot deposit to a closed account"); + } + if (amount <= 0) { + throw new IllegalArgumentException("Deposit amount must be positive"); + } + balance += amount; + } + + /** + * Gets the balance of the account. + * + * @return The balance of the account. + */ + public double getBalance() { + return balance; + } + + /** Closes the account. */ + public void closeAccount() throws IllegalStateException { + if (balance > 0) { + throw new IllegalStateException("Cannot close account with a positive balance"); + } + isActive = false; + } + + /** + * Checks if the account is closed. + * + * @return True if the account is closed, otherwise false. + */ + public boolean isClosed() { + return !isActive; + } + + @Override + public int hashCode() { + return accountNumber.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SavingAccount other) { + return accountNumber.equals(other.accountNumber); + } + return false; + } + + @Override + public String toString() { + return "SavingAccount{" + + "accountNumber='" + + accountNumber + + '\'' + + ", balance=" + + balance + + ", isActive=" + + isActive + + '}'; + } +} diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/exceptions/MoneyOrderVoidedException.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/exceptions/MoneyOrderVoidedException.java new file mode 100644 index 000000000..d788f9766 --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/exceptions/MoneyOrderVoidedException.java @@ -0,0 +1,9 @@ +package com.codedifferently.lesson17.bank.exceptions; + +public class MoneyOrderVoidedException extends RuntimeException { + public MoneyOrderVoidedException() {} + + public MoneyOrderVoidedException(String message) { + super(message); + } +} diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/MoneyOrderTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/MoneyOrderTest.java new file mode 100644 index 000000000..5eb1c8fa2 --- /dev/null +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/MoneyOrderTest.java @@ -0,0 +1,89 @@ +package com.codedifferently.lesson17.bank; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import com.codedifferently.lesson17.bank.exceptions.MoneyOrderVoidedException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class MoneyOrderTest { + + private CheckingAccount account1; + private CheckingAccount account2; + private MoneyOrder classUnderTest; + + @BeforeEach + void setUp() { + account1 = new CheckingAccount("123456789", null, 200.0); + account2 = new CheckingAccount("987654321", null, 300.0); + classUnderTest = new MoneyOrder("123456789", 50.0, account1); + } + + @Test + void testInitializesProperly() { + // Arrange + double balanceAfterMoneyOrder = account1.getBalance(); + + // Act - happened upon money order creation + + // Assert + assertThat(balanceAfterMoneyOrder).isEqualTo(150.0); + } + + @Test + void testDepositFunds() { + // Act + classUnderTest.depositFunds(account2); + + // Assert + assertThat(account1.getBalance()).isEqualTo(100.0); + assertThat(account2.getBalance()).isEqualTo(350.0); + } + + @Test + void testDepositFunds_MoneyOrderVoided() { + // Arrange + classUnderTest.voidMoneyOrder(); + + // Act & Assert + assertThatExceptionOfType(MoneyOrderVoidedException.class) + .isThrownBy(() -> classUnderTest.depositFunds(account2)) + .withMessage("Money order is voided"); + } + + @Test + void testConstructor_CantCreateCheckWithNegativeAmount() { + // Act & Assert + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new MoneyOrder("123456789", -50.0, account1)) + .withMessage("Money Order amount must be positive"); + } + + @Test + void testHashCode() { + // Arrange + MoneyOrder otherMoneyOrder = new MoneyOrder("123456789", 100.0, account1); + + // Assert + assertThat(classUnderTest.hashCode()).isEqualTo(otherMoneyOrder.hashCode()); + } + + @Test + void testEquals() { + // Arrange + MoneyOrder otherCheck = new MoneyOrder("123456789", 25.0, account1); + MoneyOrder differentCheck = new MoneyOrder("987654321", 25.0, account1); + + // Assert + assertThat(classUnderTest.equals(otherCheck)).isTrue(); + assertThat(classUnderTest.equals(differentCheck)).isFalse(); + } + + @Test + void testToString() { + // Assert + assertThat(classUnderTest.toString()) + .isEqualTo("Money Order{money Order Number='123456789', amount=50.0, account=123456789}"); + } +} diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingAccountTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingAccountTest.java new file mode 100644 index 000000000..04deceef9 --- /dev/null +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingAccountTest.java @@ -0,0 +1,75 @@ +package com.codedifferently.lesson17.bank; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SavingAccountTest { + + private SavingAccount classUnderTest; + private Set owners; + + @BeforeEach + void setUp() { + owners = new HashSet<>(); + owners.add(new Customer(UUID.randomUUID(), "John Doe")); + owners.add(new Customer(UUID.randomUUID(), "Jane Smith")); + classUnderTest = new SavingAccount("123456789", owners, 100.0); + } + + @Test + void getAccountNumber() { + assertEquals("123456789", classUnderTest.getAccountNumber()); + } + + @Test + void getOwners() { + assertEquals(owners, classUnderTest.getOwners()); + } + + @Test + void deposit() { + classUnderTest.deposit(50.0); + assertEquals(150.0, classUnderTest.getBalance()); + } + + @Test + void deposit_withNegativeAmount() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> classUnderTest.deposit(-50.0)); + } + + @Test + void getBalance() { + assertEquals(100.0, classUnderTest.getBalance()); + } + + @Test + void closeAccount_withPositiveBalance() { + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> classUnderTest.closeAccount()); + } + + @Test + void equals() { + SavingAccount otherAccount = new SavingAccount("123456789", owners, 200.0); + assertEquals(classUnderTest, otherAccount); + } + + @Test + void hashCodeTest() { + SavingAccount otherAccount = new SavingAccount("123456789", owners, 200.0); + assertEquals(classUnderTest.hashCode(), otherAccount.hashCode()); + } + + @Test + void toStringTest() { + String expected = "SavingAccount{accountNumber='123456789', balance=100.0, isActive=true}"; + assertEquals(expected, classUnderTest.toString()); + } +}