diff --git a/Untitled Diagram.xml b/Untitled Diagram.xml new file mode 100644 index 0000000..36aa9f4 --- /dev/null +++ b/Untitled Diagram.xml @@ -0,0 +1 @@ +3Vvbkps4EP0aP84UQuDLYzKX7MtWpWq2ajePDMiGGoxYIY/tfP1KIDCoZUe2uaR2XmJaQqCjo+7TajLDT9vDNxbk8Z80IunMdaLDDD/PXBd52BP/SMuxsnirVWXYsCRSnU6Gt+QnUUZHWXdJRIpOR05pypO8awxplpGQd2wBY3Tf7bamafepebAhwPAWBim0/p1EPFZWNF+dGv4gySZWj16686rhPQg/NozuMvW8mYvX5V/VvA3qsdREiziI6L5lwi8z/MQo5dWv7eGJpBLbGrbqvtczrc17M5Jxmxvc6obPIN2pqf8VMxJEwqbGKvixRqXYJ9s0yMTV132ccPKWB6Fs2gsSwAer+z8J4+TQMqkX+UbolnB2FF1Ua43JsXu5Py2Au1S2uIW9v1DGQC36phn5NHHxQ83djIMPcACzFzcI+snJi0XLpbHgAeNvPODSuE7S9ImmlJW9sVP+yc6c0Q/SalmvVQuEzL0WMuR0MfMgZtgAGe4BsbkFYpHYVOqSpO90/3IyfC0NoiGmLPlJMx6IB32VM0/ENvySJptMNL5TzulW9s6iL3JfCxvNSVZZlN9YmlB+fVUoi36viZzFMxJX5dYkcgrOWfgLumMh6fBCLPSGqF6LyiQnd88SmbBXg3yniXil0wjI74yAkDZE9XbqLm0FmxeyWtQFWNQkEqulL2wPzJ075jnt2+7WtNt7oO4SzHJXECYHDXlCsxGma3Jug013ZbFTwfYaakMt4IZaWm4oRtKAJ5/dEH0PMDXgLWRyWvBSV2y3gYjhwzMB1y5mDCYgBCY8IRWWkAr1xCfgAlRCPcSzi9DBgHYHmDVyt0SqNvUcA/UaozXqZwKZ7gVXGqerCYFABgYC0UMf6ExEFIgHx1a3XHYozr8w1t7X74hp8aMa8NZoiwHlGvENyTew+MaaTBlVfSOIBNx8w8tvfC1oGg1HVN/IG8JdTSu/scGrYUOM8C3d2qG7Khqx7d2W35Xflr7mBn+AYBZqKb+vZq6Wa48qvxFMHcOYhB8zeVAjZfhMJpcYSfpkZH+SY8UISIyqzBHMt+AuHkaPmTabIdmt12oCQQaztEaVO//uyG6MfTGuOp8uUTOxYW5gw2SpmgszF8UBh2xzfgRAsZhu33cFVAbyMDYcXBkgX3crkEgmOXXpdMgaK5jKHAn0ndfLg0DJgpSs+UBq4ZDwfyRFH3119aMk7CUyyzaBUHXbwq+vf5yGkZffCUsEkoRZb4Cm8NDaAO6V2uNBjdFz4oR0d9NTvtPkUfVzlv0mPIaMJ6PDE5PTfEINa+JRnQKMzSNtfbHjW/HolqW2SVAmDWY1fBMEM4tqU53kpkmZ8lfA1LXI+cXwxajIieU5Nn5enYfnilimHYMgd/EIo5lviGbI7wGs/2GhyeQlTOL7ymijL5Seqf7aQegnXkjXI/05iPpJrXWNkiIPeBi38r9G8jeWPWUfZbGGq7Oy/pMA5E2YBWCodEOWlGRtoVAQc6mqdhsZ5eaTQnFrReY697wPKad7NuKtDNmz6Ui5F6Sgzr0UYjLa8qSXN7ADJGYUFHF5YfjCwhRvDLUNPFm8wRax2MiUs1BpOZWy388n1+vyCa8MgQayyeshzng2tbGr48wpNYF5yUDFIQMda1/boaNnScexqkP6YfpScxG2xSE9WcL6QL0lS5rvc/pNluCmbapD9RKPVh3yl11MR60OYZg15oyGpChMQuGXcsC7dvJa0uQ5Y6oBmw/TJipLdw5e3BsPXjzomawPWcbyTA+aKvb0D7BsXdMD0usuejWqJ9/0gLTnKB71Vrm2KVy0aGmjvW6PeAYO1T7j9+WQu3rUVIsti3R/BEfqMUuDVRi40KAyL1PmG+vy97trPQv2HRishirL4+lKOAqnjuwzVM/xdCUcmPCPhQ2C2Ji+lxqtvCUuT5/4V7vy9P8o8Mt/ \ No newline at end of file diff --git a/atm_uml.xml b/atm_uml.xml new file mode 100644 index 0000000..9caa683 --- /dev/null +++ b/atm_uml.xml @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9901415..b450953 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,14 @@ io.zipcoder project-2-atm 1.0-SNAPSHOT + + + + junit + junit + 4.12 + + \ No newline at end of file diff --git a/src/main/java/io/zipcoder/macrolabs/atm/Account.java b/src/main/java/io/zipcoder/macrolabs/atm/Account.java new file mode 100644 index 0000000..20e0169 --- /dev/null +++ b/src/main/java/io/zipcoder/macrolabs/atm/Account.java @@ -0,0 +1,75 @@ +package io.zipcoder.macrolabs.atm; + +import java.util.ArrayList; + +public class Account { + private String accountName=""; + private final int ownedByUserID; + private final int accountNumber; + private static int nextAccountNumber; + protected double balance=0; + private ArrayList transactionHistory=new ArrayList<>(); + + static{ + nextAccountNumber=1; + } + + //Object initialization block + { + accountNumber=nextAccountNumber; + nextAccountNumber++; + } + + + + public Account(int passedOwnerUserID) + { + ownedByUserID=passedOwnerUserID; + } + + public Account(int passedOwnerUserID, String passedAccountName){ + accountName=passedAccountName; + ownedByUserID=passedOwnerUserID; + } + + protected String transactionBuilder(String descriptionOfChange, double amount){ + String lineItem=""; + lineItem+=descriptionOfChange + amount; + return lineItem; + } + + public void changeBalance(double amount){ + balance+=amount; + changeTransactionHistory(transactionBuilder("Account, overload changeBalance ", amount) ); + + } + + public double getBalance(){ + return (balance); + } + + public ArrayList getTransactionHistory() { + return transactionHistory; + } + + protected void changeTransactionHistory(String lineItem){ + transactionHistory.add(lineItem); + } + + public String getAccountName(){ + return accountName; + } + + public int getAccountNumber() { + return accountNumber; + } + + public void setAccountName(String passedAccountName) { + accountName = passedAccountName; + } + + public int getOwnerID(){ + return ownedByUserID; + } + +} diff --git a/src/main/java/io/zipcoder/macrolabs/atm/AccountFactory.java b/src/main/java/io/zipcoder/macrolabs/atm/AccountFactory.java new file mode 100644 index 0000000..77e9413 --- /dev/null +++ b/src/main/java/io/zipcoder/macrolabs/atm/AccountFactory.java @@ -0,0 +1,39 @@ +package io.zipcoder.macrolabs.atm; + +public class AccountFactory { + + private AccountFactory(){} + + public static InvestmentAccount createInvestment(int passedUserID){ + return (createInvestment(passedUserID, "Investment Account")); + } + + public static InvestmentAccount createInvestment(int passedUserID, + String passedAccountName){ + return (createInvestment(passedUserID, passedAccountName, 7.95)); + + } + + public static InvestmentAccount createInvestment(int passedUserID, + String passedAccountName, + double passedCommissionRate){ + return (new InvestmentAccount(passedUserID, passedAccountName, passedCommissionRate)); + } + + public static SavingAccount createSaving(int passedUserID){ + return (createSaving(passedUserID, "Saving Account")); + } + + public static SavingAccount createSaving(int passedUserID, + String passedAccountName){ + return (createSaving(passedUserID, passedAccountName, 0.01)); + + } + + public static SavingAccount createSaving(int passedUserID, + String passedAccountName, + double passedInterestRate){ + return (new SavingAccount(passedUserID, passedAccountName, passedInterestRate)); + } + +} diff --git a/src/main/java/io/zipcoder/macrolabs/atm/InvestmentAccount.java b/src/main/java/io/zipcoder/macrolabs/atm/InvestmentAccount.java new file mode 100644 index 0000000..09ebf47 --- /dev/null +++ b/src/main/java/io/zipcoder/macrolabs/atm/InvestmentAccount.java @@ -0,0 +1,180 @@ +package io.zipcoder.macrolabs.atm; + +import java.util.ArrayList; + +public class InvestmentAccount extends Account{ + + private double securitiesTotalValue; + private ArrayList ownedSecurities=new ArrayList<>(); + private double commissionRate=7.95; + private double accountTotalValue; + + public InvestmentAccount(int passedOwnerUserID) { + super(passedOwnerUserID, "Investment Account"); + } + + public InvestmentAccount(int passedOwnerUserID, String passedAccountName){ + super(passedOwnerUserID, passedAccountName); + } + + public InvestmentAccount(int passedOwnerUserID, String passedAccountName, + double passedCommissionRate){ + super(passedOwnerUserID, passedAccountName); + commissionRate=passedCommissionRate; + } + + public void changeBalance(String descriptionOfChange, double amount) { + balance+=amount; + this.setAccountTotalValue(this.getBalance()+this.getSecuritiesTotalValue()); + changeTransactionHistory(transactionBuilder(descriptionOfChange, amount)); + + } + + public ArrayList getSecurityList(){ + return (ownedSecurities); + } + + public boolean tradeSecurity (String passedName, double sharesToTrade){ + boolean tradeSuccess=false; + if (sharesToTrade>0) + { + tradeSuccess=buySecurity(passedName, sharesToTrade); + } + else if (sharesToTrade<0) + { + tradeSuccess=sellSecurity(passedName, sharesToTrade); + } + accountTotalValue=getBalance()+calculateSecuritiesTotalValue(); + return tradeSuccess; + } + + private boolean sellSecurity(String passedName, double sharesToTrade){ + if (isSecurityAvailableToSell(passedName, sharesToTrade)) + { + for (int i=0; ithis.getBalance() ) { + return false; + } + return true; + } + + private double calculateSecuritiesTotalValue(){ + double calculateSecuritiesValue=0.0; + for (Security s : ownedSecurities) + { + calculateSecuritiesValue += (s.getValue() * s.getNumberOwned()); + } + setSecuritiesTotalValue(calculateSecuritiesValue); + setAccountTotalValue(getBalance()+calculateSecuritiesValue); + return calculateSecuritiesValue; + } + + public double getCommissionRate(){ + return commissionRate; + } + + public void setCommissionRate(double passedCommissionRate){ + commissionRate=passedCommissionRate; + } + + private void setSecuritiesTotalValue(double passedTotal){ + securitiesTotalValue=passedTotal; + } + + private void setAccountTotalValue(double passedTotal){ + accountTotalValue=passedTotal; + } + + public double getAccountTotalValue(){ + return accountTotalValue; + } + + public double getSecuritiesTotalValue(){ + return securitiesTotalValue; + } + + +} diff --git a/src/main/java/Main.java b/src/main/java/io/zipcoder/macrolabs/atm/Main.java similarity index 77% rename from src/main/java/Main.java rename to src/main/java/io/zipcoder/macrolabs/atm/Main.java index 05e41a9..d9187a8 100644 --- a/src/main/java/Main.java +++ b/src/main/java/io/zipcoder/macrolabs/atm/Main.java @@ -1,6 +1,9 @@ /** * Created by iyasuwatts on 10/17/17. */ +package io.zipcoder.macrolabs.atm; + + public class Main { public static void main(String[] args){ diff --git a/src/main/java/io/zipcoder/macrolabs/atm/SavingAccount.java b/src/main/java/io/zipcoder/macrolabs/atm/SavingAccount.java new file mode 100644 index 0000000..e3239cd --- /dev/null +++ b/src/main/java/io/zipcoder/macrolabs/atm/SavingAccount.java @@ -0,0 +1,24 @@ +package io.zipcoder.macrolabs.atm; + +public class SavingAccount extends Account{ + + private double interestRate; + + public SavingAccount(int passedOwnerUserID) { + this(passedOwnerUserID, "Saving Account"); + } + + public SavingAccount(int passedOwnerUserID, String passedAccountName){ + this(passedOwnerUserID, passedAccountName, 0.01); + } + + public SavingAccount(int passedOwnerUserID, String passedAccountName, + double passedInterestRate){ + super(passedOwnerUserID, passedAccountName); + interestRate=passedInterestRate; + } + + public double getInterestRate(){ + return interestRate; + } +} diff --git a/src/main/java/io/zipcoder/macrolabs/atm/Security.java b/src/main/java/io/zipcoder/macrolabs/atm/Security.java new file mode 100644 index 0000000..08702e6 --- /dev/null +++ b/src/main/java/io/zipcoder/macrolabs/atm/Security.java @@ -0,0 +1,40 @@ +package io.zipcoder.macrolabs.atm; + +import java.util.Random; + +public class Security +{ + private final String name; + private double numberOwned=0; + private double value=0; + + public Security(String passedName, double passedNumberOwned, double passedValue){ + name=passedName; + numberOwned=passedNumberOwned; + value=passedValue; + } + + public Security(String passedName, double passedNumberOwned){ + Random randomizer = new Random(); + name = passedName; + numberOwned = passedNumberOwned; + value = Math.abs( (randomizer.nextDouble()*randomizer.nextInt(50)) ); + } + + public String getName(){ + return name; + } + + public double getNumberOwned(){ + return numberOwned; + } + + public void changeNumberOwned(double numberDifference){ + numberOwned+=numberDifference; + } + + public double getValue(){ + return value; + } + +} diff --git a/src/main/java/io/zipcoder/macrolabs/atm/SecurityFactory.java b/src/main/java/io/zipcoder/macrolabs/atm/SecurityFactory.java new file mode 100644 index 0000000..c95549b --- /dev/null +++ b/src/main/java/io/zipcoder/macrolabs/atm/SecurityFactory.java @@ -0,0 +1,30 @@ +package io.zipcoder.macrolabs.atm; + +import java.util.Random; + +public class SecurityFactory { + private SecurityFactory(){} //cannot instantiate. Must use class via static methods + + public static Security createRandomSecurity(){ + Random randomizer = new Random(); + String name =""; + for (int i=0; i<3; i++) + { + name = name + (char) (randomizer.nextInt(26) + 65); + } + + double numberOwned = Math.abs( (randomizer.nextDouble()*randomizer.nextInt(100)) ); + double value = Math.abs( (randomizer.nextDouble()*randomizer.nextInt(50)) ); + + return (new Security(name, numberOwned, value)); + } + + public static Security createSecurity(String passedName){ + return (new Security(passedName, 0)); + } + + public static Security createSecurity(String passedName, double passedSharesOwned){ + return (new Security(passedName, passedSharesOwned)); + } + +} diff --git a/src/test/java/io/zipcoder/macrolabs/atm/mainTest.java b/src/test/java/io/zipcoder/macrolabs/atm/mainTest.java new file mode 100644 index 0000000..6007118 --- /dev/null +++ b/src/test/java/io/zipcoder/macrolabs/atm/mainTest.java @@ -0,0 +1,398 @@ +package io.zipcoder.macrolabs.atm; /** + * Created by Timothy Rager on 10/24/17. + */ + +import org.junit.Assert; +import org.junit.Test; +import java.util.ArrayList; + +public class mainTest { + + public final double allowedDeltaShares = 0.0001; //Securities to three decimal places-->Accuracy, not formatting + public final double allowedDeltaDollars = 0.001; //Dollars to two decimal places -->Accuracy, not formatting + +//SECURITY CLASS TESTS + @Test + public void testSecurityGetName(){ + String expected="XKCD"; + Security security = new Security(expected, 10.02, 25.12); + String actual = security.getName(); + + Assert.assertEquals("The strings do not match", expected, actual); + } + @Test + public void testSecurityGetNumberOwned(){ + double expected=10.030; + Security security = new Security("XKCD", expected, 25.12); + double actual = security.getNumberOwned(); + + Assert.assertEquals(expected, actual, allowedDeltaShares);//Seeking reasonable precision within + // three decimal places + } + + @Test + public void testSecurityChangeNumberOwned_PassNegative(){ + double expected=20.026; + double changedBy=-0.004; + Security security=new Security("XKCD", 20.03,10); + security.changeNumberOwned(changedBy); + double actual=security.getNumberOwned(); + Assert.assertEquals(expected, actual, allowedDeltaShares); + } + + @Test + public void testSecurityChangeNumberOwned_PassPositive(){ + double expected=20.034; + double changedBy=0.004; + Security security=new Security("XKCD", 20.03,10); + security.changeNumberOwned(changedBy); + double actual=security.getNumberOwned(); + Assert.assertEquals(expected, actual, allowedDeltaShares); + } + + @Test + public void testSecurityGetValue(){ + double expected=25.12; + Security security = new Security("XKCD", 200, 25.12); + double actual = security.getValue(); + + Assert.assertEquals(expected, actual, allowedDeltaDollars); + } + +//SECURITYFACTORY TESTS + + @Test + public void testSecurityFactoryCreateRandomSecurity(){ + Security security=SecurityFactory.createRandomSecurity(); + //We'll check the fields of security and if they are not of the correct type / format + // then set to false (ie, name should be three characters long, value and numberOwned + //should be positive + + Assert.assertTrue(security.getValue()>=0); + Assert.assertTrue(security.getNumberOwned()>=0); + Assert.assertTrue(security.getName().length()==3); + + } + + @Test + public void testSecurityFactoryCreateSecurity_PassedString(){ + Security security=SecurityFactory.createSecurity("XKCD"); + + Assert.assertTrue(security.getValue()>=0); + Assert.assertTrue(security.getNumberOwned()>=0); + Assert.assertTrue(security.getName().length()==4); + } + + @Test + public void testSecurityFactoryCreateSecurity_PassedStringAndSharesOwned(){ + Security security=SecurityFactory.createSecurity("XKCD", 25); + + Assert.assertTrue(security.getValue()>=0); + Assert.assertTrue(security.getNumberOwned()>=0); + Assert.assertTrue(security.getName().length()==4); + } + +//ACCOUNT TESTS + @Test + public void testAccountGetAccountNumber() + { + Account account=new Account(1); + Account secondAccount=new Account(1); + int expected=secondAccount.getAccountNumber(); + + for (int i=1; i<=10; i++) + { + account=new Account(i); + expected++; + } + for (int i=1; i<=10; i++) + { + secondAccount=new Account(i); + expected++; + } + int actual = secondAccount.getAccountNumber(); + + Assert.assertEquals("Account numbers don't match", expected, actual); + } + @Test + public void testAccountConstructors(){ + Account[] twoAccounts = {new Account(1), + new Account(2,"Checksorg")}; + Assert.assertTrue(twoAccounts[0].getAccountName().isEmpty()); + Assert.assertTrue(!(twoAccounts[1].getAccountName().isEmpty())); + } + + @Test + public void testAccountChangeBalanceAndGetBalance(){ + //double expected=10.5; + double expected=-10.5; + Account account = new Account(1); + account.changeBalance(expected); + double actual=account.getBalance(); + + Assert.assertEquals(expected, actual, allowedDeltaDollars); + } + + @Test + public void testAccountChangeTransactionHistoryAndGetTransactionHistory() { + Account account=new Account(1); + ArrayList expected=new ArrayList<>(); + + expected.add("Account, overload changeBalance 1.1"); + expected.add("Account, overload changeBalance -2.2");//expected contains {1.1, -2.2} + + account.changeBalance(1.1); + account.changeBalance(-2.2); + + ArrayList actual = account.getTransactionHistory(); + + boolean sameElementsInAL = false; + + if (actual.get(0).equals(expected.get(0)) && actual.get(1).equals(expected.get(1))) + sameElementsInAL = true; + Assert.assertTrue("The elements in the ALs were not the same", sameElementsInAL); + } + + @Test + public void testAccountSetAccountNameAndGetAccountName(){ + Account account = new Account (1,"For College"); + String expected = "For Boat"; + //account.setAccountName("For Beer"); + account.setAccountName(expected); + String actual = account.getAccountName(); + + Assert.assertEquals("the strings do not match", expected, actual); + } + + @Test + public void testAccountGetOwnerID(){ + Account account = new Account(1); + //int expected = 2; + int expected = 1; + int actual = account.getOwnerID(); + + Assert.assertTrue("The ownerIDs do not match",expected==actual); + } + +//INVESTMENTACCOUNT TESTS + @Test + public void testInvestmentAccountConstructorPassedIdOnly(){ + InvestmentAccount ia = new InvestmentAccount(1); + String expected = "Investment Account"; + String actual = ia.getAccountName(); + Assert.assertEquals("Constructor sans nickname default not working", expected, actual); + } + + @Test + public void testInvestmentAccountConstructorAndGetCommissionRate(){ + InvestmentAccount ia = new InvestmentAccount(1, + "Retirement", + 6.95); + double expected = 6.95; + double actual = ia.getCommissionRate(); + Assert.assertEquals(expected, actual, allowedDeltaDollars); + } + + @Test + public void testInvestmentAccountSetCommissionRate(){ + InvestmentAccount ia = new InvestmentAccount(1, + "Retirement", + 6.95); + double expected = 9.95; + ia.setCommissionRate(expected); + double actual = ia.getCommissionRate(); + Assert.assertEquals(expected, actual, allowedDeltaDollars); + } + + @Test + public void testInvestmentAccountGetSecurityList(){ + InvestmentAccount ia = new InvestmentAccount(1, "Retirement"); + Assert.assertTrue("Null", ia.getSecurityList()!=null); + } + + //tradeSecurity(String,double) + //This public method implicitly runs several private methods. + // If passed positive shares, we buy. If negative, we sell. If 0, return false + //Tests buySecurity -> generateSecurityToBuy ->isCashAvailableToBuy -> calculateSecuritiesTotalValue + // returns true if everything worked as intended, false otherwise. + //Tests sellSecurity -> isSecurityAvailableToSell -> calculateSecuritiesTotalValue + // returns true if everything worked as intended, false otherwise. + // + //Note that as a consequence of calling calculateSecuritiesTotalValue() we also + //call the setters for securitiesTotalValue and totalAccountValue. + + + @Test + public void testInvestmentAccountTradeSecurityPassed_0(){ + InvestmentAccount ia = new InvestmentAccount(1,"R"); + boolean expected=false; + boolean actual=ia.tradeSecurity("XKCD",0); + + Assert.assertTrue("Shouldn't be able to trade on 0 shares", expected==actual); + } + + @Test + public void testInvestmentAccountTradeSecurityPassed_PositiveCreatesSecurity(){ + InvestmentAccount ia = new InvestmentAccount(1,"R"); + ia.changeBalance(10000000);//Seed the account with cash + boolean expected=true; + boolean actual=ia.tradeSecurity("XKCD",1); + + Assert.assertTrue("Failed to transact", expected==actual); + } + + @Test + public void testInvestmentAccountTradeSecurityPassed_PositiveSecurityPreexisting(){ + InvestmentAccount ia = new InvestmentAccount(1,"R"); + ia.changeBalance(10000000);//Seed the account with cash + boolean expected=true; + boolean actual=ia.tradeSecurity("XKCD",1); + + actual=ia.tradeSecurity("XKCD", 10);//Buy more of the existing + + Assert.assertTrue("Failed to transact", expected==actual); + } + + @Test + public void testInvestmentAccountChangeBalanceWithTransactionBuilder(){ + InvestmentAccount ia = new InvestmentAccount(1,"R"); + ia.changeBalance("Testing change balance with transactionBuilder : ", 10000000);//Seed the account with cash + String expected = "Testing change balance with transactionBuilder : 1.0E7"; + String actual = ia.getTransactionHistory().get(0); + + Assert.assertEquals("Strings don't match", expected, actual); + } + + @Test + public void testInvestmentAccountTradeSecurityPassed_Negative(){ + //Must create a security in order to sell it, so we repeat the + //code from "."_Positive(), above + InvestmentAccount ia = new InvestmentAccount(1,"R"); + ia.changeBalance(10_000_000);//Seed the account with cash + boolean expected=true; + boolean actual=ia.tradeSecurity("XKCD",1);//Placeholder to generate security to sell + //We can reasonably expect that if, after running the sell, the value of the + //account's cash position is 10_000_000 - commission*2 then things ran smoothly. + //Another possibility for testing these methods? + //System.out.println("$10,000,000 - "+ia.getCommissionRate()*2+" = "+ + // (10_000_000-(ia.getCommissionRate()*2))); + actual=ia.tradeSecurity("XKCD",-1); + + Assert.assertTrue("Failed to transact", expected==actual); + } + + @Test + public void testInvestmentAccountTradeSecurityPassedPositive_NotEnoughCash(){ + InvestmentAccount ia = new InvestmentAccount(1,"R"); + //ia.changeBalance(10000000);//Seed the account with cash + boolean expected=false; + boolean actual=ia.tradeSecurity("XKCD",1); + + Assert.assertTrue("Failed to transact", expected==actual); + } + + @Test + public void testInvestmentAccountTradeSecurityPassedNegative_NotEnoughShares(){ + //Must create a security in order to sell it, so we repeat the + //code from "."_Positive(), above + InvestmentAccount ia = new InvestmentAccount(1,"R"); + ia.changeBalance(10_000_000);//Seed the account with cash + boolean expected=false; + boolean actual=ia.tradeSecurity("XKCD",1);//Placeholder to generate security to sell + //We can reasonably expect that if, after running the sell, the value of the + //account's cash position is 10_000_000 - commission*2 then things ran smoothly. + //Another possibility for testing these methods? + //System.out.println("$10,000,000 - "+ia.getCommissionRate()*2+" = "+ + // (10_000_000-(ia.getCommissionRate()*2))); + actual=ia.tradeSecurity("XKCD",-2); + + Assert.assertTrue("Failed to transact", expected==actual); + } + + @Test + public void testInvestmentAccountGetAccountTotalValue(){ + + double expected; + double actual; + double passCash=1000; + double sharesToTrade=10; + InvestmentAccount ia = new InvestmentAccount(1,"R"); + ia.changeBalance(passCash);//Seed the account with cash + if (ia.tradeSecurity("XKCD", sharesToTrade)) + { + actual=ia.getAccountTotalValue(); + expected=(passCash) - ia.getCommissionRate(); + } + else + { + actual=ia.getAccountTotalValue(); + expected=passCash; + } + + Assert.assertEquals(expected, actual, allowedDeltaDollars); + } + +//ACCOUNTFACTORY TESTS + + @Test + public void testAccountFactoryCreateInvestment(){ + InvestmentAccount ia = new InvestmentAccount(0);//Use minimal constructor to populate default + // fields for comparison + InvestmentAccount iaUserId= AccountFactory.createInvestment(1); + InvestmentAccount iaUserIdAndAccountName= AccountFactory.createInvestment(2, + "Retirement"); + InvestmentAccount iaUserIdAccountNameAndCommissionRate= AccountFactory.createInvestment(3, + "Brokerage", + 6.95); + Assert.assertTrue("User ID failed", + iaUserId.getOwnerID()==1 && + ia.getAccountName().equals(iaUserId.getAccountName()) && + iaUserId.getCommissionRate()==ia.getCommissionRate()); + Assert.assertTrue("User ID & AccountName failed", + iaUserIdAndAccountName.getOwnerID()==2 && + "Retirement".equals(iaUserIdAndAccountName.getAccountName()) && + iaUserIdAndAccountName.getCommissionRate()==ia.getCommissionRate()); + Assert.assertTrue("User ID & AccountName & CommissionRate failed", + iaUserIdAccountNameAndCommissionRate.getOwnerID()==3 && + "Brokerage".equals(iaUserIdAccountNameAndCommissionRate.getAccountName()) && + iaUserIdAccountNameAndCommissionRate.getCommissionRate()==6.95); + } + + @Test + public void testAccountFactoryCreateSaving(){ + SavingAccount sa = new SavingAccount(0);//Use minimal constructor to populate default + // fields for comparison + SavingAccount saUserId= AccountFactory.createSaving(1); + SavingAccount saUserIdAndAccountName= AccountFactory.createSaving(2, + "For Boat"); + SavingAccount saUserIdAccountNameAndInterestRate= AccountFactory.createSaving(3, + "For Beer", + 0.05); + Assert.assertTrue("User ID failed", + saUserId.getOwnerID()==1 && + sa.getAccountName().equals(saUserId.getAccountName()) && + saUserId.getInterestRate()==sa.getInterestRate()); + Assert.assertTrue("User ID & AccountName failed", + saUserIdAndAccountName.getOwnerID()==2 && + "For Boat".equals(saUserIdAndAccountName.getAccountName()) && + saUserIdAndAccountName.getInterestRate()==sa.getInterestRate()); + Assert.assertTrue("User ID & AccountName & InterestRate failed", + saUserIdAccountNameAndInterestRate.getOwnerID()==3 && + "For Beer".equals(saUserIdAccountNameAndInterestRate.getAccountName()) && + saUserIdAccountNameAndInterestRate.getInterestRate()==0.05); + } + +//SAVINGACCOUNT TESTS + + @Test + public void testSavingAccountConstructors(){ + SavingAccount sa = new SavingAccount(0);//Load defaults for comparisons + + Assert.assertTrue(sa.getOwnerID()==0 && + "Saving Account".equals(sa.getAccountName()) && + sa.getInterestRate()==0.01); + } + +//CHECKINGACCOUNT TESTS + +}