diff --git a/.gitignore b/.gitignore index 4cc292d8..f1e7b433 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ target/ +.idea/ +SoftwareEngineeringPractice.iml # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 28c6362f..00000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index b26911bd..00000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 750d1d0b..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/sbt.xml b/.idea/sbt.xml deleted file mode 100644 index 20187435..00000000 --- a/.idea/sbt.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddf..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 87c23b2d..38d52c6e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ # SoftwareEngineeringPractice -## grading - -To Do | correct ----|--- -at least 8 commits| -isEmailValid| -withdraw| -isamountValid| -constructor & withdraw fix| + +Use Case Diagram: https://www.lucidchart.com/invitations/accept/4307fa3a-0405-408d-ba36-95b8793790b6 + +Class Diagram: https://www.draw.io/#G14lOqCFtOO7uEm51Zpj4FGR7ti2bjM54R + +Sequence Diagram (Saul): Teller, User, Account https://drive.google.com/file/d/1OXqnUsb1rqihpPv-qyBwDjLqungH4SJd/view?usp=sharing + +Sequence Diagram (Josh): Admin, Account, CentralBank https://drive.google.com/file/d/1hWu4E4gvjYxcYmPHV18QAMbwkdUuo9Hd/view?usp=sharing + +Sequence Diagram (Erich): https://drive.google.com/file/d/1tcE_ITNZHlpZ7IzYDILuwuuKqsxNMex5/view?usp=sharing + +Code Review Notes: Need to update class diagram to no longer have user. Update use case diagram to be more readable. +Generally we want to update tests, Josh will update Admin system test to test for more than two accounts. Saul will make sure method names match the diagram. Eric will update some other tests. diff --git a/SoftwareEngineeringPractice.iml b/SoftwareEngineeringPractice.iml deleted file mode 100644 index 78b2cc53..00000000 --- a/SoftwareEngineeringPractice.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/src/main/java/edu/ithaca/dragon/bank/ATM.java b/src/main/java/edu/ithaca/dragon/bank/ATM.java new file mode 100644 index 00000000..6e21a09b --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/ATM.java @@ -0,0 +1,45 @@ +package edu.ithaca.dragon.bank; + +public class ATM implements BasicAPI { + + protected CentralBank centralBank; + + public ATM(CentralBank bank) { + centralBank = bank; + } + + @Override + public boolean confirmCredentials(String acctId, String password) { + return false; + } + + @Override + public double checkBalance(String acctId) { + + return centralBank.checkBalance(acctId); + } + + @Override + public void withdraw(String acctId, double amount) throws AccountFrozenException, InsufficientFundsException { + centralBank.withdraw(acctId, amount); + } + + @Override + public void deposit(String acctId, double amount) throws AccountFrozenException { + centralBank.deposit(acctId, amount); + } + + @Override + public void transfer(String acctIdToWithdrawFrom, String acctIdToDepositTo, double amount) throws InsufficientFundsException, AccountFrozenException { + centralBank.transfer(acctIdToWithdrawFrom, acctIdToDepositTo, amount); + } + + @Override + public String transactionHistory(String acctId) { + return null; + } + + public CentralBank getCentralBank() { + return centralBank; + } +} diff --git a/src/main/java/edu/ithaca/dragon/bank/Account.java b/src/main/java/edu/ithaca/dragon/bank/Account.java new file mode 100644 index 00000000..55fab9a3 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/Account.java @@ -0,0 +1,117 @@ +package edu.ithaca.dragon.bank; + +import java.util.Collection; +import java.util.regex.Pattern; + +public abstract class Account { + protected double balance; + protected boolean isFrozen; + protected Collection users; + protected String id; + + + public Account(double startingBalance, String id) { + if (!isAmountValid(startingBalance)) { + throw new IllegalArgumentException("Starting balance: " + startingBalance + " is invalid, cannot create account"); + } + else if (id.equals("")){ + throw new IllegalArgumentException("ID cannot be an empty string"); + } + else { + this.balance = startingBalance; + this.isFrozen = false; + this.id = id; + } + } + + /** + * reduces the balance by amount if amount is non-negative, has 2 or fewer decimals and is smaller or equal to balance + * @param amount quantity to reduce balance by + * @throws IllegalArgumentException if amount is negative or has more than 2 decimals + * @throws InsufficientFundsException if amount is larger than balance + */ + public void withdraw(double amount) throws InsufficientFundsException, AccountFrozenException{ + if (isFrozen){ + throw new AccountFrozenException("Account is frozen"); + } + else if (!isAmountValid(amount)) { + throw new IllegalArgumentException("Amount: " + amount + " is invalid, cannot withdraw"); + } else if (amount > balance) { + throw new InsufficientFundsException("Not enough money"); + } else { + balance -= amount; + } + } + + /** + * increases the balance by amount if non-negative and has 2 or fewer decimals + * @param amount quantity to increase balance by + * @throws IllegalArgumentException if amount is negative or has more than 2 decimal places + */ + public void deposit(double amount) throws AccountFrozenException{ + if (isFrozen){ + throw new AccountFrozenException("Account is frozen"); + } + else if (!isAmountValid(amount)) { + throw new IllegalArgumentException("Amount: " + amount + " is invalid, cannot deposit"); + } else { + balance += amount; + } + } + + /** + * withdraws amount from balance and deposits it into to's balance + * @param toAccount BankAccount who's balance will be deposited into + * @param amount quantity to withdraw from balance and deposit into to's balance + * @throws IllegalArgumentException if amount is negative or has more than 2 decimals + * @throws InsufficientFundsException if amount is larger than balance + */ + public void transfer(Account toAccount, double amount) throws InsufficientFundsException, AccountFrozenException { + if (this.isFrozen || toAccount.isFrozen){ + throw new AccountFrozenException("Account is frozen"); + } + else if (!isAmountValid(amount)) { + throw new IllegalArgumentException("Amount: " + amount + " is invalid, cannot transfer"); + } else if (amount > balance) { + throw new InsufficientFundsException("Not enough money"); + } else { + withdraw(amount); + toAccount.deposit(amount); + } + } + + public String getCredentials() { + return ""; + } + + public double getBalance() { + return balance; + } + + public String getHistory() { + return ""; + } + + public boolean getFrozenStatus(){ + return isFrozen; + } + + public void setFrozen(boolean frozenStatus){ + isFrozen = frozenStatus; + } + + public String getID(){ + return id; + } + + /** + * returns true if the amount is non-negative and has two decimal points or less, and false otherwise + * @param amount quantity to check + * @return true if the amount is non-negative and has two decimal points or less, and false otherwise + */ + public static boolean isAmountValid(double amount) { + String amountStr = String.valueOf(amount); + int charsAfterDec = amountStr.length() - amountStr.indexOf('.') - 1; + return amount >= 0 && charsAfterDec <= 2; + } +} diff --git a/src/main/java/edu/ithaca/dragon/bank/AccountFrozenException.java b/src/main/java/edu/ithaca/dragon/bank/AccountFrozenException.java new file mode 100644 index 00000000..57a7b7a4 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/AccountFrozenException.java @@ -0,0 +1,9 @@ +package edu.ithaca.dragon.bank; + +public class AccountFrozenException extends Exception{ + + public AccountFrozenException(String s){ + super(s); + } + +} \ No newline at end of file diff --git a/src/main/java/edu/ithaca/dragon/bank/Admin.java b/src/main/java/edu/ithaca/dragon/bank/Admin.java new file mode 100644 index 00000000..da659ab6 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/Admin.java @@ -0,0 +1,63 @@ +package edu.ithaca.dragon.bank; + +import java.util.Collection; +import java.util.Iterator; +import java.math.RoundingMode; +import java.text.DecimalFormat; + + + +public class Admin implements AdminAPI { + private static DecimalFormat twoDecimals = new DecimalFormat("0.00"); + CentralBank bank; + + + /** + * creates an Admin account that knows what accounts it controls + * @param bank the CentralBank that Admin must act on + */ + public Admin(CentralBank bank){ + this.bank = bank; + } + + @Override + public double calcTotalAssets() { + double total = 0; + Iterator itr = this.bank.getAccounts().values().iterator(); + while (itr.hasNext()){ + Account current = itr.next(); + total += current.getBalance(); + } + total = Double.valueOf(twoDecimals.format(total)); + + return total; + } + + @Override + public Collection findAcctIdsWithSuspiciousActivity() { + return null; + } + + @Override + public void freezeAccount(String acctId) throws IllegalArgumentException { + setAcctFreezeStatus(acctId,true); + } + + @Override + public void unfreezeAcct(String acctId) throws IllegalArgumentException { + setAcctFreezeStatus(acctId,false); + } + + public void setAcctFreezeStatus(String acctId, boolean isFrozen) { + boolean accountFound = (bank.getAccounts().containsKey(acctId)); + if(accountFound) { + bank.getAccounts().get(acctId).setFrozen(isFrozen); + } else { + throw new IllegalArgumentException("String not in collection"); + } + } + + public CentralBank getBank(){ + return this.bank; + } +} diff --git a/src/main/java/edu/ithaca/dragon/bank/AdminAPI.java b/src/main/java/edu/ithaca/dragon/bank/AdminAPI.java new file mode 100644 index 00000000..b11e2b4e --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/AdminAPI.java @@ -0,0 +1,15 @@ +package edu.ithaca.dragon.bank; + +import java.util.Collection; + +public interface AdminAPI { + + public double calcTotalAssets(); + + public Collection findAcctIdsWithSuspiciousActivity(); + + public void freezeAccount(String acctId); + + public void unfreezeAcct(String acctId); + +} diff --git a/src/main/java/edu/ithaca/dragon/bank/AdvancedAPI.java b/src/main/java/edu/ithaca/dragon/bank/AdvancedAPI.java new file mode 100644 index 00000000..26253541 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/AdvancedAPI.java @@ -0,0 +1,9 @@ +package edu.ithaca.dragon.bank; + +//API to be used by Teller systems +public interface AdvancedAPI extends BasicAPI { + + public void createAccount(String acctId, double startingBalance); + + public void closeAccount(String acctId); +} diff --git a/src/main/java/edu/ithaca/dragon/bank/BankAccount.java b/src/main/java/edu/ithaca/dragon/bank/BankAccount.java index 8e35fb64..edd82d30 100644 --- a/src/main/java/edu/ithaca/dragon/bank/BankAccount.java +++ b/src/main/java/edu/ithaca/dragon/bank/BankAccount.java @@ -1,21 +1,25 @@ package edu.ithaca.dragon.bank; +import java.math.BigDecimal; +import java.util.regex.Pattern; + public class BankAccount { private String email; private double balance; /** - * @throws IllegalArgumentException if email is invalid + * @throws IllegalArgumentException if email is invalid, or startingBalance is negative or has more than 2 decimal places */ - public BankAccount(String email, double startingBalance){ - if (isEmailValid(email)){ + public BankAccount(String email, double startingBalance) { + if (!isEmailValid(email)) { + throw new IllegalArgumentException("Email address: " + email + " is invalid, cannot create account"); + } else if (!isAmountValid(startingBalance)) { + throw new IllegalArgumentException("Starting balance: " + startingBalance + " is invalid, cannot create account"); + } else { this.email = email; this.balance = startingBalance; } - else { - throw new IllegalArgumentException("Email address: " + email + " is invalid, cannot create account"); - } } public double getBalance(){ @@ -27,24 +31,65 @@ public String getEmail(){ } /** - * @post reduces the balance by amount if amount is non-negative and smaller than balance + * reduces the balance by amount if amount is non-negative, has 2 or fewer decimals and is smaller or equal to balance + * @param amount quantity to reduce balance by + * @throws IllegalArgumentException if amount is negative or has more than 2 decimals + * @throws InsufficientFundsException if amount is larger than balance */ - public void withdraw (double amount) throws InsufficientFundsException{ - if (amount <= balance){ + public void withdraw(double amount) throws InsufficientFundsException { + if (!isAmountValid(amount)) { + throw new IllegalArgumentException("Amount: " + amount + " is invalid, cannot withdraw"); + } else if (amount > balance) { + throw new InsufficientFundsException("Not enough money"); + } else { balance -= amount; } - else { + } + + /** + * increases the balance by amount if non-negative and has 2 or fewer decimals + * @param amount quantity to increase balance by + * @throws IllegalArgumentException if amount is negative or has more than 2 decimal places + */ + public void deposit(double amount) { + if (!isAmountValid(amount)) { + throw new IllegalArgumentException("Amount: " + amount + " is invalid, cannot deposit"); + } else { + balance += amount; + } + } + + /** + * withdraws amount from balance and deposits it into to's balance + * @param to BankAccount who's balance will be deposited into + * @param amount quantity to withdraw from balance and deposit into to's balance + * @throws IllegalArgumentException if amount is negative or has more than 2 decimals + * @throws InsufficientFundsException if amount is larger than balance + */ + public void transfer(BankAccount to, double amount) throws InsufficientFundsException { + if (!isAmountValid(amount)) { + throw new IllegalArgumentException("Amount: " + amount + " is invalid, cannot transfer"); + } else if (amount > balance) { throw new InsufficientFundsException("Not enough money"); + } else { + withdraw(amount); + to.deposit(amount); } } + public static boolean isEmailValid(String email) { + String regex = "[\\w-]+(\\.[\\w]+)*(?= 0 && charsAfterDec <= 2; } } diff --git a/src/main/java/edu/ithaca/dragon/bank/BasicAPI.java b/src/main/java/edu/ithaca/dragon/bank/BasicAPI.java new file mode 100644 index 00000000..9231b8ce --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/BasicAPI.java @@ -0,0 +1,18 @@ +package edu.ithaca.dragon.bank; + +//API to be used by ATMs +public interface BasicAPI { + + boolean confirmCredentials(String acctId, String password); + + double checkBalance(String acctId); + + void withdraw(String acctId, double amount) throws InsufficientFundsException, AccountFrozenException; + + void deposit(String acctId, double amount) throws AccountFrozenException; + + void transfer(String acctIdToWithdrawFrom, String acctIdToDepositTo, double amount) throws InsufficientFundsException, AccountFrozenException; + + String transactionHistory(String acctId); + +} diff --git a/src/main/java/edu/ithaca/dragon/bank/CentralBank.java b/src/main/java/edu/ithaca/dragon/bank/CentralBank.java new file mode 100644 index 00000000..4ba330d3 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/CentralBank.java @@ -0,0 +1,60 @@ +package edu.ithaca.dragon.bank; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class CentralBank { + + private Collection atms; + private Map accounts; + private Collection admins; + private Collection users; + + public CentralBank(){ + atms = new ArrayList(); + accounts = new HashMap(); + admins = new ArrayList(); + users = new ArrayList(); + } + + + public void withdraw(String account, double amount) throws InsufficientFundsException, AccountFrozenException{ + if(!accounts.containsKey(account)) throw new IllegalArgumentException("No Account with ID: " + account); + accounts.get(account).withdraw(amount); + } + + public void deposit(String account, double amount) throws AccountFrozenException{ + if(!accounts.containsKey(account)) throw new IllegalArgumentException("No Account with ID: " + account); + accounts.get(account).deposit(amount); + } + + public void transfer(String fromAccount, String toAccount, double amount) throws InsufficientFundsException, AccountFrozenException{ + if(!accounts.containsKey(fromAccount)) throw new IllegalArgumentException("No Account with ID: " + fromAccount); + if(!accounts.containsKey(toAccount)) throw new IllegalArgumentException("No Account with ID: " + toAccount); + + accounts.get(fromAccount).transfer(accounts.get(toAccount), amount); + } + + public String getCredentials(String account) { + return accounts.get(account).getCredentials(); + } + + public double checkBalance(String account) { + return accounts.get(account).getBalance(); + } + + public String getHistory(String account) { + return accounts.get(account).getHistory(); + } + + public void setAccounts(Map newAccounts) { + accounts = newAccounts; + } + + public Map getAccounts() { + return accounts; + } + +} diff --git a/src/main/java/edu/ithaca/dragon/bank/CheckingAccount.java b/src/main/java/edu/ithaca/dragon/bank/CheckingAccount.java new file mode 100644 index 00000000..cb09b8cb --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/CheckingAccount.java @@ -0,0 +1,10 @@ +package edu.ithaca.dragon.bank; + +import java.util.Collection; + +public class CheckingAccount extends Account { + + public CheckingAccount(double startingBalance, String id) { + super(startingBalance, id); + } +} diff --git a/src/main/java/edu/ithaca/dragon/bank/SavingsAccount.java b/src/main/java/edu/ithaca/dragon/bank/SavingsAccount.java new file mode 100644 index 00000000..565fdf60 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/SavingsAccount.java @@ -0,0 +1,26 @@ +package edu.ithaca.dragon.bank; + +public class SavingsAccount extends Account { + private double interestRate; + private double maximumWithdrawal; + + + public SavingsAccount(double startingBalance, double interestRate, double maximumWithdrawal, String id) { + super(startingBalance, id); + this.interestRate = interestRate; + this.maximumWithdrawal = maximumWithdrawal; + } + + @Override + public void withdraw(double amount) throws InsufficientFundsException, AccountFrozenException { + if(amount <= maximumWithdrawal) { + super.withdraw(amount); + } else { + throw new IllegalArgumentException("Amount is greater than maximum withdrawal amount"); + } + } + + public void calculateInterest() { + balance += balance * interestRate; + } +} diff --git a/src/main/java/edu/ithaca/dragon/bank/Teller.java b/src/main/java/edu/ithaca/dragon/bank/Teller.java new file mode 100644 index 00000000..968fbdd4 --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/Teller.java @@ -0,0 +1,24 @@ +package edu.ithaca.dragon.bank; + +import java.rmi.NoSuchObjectException; +import java.util.NoSuchElementException; + +public class Teller extends ATM implements AdvancedAPI { + + public Teller(CentralBank bank) { + super(bank); + } + + @Override + public void createAccount(String acctId, double startingBalance) { + centralBank.getAccounts().put(acctId, new CheckingAccount(startingBalance, acctId)); + } + + @Override + public void closeAccount(String acctId) { + Account account = centralBank.getAccounts().remove(acctId); + if (account == null) { + throw new NoSuchElementException("That account does not exist"); + } + } +} diff --git a/src/main/java/edu/ithaca/dragon/bank/User.java b/src/main/java/edu/ithaca/dragon/bank/User.java new file mode 100644 index 00000000..d96d35ee --- /dev/null +++ b/src/main/java/edu/ithaca/dragon/bank/User.java @@ -0,0 +1,33 @@ +package edu.ithaca.dragon.bank; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class User { + private Map accounts; + + public User() { + accounts = new HashMap(); + } + + public void addAccount(Account accountToAdd) { + accounts.put(accountToAdd.getID(), accountToAdd); + } + + public void removeAccount(String id) { + if(accounts.containsKey(id)) { + accounts.remove(id); + } else { + throw new IllegalArgumentException("User does not contain account with id: " + id); + } + } + + public Account getAccount(String id) { + if(accounts.containsKey(id)) { + return accounts.get(id); + } else { + throw new IllegalArgumentException("User does not contain account with id: " + id); + } + } +} diff --git a/src/test/java/edu/ithaca/dragon/bank/ATMTest.java b/src/test/java/edu/ithaca/dragon/bank/ATMTest.java new file mode 100644 index 00000000..3e608e54 --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/ATMTest.java @@ -0,0 +1,67 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class ATMTest { + + @Test + void constructorTest() { + CentralBank bank = new CentralBank(); + ATM a = new ATM(bank); + + assertEquals(bank, a.getCentralBank()); + } + + @Test + void checkBalanceTest() { + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + ATM a = new ATM(bank); + + assertEquals(100, a.checkBalance("abc")); + } + + @Test + void withdrawTest() throws InsufficientFundsException, AccountFrozenException{ + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + ATM a = new ATM(bank); + + a.withdraw("abc", 50); + assertEquals(50, a.checkBalance("abc")); + assertThrows(InsufficientFundsException.class, () -> a.withdraw("abc", 100)); + assertThrows(IllegalArgumentException.class, () -> a.withdraw( "help", 100)); + + } + + @Test + void depositTest() throws AccountFrozenException{ + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + ATM a = new ATM(bank); + + a.deposit("abc", 100); + assertEquals(200, a.checkBalance("abc")); + assertThrows(IllegalArgumentException.class, () -> a.deposit( "help", 100)); + + } + + @Test + void transferTest() throws InsufficientFundsException, AccountFrozenException{ + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + bank.getAccounts().put("def", new CheckingAccount(100, "abc")); + ATM a = new ATM(bank); + + a.transfer("abc", "def", 50); + assertEquals(50, a.checkBalance("abc")); + assertEquals(150, a.checkBalance("def")); + + assertThrows(InsufficientFundsException.class, () -> a.transfer("abc", "def", 200)); + assertThrows(IllegalArgumentException.class, () -> a.transfer("abc", "help", 100)); + } + + + +} diff --git a/src/test/java/edu/ithaca/dragon/bank/AccountTest.java b/src/test/java/edu/ithaca/dragon/bank/AccountTest.java new file mode 100644 index 00000000..0a8414a4 --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/AccountTest.java @@ -0,0 +1,285 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; + + +import static org.junit.jupiter.api.Assertions.*; + +public class AccountTest { + + private static final double THRESHOLD = 0.001; + + @Test + void withdrawTest() throws InsufficientFundsException, AccountFrozenException{ + Account bankAccount = new CheckingAccount(1000, "a@b.com"); + + //non-negative amount less than or equal to balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(3141.592)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(Double.MIN_VALUE)); + + //non-negative amount greater than balance with two decimal places or less + assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(1000.01)); + assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(5432)); + assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(3216.8)); + + //non-negative amount greater than balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(1000.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(9876.543)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(Double.MAX_VALUE)); + + //negative amount with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.01)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.99)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-2718.2)); + + //negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-14850.607)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-Double.MAX_VALUE)); + + bankAccount.setFrozen(true); + //Checking that you can't withdraw from frozen account + assertThrows(AccountFrozenException.class, () -> bankAccount.withdraw(0)); + assertThrows(AccountFrozenException.class, () -> bankAccount.withdraw(100)); + + //Check that AccountFrozen has higher priority than illegal argument and insufficient funds + assertThrows(AccountFrozenException.class, () -> bankAccount.withdraw(5.1234)); + assertThrows(AccountFrozenException.class, () -> bankAccount.withdraw(-50)); + assertThrows(AccountFrozenException.class, () -> bankAccount.withdraw(1000.01)); + assertThrows(AccountFrozenException.class, () -> bankAccount.withdraw(2000.1234)); + + + + bankAccount.setFrozen(false); + + //non-negative amount less than or equal to balance with two decimal places or less + bankAccount.withdraw(0); + assertEquals(1000, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(100); + assertEquals(900, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(0.01); + assertEquals(899.99, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(898.99); + assertEquals(1, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(1); + assertEquals(0, bankAccount.getBalance(), THRESHOLD); + } + + @Test + void depositTest() throws AccountFrozenException { + + Account bankAccount = new CheckingAccount( 0, "1"); + + //non-negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(1010.101)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(Double.MAX_VALUE)); + + //negative amount with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.01)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.99)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-8008.2)); + + //negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-5000.125)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-Double.MAX_VALUE)); + + //non-negative amount with two decimal places or less + bankAccount.deposit(0); + assertEquals(0, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(10); + assertEquals(10, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(0.01); + assertEquals(10.01, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(0.99); + assertEquals(11, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(419.5); + assertEquals(430.5, bankAccount.getBalance(), THRESHOLD); + + bankAccount.setFrozen(true); + //Checking that account frozen gets thrown with basic deposits + assertThrows(AccountFrozenException.class, () -> bankAccount.deposit(0)); + assertThrows(AccountFrozenException.class, () -> bankAccount.deposit(100)); + assertThrows(AccountFrozenException.class, () -> bankAccount.deposit(50.53)); + + //Checking that account frozen has higher priority than IllegalArgument + assertThrows(AccountFrozenException.class, () -> bankAccount.deposit(-2)); + assertThrows(AccountFrozenException.class, () -> bankAccount.deposit(100.1234)); + assertThrows(AccountFrozenException.class, () -> bankAccount.deposit(-25.087)); + + + + } + + @Test + void transferTest() throws InsufficientFundsException, AccountFrozenException { + Account a = new CheckingAccount(1000, "a@b.com"); + Account b = new CheckingAccount(0, "a@b.com"); + + //non-negative amount less than or equal to balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 0.001)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 0.9999)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 999.999)); + + //non-negative amount greater than balance with two decimal places or less + assertThrows(InsufficientFundsException.class, () -> a.transfer(b, 1000.01)); + assertThrows(InsufficientFundsException.class, () -> a.transfer(b, 2500.5)); + assertThrows(InsufficientFundsException.class, () -> a.transfer(b, 1357)); + + //non-negative amount greater than balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 1000.001)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 6666.6666)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, Double.MAX_VALUE)); + + //negative amount with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.01)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.99)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -607.2)); + + //negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.001)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.9999)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -9876.54321)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -Double.MAX_VALUE)); + + //non-negative amount less than or equal to balance with two decimal places or less + a.transfer(b, 0); + assertEquals(1000, a.getBalance(), THRESHOLD); + assertEquals(0, b.getBalance(), THRESHOLD); + a.transfer(b, 0.01); + assertEquals(999.99, a.getBalance(), THRESHOLD); + assertEquals(0.01, b.getBalance(), THRESHOLD); + a.transfer(b, 500); + assertEquals(499.99, a.getBalance(), THRESHOLD); + assertEquals(500.01, b.getBalance(), THRESHOLD); + a.transfer(b, 498.99); + assertEquals(1, a.getBalance(), THRESHOLD); + assertEquals(999, b.getBalance(), THRESHOLD); + a.transfer(b, 1); + assertEquals(0, a.getBalance(), THRESHOLD); + assertEquals(1000, b.getBalance(), THRESHOLD); + + //Setting a's balance back to 1000, and b's to 0 + b.transfer(a, 1000); + //checking with the sender frozen + a.setFrozen(true); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 5)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 10.45)); + //checking with both frozen + b.setFrozen(true); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 0)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 6.34)); + //checking with only the receiver frozen + a.setFrozen(false); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 20)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 50.85)); + //Checking that Account Frozen has higher priority than other errors, with receiver frozen + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 1000.01)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 50000)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, -30)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 0.12345)); + //Checking that Account Frozen has higher priority than other errors with both frozen + a.setFrozen(true); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 1000.01)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 50000)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, -30)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 0.12345)); + //Checking that Account Frozen has higher priority than other errors with sender frozen + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 1000.01)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 50000)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, -30)); + assertThrows(AccountFrozenException.class, () -> a.transfer(b, 0.12345)); + + + + } + + @Test + void constructorTest() { + Account bankAccount = new CheckingAccount( 200, "1"); + + assertEquals(200, bankAccount.getBalance()); + + //non-negative balance with two decimal places or less + bankAccount = new CheckingAccount( 0, "1"); + assertEquals(0, bankAccount.getBalance(), THRESHOLD); + bankAccount = new CheckingAccount( 0.01, "1"); + assertEquals(0.01, bankAccount.getBalance(), THRESHOLD); + bankAccount = new CheckingAccount( 0.99, "1"); + assertEquals(0.99, bankAccount.getBalance(), THRESHOLD); + bankAccount = new CheckingAccount( 9876.5, "1"); + assertEquals(9876.5, bankAccount.getBalance(), THRESHOLD); + bankAccount = new CheckingAccount(248, "1"); + assertEquals(248, bankAccount.getBalance(), THRESHOLD); + + //non-negative balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount(0.001, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount(0.9999, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( 369.333, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( Double.MAX_VALUE, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( Double.MIN_VALUE, "1")); + + //negative balance with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -0.01, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -0.99, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -10.2, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -125, "1")); + + //negative balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -0.001, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -0.9999, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -369.333, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -Double.MAX_VALUE, "1")); + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -Double.MIN_VALUE, "1")); + + //for now assuming any non-empty string is a valid id, may have to update these tests later + bankAccount = new CheckingAccount(50, "1"); + assertEquals("1", bankAccount.getID()); + bankAccount = new CheckingAccount(50, "abc"); + assertEquals("abc", bankAccount.getID()); + + //checking with emptyString, illegal argument for balance takes precedence + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( -0.001, ""));//Bad balance takes precedence + assertThrows(IllegalArgumentException.class, () -> new CheckingAccount( 50, "")); + + } + + @Test + void isAmountValidTest() { + //non-negative amount with two decimal points or less + assertTrue(Account.isAmountValid(0)); + assertTrue(Account.isAmountValid(0.01)); + assertTrue(Account.isAmountValid(0.99)); + assertTrue(Account.isAmountValid(250)); + assertTrue(Account.isAmountValid(1234.50)); + + //non-negative amount with more than two decimal points + assertFalse(Account.isAmountValid(0.001)); + assertFalse(Account.isAmountValid(0.9999)); + assertFalse(Account.isAmountValid(536.125)); + assertFalse(Account.isAmountValid(Double.MIN_VALUE)); + assertFalse(Account.isAmountValid(Double.MAX_VALUE)); + + //negative amount with two decimal points or less + assertFalse(Account.isAmountValid(-0.01)); + assertFalse(Account.isAmountValid(-0.99)); + assertFalse(Account.isAmountValid(-120)); + assertFalse(Account.isAmountValid(-946.5)); + + //negative amount with more than two decimal points + assertFalse(Account.isAmountValid(-0.001)); + assertFalse(Account.isAmountValid(-0.9999)); + assertFalse(Account.isAmountValid(-Double.MIN_VALUE)); + assertFalse(Account.isAmountValid(-Double.MAX_VALUE)); + } +} diff --git a/src/test/java/edu/ithaca/dragon/bank/AdminTest.java b/src/test/java/edu/ithaca/dragon/bank/AdminTest.java new file mode 100644 index 00000000..21ad94b5 --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/AdminTest.java @@ -0,0 +1,179 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class AdminTest { + + @Test + void constructorTest() { + Admin admin = new Admin(null); + assertEquals(null, admin.getBank()); + Map testCollection = new HashMap<>(); + testCollection.put("1234", new CheckingAccount(50, "1234")); + testCollection.put("123", new CheckingAccount(100,"123")); + CentralBank testBank = new CentralBank(); + testBank.setAccounts(testCollection); + admin = new Admin(testBank); + assertEquals(testBank, admin.getBank()); + + } + + @Test + void freezeAccountTest() { + Account abcAcc = new CheckingAccount(500, "abc"); + Account xyzAcc = new CheckingAccount(500, "xyz"); + Map collection = new HashMap<>(); + collection.put(abcAcc.getID(), abcAcc); + collection.put(xyzAcc.getID(), xyzAcc); + CentralBank testBank = new CentralBank(); + testBank.setAccounts(collection); + Admin admin = new Admin(testBank); + //Checking false frozen status after no change + assertEquals(false, abcAcc.getFrozenStatus()); + assertEquals(false, xyzAcc.getFrozenStatus()); + admin.freezeAccount("abc"); + //Checking for true after frozen, and that other account unaffected + assertEquals(true, abcAcc.getFrozenStatus()); + assertEquals(false, xyzAcc.getFrozenStatus()); + admin.freezeAccount("abc"); + //Checking still true if you attempt to freeze a frozen account + assertEquals(true, abcAcc.getFrozenStatus()); + //Checking freezing other account + admin.freezeAccount("xyz"); + assertEquals(true, xyzAcc.getFrozenStatus()); + //Checking with IDs not present in collection + assertThrows(IllegalArgumentException.class, () -> admin.freezeAccount("123")); + assertThrows(IllegalArgumentException.class, () -> admin.freezeAccount("")); + assertThrows(IllegalArgumentException.class, () -> admin.freezeAccount("abcd")); + + } + + @Test + void unFreezeAccountTest() { + Account abcAcc = new CheckingAccount(500, "abc"); + Account xyzAcc = new CheckingAccount(500, "xyz"); + Map collection = new HashMap<>(); + collection.put(abcAcc.getID(), abcAcc); + collection.put(xyzAcc.getID(), xyzAcc); + CentralBank testBank = new CentralBank(); + testBank.setAccounts(collection); + Admin admin = new Admin(testBank); + //Checking true frozen status after change + abcAcc.setFrozen(true); + xyzAcc.setFrozen(true); + assertEquals(true, abcAcc.getFrozenStatus()); + assertEquals(true, xyzAcc.getFrozenStatus()); + //Checking only one acc gets changed + admin.unfreezeAcct("abc"); + assertEquals(false, abcAcc.getFrozenStatus()); + assertEquals(true, xyzAcc.getFrozenStatus()); + //Checking can unfreeze other acc + admin.unfreezeAcct("xyz"); + assertEquals(false, xyzAcc.getFrozenStatus()); + //Checking that unfreezing an unfrozen account remains false + admin.unfreezeAcct("xyz"); + assertEquals(false, xyzAcc.getFrozenStatus()); + //Checking with IDs not present in collection + assertThrows(IllegalArgumentException.class, () -> admin.unfreezeAcct("123")); + assertThrows(IllegalArgumentException.class, () -> admin.unfreezeAcct("")); + assertThrows(IllegalArgumentException.class, () -> admin.unfreezeAcct("abcd")); + + } + + @Test + void calcTotalAssetsTest(){ + CentralBank testBank = new CentralBank(); + Admin admin = new Admin(testBank); + //Checking with no accounts + assertEquals(0, admin.calcTotalAssets()); + //Checking with one account + testBank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + assertEquals(100, admin.calcTotalAssets()); + //Checking with multiple accounts + testBank.getAccounts().put("xyz", new CheckingAccount(50.65, "xyz")); + testBank.getAccounts().put("def",new CheckingAccount(156, "def")); + assertEquals(306.65, admin.calcTotalAssets()); + //Check when there is an account with 0 assets + testBank.getAccounts().put("ghi", new CheckingAccount(0, "ghi")); + assertEquals(306.65, admin.calcTotalAssets()); + } + + + + @Test + void integrationTest() throws InsufficientFundsException, AccountFrozenException{ + //Going to test that teller and admin are working properly, use teller to create new accounts and admin to find the total balance + CentralBank bank = new CentralBank(); + Teller teller = new Teller(bank); + Admin admin = new Admin(bank); + assertEquals(0, admin.calcTotalAssets()); + teller.createAccount("abc", 150); + assertEquals(150, admin.calcTotalAssets()); + teller.createAccount("123", 20.45); + assertEquals(170.45, admin.calcTotalAssets()); + teller.createAccount("xyz", 0); + assertEquals(170.45, admin.calcTotalAssets()); + teller.createAccount("acc", 0.14); + assertEquals(170.59, admin.calcTotalAssets()); + assertThrows(IllegalArgumentException.class, ()->teller.createAccount("account", -50)); + assertThrows(IllegalArgumentException.class, ()->teller.createAccount("ghi", 100.505)); + + } + + @Test + void systemTest() throws InsufficientFundsException, AccountFrozenException{ + //Meant to test that freeze/unfreeze can work in conjunction, as well as calcTotalAssets working with the Account methods + CentralBank testBank = new CentralBank(); + Teller teller = new Teller(testBank); + teller.createAccount("abc", 500); + teller.createAccount("xyz", 500); + Admin admin = new Admin(testBank); + assertEquals(1000, admin.calcTotalAssets()); + teller.transfer("abc", "xyz", 200); + assertEquals(1000, admin.calcTotalAssets()); + teller.deposit("abc",300); + assertEquals(1300, admin.calcTotalAssets()); + teller.withdraw("xyz",100.55); + assertEquals(1199.45, admin.calcTotalAssets()); + + admin.freezeAccount("abc"); + assertThrows(AccountFrozenException.class, ()->teller.deposit("abc", 50)); + //Checking that a frozen account is still counted in banks assets + assertEquals(1199.45, admin.calcTotalAssets()); + assertThrows(AccountFrozenException.class, ()->teller.withdraw("abc", 50)); + assertThrows(AccountFrozenException.class, ()->teller.transfer("abc", "xyz",50)); + assertThrows(AccountFrozenException.class, ()->teller.transfer("xyz", "abc",50)); + teller.deposit("xyz", 0.13); + assertEquals(1199.58, admin.calcTotalAssets()); + + //Going to add a new account and make sure unfreeze account works as expected + + teller.createAccount("new", 300.42); + assertEquals(1500, admin.calcTotalAssets()); + assertThrows(AccountFrozenException.class, ()->teller.transfer("abc", "new",50)); + assertThrows(AccountFrozenException.class, ()->teller.transfer("new", "abc",50)); + admin.unfreezeAcct("abc"); + teller.transfer("abc", "new", 100); + assertEquals(1500, admin.calcTotalAssets()); + teller.deposit("abc", 150); + assertEquals(1650, admin.calcTotalAssets()); + teller.withdraw("abc", 200); + assertEquals(1450, admin.calcTotalAssets()); + + + } + + + + +} diff --git a/src/test/java/edu/ithaca/dragon/bank/BankAccountTest.java b/src/test/java/edu/ithaca/dragon/bank/BankAccountTest.java index df0150db..c95b85e6 100644 --- a/src/test/java/edu/ithaca/dragon/bank/BankAccountTest.java +++ b/src/test/java/edu/ithaca/dragon/bank/BankAccountTest.java @@ -6,26 +6,221 @@ class BankAccountTest { + private static final double THRESHOLD = 0.001; + @Test void getBalanceTest() { - BankAccount bankAccount = new BankAccount("a@b.com", 200); + //negative balance + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -200)); - assertEquals(200, bankAccount.getBalance()); + //non-negative balance + BankAccount bankAccount = new BankAccount("a@b.com", 0); + assertEquals(0, bankAccount.getBalance()); + + //non-negative balance + bankAccount = new BankAccount("a@b.com", 100); + assertEquals(100, bankAccount.getBalance()); } @Test - void withdrawTest() throws InsufficientFundsException{ - BankAccount bankAccount = new BankAccount("a@b.com", 200); + void withdrawTest() throws InsufficientFundsException { + BankAccount bankAccount = new BankAccount("a@b.com", 1000); + + //non-negative amount less than or equal to balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(3141.592)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(Double.MIN_VALUE)); + + //non-negative amount greater than balance with two decimal places or less + assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(1000.01)); + assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(5432)); + assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(3216.8)); + + //non-negative amount greater than balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(1000.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(9876.543)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(Double.MAX_VALUE)); + + //negative amount with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.01)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.99)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-2718.2)); + + //negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-14850.607)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.withdraw(-Double.MAX_VALUE)); + + //non-negative amount less than or equal to balance with two decimal places or less + bankAccount.withdraw(0); + assertEquals(1000, bankAccount.getBalance(), THRESHOLD); bankAccount.withdraw(100); + assertEquals(900, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(0.01); + assertEquals(899.99, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(898.99); + assertEquals(1, bankAccount.getBalance(), THRESHOLD); + bankAccount.withdraw(1); + assertEquals(0, bankAccount.getBalance(), THRESHOLD); + } - assertEquals(100, bankAccount.getBalance()); - assertThrows(InsufficientFundsException.class, () -> bankAccount.withdraw(300)); + @Test + void depositTest() { + BankAccount bankAccount = new BankAccount("a@b.com", 0); + + //non-negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(1010.101)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(Double.MAX_VALUE)); + + //negative amount with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.01)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.99)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-8008.2)); + + //negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.001)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-0.9999)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-5000.125)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> bankAccount.deposit(-Double.MAX_VALUE)); + + //non-negative amount with two decimal places or less + bankAccount.deposit(0); + assertEquals(0, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(10); + assertEquals(10, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(0.01); + assertEquals(10.01, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(0.99); + assertEquals(11, bankAccount.getBalance(), THRESHOLD); + bankAccount.deposit(419.5); + assertEquals(430.5, bankAccount.getBalance(), THRESHOLD); + } + + @Test + void transferTest() throws InsufficientFundsException { + BankAccount a = new BankAccount("a@b.com", 1000); + BankAccount b = new BankAccount("a@b.com", 0); + + //non-negative amount less than or equal to balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 0.001)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 0.9999)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 999.999)); + + //non-negative amount greater than balance with two decimal places or less + assertThrows(InsufficientFundsException.class, () -> a.transfer(b, 1000.01)); + assertThrows(InsufficientFundsException.class, () -> a.transfer(b, 2500.5)); + assertThrows(InsufficientFundsException.class, () -> a.transfer(b, 1357)); + + //non-negative amount greater than balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 1000.001)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, 6666.6666)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, Double.MAX_VALUE)); + + //negative amount with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.01)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.99)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -607.2)); + + //negative amount with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.001)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -0.9999)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -9876.54321)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -Double.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> a.transfer(b, -Double.MAX_VALUE)); + + //non-negative amount less than or equal to balance with two decimal places or less + a.transfer(b, 0); + assertEquals(1000, a.getBalance(), THRESHOLD); + assertEquals(0, b.getBalance(), THRESHOLD); + a.transfer(b, 0.01); + assertEquals(999.99, a.getBalance(), THRESHOLD); + assertEquals(0.01, b.getBalance(), THRESHOLD); + a.transfer(b, 500); + assertEquals(499.99, a.getBalance(), THRESHOLD); + assertEquals(500.01, b.getBalance(), THRESHOLD); + a.transfer(b, 498.99); + assertEquals(1, a.getBalance(), THRESHOLD); + assertEquals(999, b.getBalance(), THRESHOLD); + a.transfer(b, 1); + assertEquals(0, a.getBalance(), THRESHOLD); + assertEquals(1000, b.getBalance(), THRESHOLD); + } + + @Test + void isEmailValidTest() { + //valid prefix and domain + assertTrue(BankAccount.isEmailValid("a@b.com")); + //missing prefix and/or domain + assertFalse(BankAccount.isEmailValid("")); + + //prefix with underscore, period, or dash not followed by one or more letter or number + assertFalse(BankAccount.isEmailValid("abc-@mail.com")); + //prefix with underscore, period, or dash followed by one or more letter or number + assertTrue(BankAccount.isEmailValid("abc-d@mail.com")); + //prefix with underscore, period, or dash not followed by one or more letter or number + assertFalse(BankAccount.isEmailValid("abc..def@mail.com")); + //prefix with underscore, period, or dash followed by one or more letter or number + assertTrue(BankAccount.isEmailValid("abc.def@mail.com")); + //prefix with underscore, period, or dash not preceded by one or more letter or number + assertFalse(BankAccount.isEmailValid(".abc@mail.com")); + //valid prefix and domain + assertTrue(BankAccount.isEmailValid("abc@mail.com")); + //prefix with invalid character + assertFalse(BankAccount.isEmailValid("abc#def@mail.com")); + //prefix with underscore, period, or dash followed by one or more letter or number + assertTrue(BankAccount.isEmailValid("abc_def@mail.com")); + //last portion of the domain without at least two characters + assertFalse(BankAccount.isEmailValid("abc.def@mail.c")); + //last portion of the domain with at least two characters + assertTrue(BankAccount.isEmailValid("abc.def@mail.cc")); + //domain with invalid character + assertFalse(BankAccount.isEmailValid("abc.def@mail#archive.com")); + //domain with period or dash followed by one or more letter or number + assertTrue(BankAccount.isEmailValid("abc.def@mail-archive.com")); + //last portion of the domain without at least two characters + assertFalse(BankAccount.isEmailValid("abc.def@mail")); + //last portion of the domain with at least two characters + assertTrue(BankAccount.isEmailValid("abc.def@mail.org")); + //domain with period or dash not followed by one or more letter or number + assertFalse(BankAccount.isEmailValid("abc.def@mail..com")); + //prefix with underscore, period, or dash followed by one or more letter or number + assertTrue(BankAccount.isEmailValid("abc.def@mail.com")); } @Test - void isEmailValidTest(){ - assertTrue(BankAccount.isEmailValid( "a@b.com")); - assertFalse( BankAccount.isEmailValid("")); + void isAmountValidTest() { + //non-negative amount with two decimal points or less + assertTrue(BankAccount.isAmountValid(0)); + assertTrue(BankAccount.isAmountValid(0.01)); + assertTrue(BankAccount.isAmountValid(0.99)); + assertTrue(BankAccount.isAmountValid(250)); + assertTrue(BankAccount.isAmountValid(1234.50)); + + //non-negative amount with more than two decimal points + assertFalse(BankAccount.isAmountValid(0.001)); + assertFalse(BankAccount.isAmountValid(0.9999)); + assertFalse(BankAccount.isAmountValid(536.125)); + assertFalse(BankAccount.isAmountValid(Double.MIN_VALUE)); + assertFalse(BankAccount.isAmountValid(Double.MAX_VALUE)); + + //negative amount with two decimal points or less + assertFalse(BankAccount.isAmountValid(-0.01)); + assertFalse(BankAccount.isAmountValid(-0.99)); + assertFalse(BankAccount.isAmountValid(-120)); + assertFalse(BankAccount.isAmountValid(-946.5)); + + //negative amount with more than two decimal points + assertFalse(BankAccount.isAmountValid(-0.001)); + assertFalse(BankAccount.isAmountValid(-0.9999)); + assertFalse(BankAccount.isAmountValid(-Double.MIN_VALUE)); + assertFalse(BankAccount.isAmountValid(-Double.MAX_VALUE)); } @Test @@ -35,7 +230,38 @@ void constructorTest() { assertEquals("a@b.com", bankAccount.getEmail()); assertEquals(200, bankAccount.getBalance()); //check for exception thrown correctly - assertThrows(IllegalArgumentException.class, ()-> new BankAccount("", 100)); - } + assertThrows(IllegalArgumentException.class, () -> new BankAccount("", 100)); + + //non-negative balance with two decimal places or less + bankAccount = new BankAccount("a@b.com", 0); + assertEquals(0, bankAccount.getBalance(), THRESHOLD); + bankAccount = new BankAccount("a@b.com", 0.01); + assertEquals(0.01, bankAccount.getBalance(), THRESHOLD); + bankAccount = new BankAccount("a@b.com", 0.99); + assertEquals(0.99, bankAccount.getBalance(), THRESHOLD); + bankAccount = new BankAccount("a@b.com", 9876.5); + assertEquals(9876.5, bankAccount.getBalance(), THRESHOLD); + bankAccount = new BankAccount("a@b.com", 248); + assertEquals(248, bankAccount.getBalance(), THRESHOLD); + + //non-negative balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", 0.001)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", 0.9999)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", 369.333)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", Double.MAX_VALUE)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", Double.MIN_VALUE)); + //negative balance with two decimal places or less + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -0.01)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -0.99)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -10.2)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -125)); + + //negative balance with more than two decimal places + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -0.001)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -0.9999)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -369.333)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -Double.MAX_VALUE)); + assertThrows(IllegalArgumentException.class, () -> new BankAccount("a@b.com", -Double.MIN_VALUE)); + } } \ No newline at end of file diff --git a/src/test/java/edu/ithaca/dragon/bank/CentralBankTest.java b/src/test/java/edu/ithaca/dragon/bank/CentralBankTest.java new file mode 100644 index 00000000..2e9cb45d --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/CentralBankTest.java @@ -0,0 +1,67 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class CentralBankTest { + + @Test + void constructorTest() { + CentralBank bank = new CentralBank(); + + assertEquals(0, bank.getAccounts().size()); + } + + + @Test + void withdrawTest() throws InsufficientFundsException, AccountFrozenException{ + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + + bank.withdraw("abc", 50); + assertEquals(50, bank.checkBalance("abc")); + assertThrows(InsufficientFundsException.class, () -> bank.withdraw("abc", 100)); + assertThrows(IllegalArgumentException.class, () -> bank.withdraw( "help", 100)); + bank.getAccounts().get("abc").setFrozen(true); + assertThrows(AccountFrozenException.class, () -> bank.withdraw( "abc", 100)); + + } + + @Test + void depositTest() throws AccountFrozenException{ + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + + + bank.deposit("abc", 100); + assertEquals(200, bank.checkBalance("abc")); + assertThrows(IllegalArgumentException.class, () -> bank.deposit( "help", 100)); + bank.getAccounts().get("abc").setFrozen(true); + assertThrows(AccountFrozenException.class, () -> bank.deposit( "abc", 100)); + + } + + @Test + void transferTest() throws InsufficientFundsException, AccountFrozenException{ + CentralBank bank = new CentralBank(); + bank.getAccounts().put("abc", new CheckingAccount(100, "abc")); + bank.getAccounts().put("def", new CheckingAccount(100, "def")); + + bank.transfer("abc", "def", 50); + assertEquals(50, bank.checkBalance("abc")); + assertEquals(150, bank.checkBalance("def")); + + bank.getAccounts().get("abc").setFrozen(true); + assertThrows(AccountFrozenException.class, () -> bank.transfer( "abc", "def", 100)); + bank.getAccounts().get("abc").setFrozen(false); + bank.getAccounts().get("def").setFrozen(true); + assertThrows(AccountFrozenException.class, () -> bank.transfer( "abc", "def", 100)); + bank.getAccounts().get("def").setFrozen(false); + + + assertThrows(InsufficientFundsException.class, () -> bank.transfer("abc", "def", 200)); + assertThrows(IllegalArgumentException.class, () -> bank.transfer("abc", "help", 100)); + } + +} diff --git a/src/test/java/edu/ithaca/dragon/bank/SavingsAccountTest.java b/src/test/java/edu/ithaca/dragon/bank/SavingsAccountTest.java new file mode 100644 index 00000000..eda81d86 --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/SavingsAccountTest.java @@ -0,0 +1,31 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + + +public class SavingsAccountTest { + + + @Test + void withdrawTest() throws InsufficientFundsException, AccountFrozenException{ + Account a = new SavingsAccount(30, 0.5, 20, "a@b.com"); + + a.withdraw(10); + assertEquals(20, a.getBalance()); + + assertThrows(IllegalArgumentException.class, () -> a.withdraw(50)); + a.withdraw(10); + assertThrows(InsufficientFundsException.class, () -> a.withdraw(15)); + + } + + @Test + void calcInterestTest() { + SavingsAccount a = new SavingsAccount(100, 0.5, 20, "a@b.com"); + + a.calculateInterest(); + assertEquals(150, a.getBalance()); + } + +} diff --git a/src/test/java/edu/ithaca/dragon/bank/TellerTest.java b/src/test/java/edu/ithaca/dragon/bank/TellerTest.java new file mode 100644 index 00000000..5e93a9b3 --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/TellerTest.java @@ -0,0 +1,50 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; + +import static org.junit.jupiter.api.Assertions.*; + +public class TellerTest { + + @Test + void createAccountTest() { + CentralBank centralBank = new CentralBank(); + Teller teller = new Teller(centralBank); + + teller.createAccount("0", 0); + + assertNotNull(teller.centralBank.getAccounts().get("0")); + + teller.createAccount("1", 10); + teller.createAccount("2", 20); + teller.createAccount("3", 150); + + assertNotNull(teller.centralBank.getAccounts().get("2")); + } + + @Test + void closeAccountTest() { + CentralBank centralBank = new CentralBank(); + Teller teller = new Teller(centralBank); + + assertThrows(NoSuchElementException.class, () -> teller.closeAccount("0")); + + teller.createAccount("0", 0); + + assertThrows(NoSuchElementException.class, () -> teller.closeAccount("1")); + + teller.createAccount("1", 123); + teller.createAccount("2", 967); + + teller.closeAccount("0"); + assertNull(teller.centralBank.getAccounts().get("0")); + + teller.closeAccount("1"); + assertNull(teller.centralBank.getAccounts().get("1")); + + teller.closeAccount("2"); + assertNull(teller.centralBank.getAccounts().get("2")); + } +} diff --git a/src/test/java/edu/ithaca/dragon/bank/UserTest.java b/src/test/java/edu/ithaca/dragon/bank/UserTest.java new file mode 100644 index 00000000..06506469 --- /dev/null +++ b/src/test/java/edu/ithaca/dragon/bank/UserTest.java @@ -0,0 +1,69 @@ +package edu.ithaca.dragon.bank; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + + +public class UserTest { + + @Test + void constructorTest() { + User u = new User(); + } + + @Test + void addAccountTest() { + Account a = new CheckingAccount(100, "a@b.com"); + User u = new User(); + + u.addAccount(a); + assertEquals(u.getAccount("a@b.com"), a); + } + + @Test + void removeAccountTest() { + Account a = new CheckingAccount(100, "a@b.com"); + User u = new User(); + + assertThrows(IllegalArgumentException.class, () -> u.getAccount("")); + + u.addAccount(a); + u.removeAccount("a@b.com"); + assertThrows(IllegalArgumentException.class, () -> u.getAccount("a@b.com")); + } + + @Test + void getAccountTest() { + Account a = new CheckingAccount(100, "a@b.com"); + User u = new User(); + + u.addAccount(a); + assertEquals(u.getAccount("a@b.com"), a); + + assertThrows(IllegalArgumentException.class, () -> u.getAccount("")); + } + + + //Tests adding account, getting account, and calling account methods by id + @Test + void IntegrationTest() throws InsufficientFundsException, AccountFrozenException{ + String idA = "a@c.com"; + String idB = "b@c.com"; + Account a = new CheckingAccount(100, idA); + Account b = new CheckingAccount(200, idB); + User u = new User(); + + u.addAccount(a); + u.addAccount(b); + + u.getAccount(idA).withdraw(50); + assertEquals(50, u.getAccount(idA).getBalance()); + u.getAccount(idA).deposit(20); + assertEquals(70, u.getAccount(idA).getBalance()); + u.getAccount(idB).transfer(u.getAccount(idA), 100); + assertEquals(170, u.getAccount(idA).getBalance()); + assertEquals(100, u.getAccount(idB).getBalance()); + + } + +}