From 28baf1fb5aef785f8206e3e1735b5ed09a2cbc47 Mon Sep 17 00:00:00 2001
From: Andreas Kluge Svendsrud <andreksv@stud.ntnu.no>
Date: Thu, 20 Apr 2023 10:57:18 +0200
Subject: [PATCH] Savings and SavingsGoal classes with tests, implemented into
 GeneralBudget

---
 .../demo/data/Budget/GeneralBudget.java       |  52 ++++-
 .../idatt1002/demo/data/Budget/Savings.java   | 187 ++++++++++++++++++
 .../demo/data/Budget/SavingsGoal.java         | 129 ++++++++++++
 .../demo/data/Budget/GeneralBudgetTest.java   |   6 +
 .../demo/data/Budget/SavingsGoalTest.java     |  80 ++++++++
 .../demo/data/Budget/SavingsTest.java         |  50 +++++
 6 files changed, 503 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/no/ntnu/idatt1002/demo/data/Budget/Savings.java
 create mode 100644 src/main/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoal.java
 create mode 100644 src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoalTest.java
 create mode 100644 src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsTest.java

diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java
index 04fb19f7..94d2a707 100644
--- a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java
+++ b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java
@@ -30,6 +30,22 @@ public class GeneralBudget {
      */
     private final double maxAmount;
 
+    /**
+     * The savings of budget.
+     */
+    private final Savings savings;
+
+
+    public GeneralBudget(List<BudgetItem> budgetItems, double maxAmount, Savings savings) {
+        if (maxAmount < 0) {
+            throw new IllegalArgumentException("The max amount of the budget cant be less than zero");
+        } else {
+            this.maxAmount = maxAmount;
+            this.budgetItems = budgetItems;
+            this.savings = savings;
+        }
+    }
+
     /**
      * Class constructor.
      *
@@ -43,6 +59,7 @@ public class GeneralBudget {
         } else {
             this.maxAmount = maxAmount;
             this.budgetItems = budgetItems;
+            this.savings = new Savings();
         }
     }
 
@@ -58,6 +75,7 @@ public class GeneralBudget {
         } else {
             this.maxAmount = maxAmount;
             this.budgetItems = new ArrayList<>();
+            this.savings = new Savings();
         }
     }
 
@@ -90,6 +108,15 @@ public class GeneralBudget {
         return budgetItems;
     }
 
+    /**
+     * Method for getting Savings
+     *
+     * @return savings of Budget.
+     */
+    public Savings getSavings() {
+        return savings;
+    }
+
     /**
      * Method for getting a Specific BudgetItem
      * from budgetItems
@@ -146,7 +173,7 @@ public class GeneralBudget {
      *  @param category A category from ExpenseCategory
      */
     public void addToBudget(double budgetAmount, String description, ExpenseCategory category) {
-        if ((totalSum() + budgetAmount) > maxAmount) {
+        if ((totalSumAndSavings() + budgetAmount) > maxAmount) {
             throw new IllegalArgumentException("Amount to be added goes over the max value of the budget");
         }
         if (!hasBudgetCategory(category)) {
@@ -212,6 +239,29 @@ public class GeneralBudget {
         budgetItems.removeIf(item -> item.getBudgetCategory() == category);
     }
 
+    /**
+     * Method returns totalSum of budgetItems and totalSum of savings.
+     *
+     * @return totalSum of budgetItems and totalSum of savings.
+     */
+    public double totalSumAndSavings() {
+        return totalSum() + savings.getTotalSavings();
+    }
+
+    /**
+     * Assign an amount to savings.
+     * The amount plus other assigned amounts cannot be more than the maxAmount.
+     *
+     * @param amount the amount you want to assign to savings.
+     * @throws IllegalArgumentException if amount plus totalSumAndSavings is more than maxAmount
+     */
+    public void addToSavings(double amount) {
+        if((totalSumAndSavings() + amount) > maxAmount) {
+            throw new IllegalArgumentException("Amount to be added goes over the max value of the budget");
+        }
+        savings.addToSavings(amount);
+    }
+
     @Override
     public String toString() {
         StringBuilder budgetItemsString = new StringBuilder();
diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/Savings.java b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/Savings.java
new file mode 100644
index 00000000..2bd4d476
--- /dev/null
+++ b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/Savings.java
@@ -0,0 +1,187 @@
+package no.ntnu.idatt1002.demo.data.Budget;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Savings is a class that has an amount
+ * that is given to it, which can further can be
+ * given to different savingsGoals.
+ */
+public class Savings {
+    /**
+     * List of SavingsGoals
+     */
+    private final List<SavingsGoal> savingsGoals;
+    /**
+     * An amount not used on any SavingsGoal.
+     */
+    private double amount;
+
+    /**
+     * Class constructor that sets
+     * savingsGoals to an empty ArrayList and
+     * amount to zero.
+     */
+    public Savings() {
+        this.savingsGoals = new ArrayList<>();
+        this.amount = 0;
+    }
+
+    /**
+     * Class constructor that sets
+     * savingsGoals to an empty ArrayList and
+     * amount to a given double.
+     *
+     * @param amount the double you want to assign amount
+     */
+    public Savings(double amount) {
+        this.savingsGoals = new ArrayList<>();
+        this.amount = amount;
+    }
+
+    /**
+     * Class constructor that sets
+     * savingsGoals to a given ArrayList and
+     * amount to zero.
+     *
+     * @param savingsGoals the ArrayList you want to assign savingsGoals
+     */
+    public Savings(ArrayList<SavingsGoal> savingsGoals) {
+        this.savingsGoals = savingsGoals;
+        this.amount = 0;
+    }
+
+    /**
+     * Class constructor that sets
+     * savingsGoals to a given ArrayList and
+     * amount to a given double.
+     *
+     * @param savingsGoals the ArrayList you want to assign savingsGoals
+     * @param amount
+     */
+    public Savings(ArrayList<SavingsGoal> savingsGoals, double amount) {
+        this.savingsGoals = savingsGoals;
+        this.amount = amount;
+    }
+
+    /**
+     * Get List of SavingsGoals.
+     *
+     * @return List of SavingsGoals
+     */
+    public List<SavingsGoal> getSavingsGoals() {
+        return savingsGoals;
+    }
+
+    /**
+     * Get the amount.
+     *
+     * @return savings amount
+     */
+    public double getAmount() {
+        return amount;
+    }
+
+    /**
+     * Get the total amount invested into SavingsGoals
+     * and the amount that is unused.
+     *
+     * @return amount invested into SavingsGoals and amount not used.
+     */
+    public double getTotalSavings() {
+        double totalSavings = 0;
+        for(SavingsGoal savingsGoal : savingsGoals) {
+            totalSavings += savingsGoal.getAmountInvested();
+        }
+        totalSavings += getAmount();
+        return totalSavings;
+    }
+
+    /**
+     * Get a specific SavingsGoal from
+     * savingsGoals
+     *
+     * @param savingsGoal the SavingsGoal you want to get
+     * @throws IllegalArgumentException if the SavingsGoal is not in the List
+     * @return the SavingsGoal you wanted to find if it exists
+     */
+    public SavingsGoal getSavingsGoal(SavingsGoal savingsGoal) {
+        for(SavingsGoal aSavingsGoal : savingsGoals) {
+                if(savingsGoal == aSavingsGoal) {
+                    return aSavingsGoal;
+                }
+            }
+        throw new IllegalArgumentException("The SavingsGoal is not in the List");
+    }
+
+    /**
+     * Method to check if savingsGoals
+     * contains a specific SavingsGoal
+     *
+     * @param savingsGoal the SavingsGoal you want to check.
+     * @return boolean depending on if savingsGoals contains the savingsGoal.
+     */
+    public boolean hasSavingsGoal(SavingsGoal savingsGoal) {
+        return savingsGoals.contains(savingsGoal);
+    }
+
+    /**
+     * A List of all SavingsGoal that are achieved.
+     * A SavingsGoal is achieved if its amount is zero.
+     *
+     * @return List of achieved SavingsGoal
+     */
+    public List<SavingsGoal> getAchievedSavingsGoal() {
+        List<SavingsGoal> achievedSavingsGoals = new ArrayList<>();
+        for(SavingsGoal aSavingsGoal : savingsGoals) {
+            if(aSavingsGoal.isAchieved()) {
+                achievedSavingsGoals.add(aSavingsGoal);
+            }
+        }
+        return achievedSavingsGoals;
+    }
+
+    /**
+     * Method for adding an amount to a
+     * SavingsGoal.
+     *
+     * @param amount the amount you want to add
+     * @param savingsGoal the SavingsGoal you want to add to
+     * @throws IllegalArgumentException if the amount is higher than the Savings amount.
+     * @throws IllegalArgumentException if SavingsGoal is not in savingsGoal.
+     */
+    public void addToSavingsGoal(int amount, SavingsGoal savingsGoal) {
+        if(amount > this.amount) {
+            throw new IllegalArgumentException("The amount cannot be higher than the Savings amount");
+        }
+        if(!hasSavingsGoal(savingsGoal)) {
+            throw new IllegalArgumentException("The SavingsGoal is not in savingsGoals");
+        }
+        getSavingsGoal(savingsGoal).addAmountInvested(amount);
+        this.amount -= amount;
+    }
+
+    /**
+     * Add an amount to Savings
+     *
+     * @param amount the amount you want to add.
+     */
+    public void addToSavings(double amount) {
+        this.amount += amount;
+    }
+
+    /**
+     * Add a SavingsGoal to Savings.
+     *
+     * @param savingsGoal the SavingsGoal you want to add.
+     * @throws IllegalArgumentException if the SavingsGoal already exists in the Savings.
+     */
+    public void addSavingsGoal(SavingsGoal savingsGoal) {
+        if(savingsGoals.contains(savingsGoal)) {
+            throw new IllegalArgumentException("SavingsGoal already in Savings");
+        } else {
+            savingsGoals.add(savingsGoal);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoal.java b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoal.java
new file mode 100644
index 00000000..ce7fd18e
--- /dev/null
+++ b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoal.java
@@ -0,0 +1,129 @@
+package no.ntnu.idatt1002.demo.data.Budget;
+
+/**
+ * SavingsGoal is a specific goal that you are
+ * saving towards, for example a car or holiday.
+ */
+public class SavingsGoal {
+    /**
+     * A description of what the SavingsGoal is for.
+     */
+    private String description;
+    /**
+     * The monetary amount invested into the SavingsGoal
+     */
+    private double amountInvested;
+
+    /**
+     * The monetary amount needed to achieve the SavingsGoal
+     */
+    private double amountGoal;
+
+    /**
+     * Boolean to check if the SavingsGoal has been achieved.
+     * SavingsGoal has been achieved when amount is zero.
+     */
+    private boolean achieved = false;
+
+    /**
+     * The class constructor for a SavingsGoal.
+     *
+     * @param description a String the explains what the SavingsGoal is for.
+     * @param amountInvested the monetary amount invested into the SavingsGoal.
+     * @param amountGoal the monetary amount needed to achieve the SavingsGoal.
+     */
+    public SavingsGoal(String description, double amountInvested, double amountGoal) throws IllegalArgumentException{
+        this.description = description;
+        if(amountGoal < 0) {
+            amountGoal = 0;
+        }
+        if(amountInvested < 0) {
+            amountInvested = 0;
+        }
+        this.amountGoal = amountGoal;
+        this.amountInvested = amountInvested;
+        achieved = amountInvested >= amountGoal;
+
+    }
+
+    /**
+     * The class constructor for a SavingsGoal,
+     * amountInvested is set to zero.
+     *
+     * @param description a String the explains what the SavingsGoal is for.
+     * @param amountGoal the monetary amount needed to achieve the SavingsGoal.
+     */
+    public SavingsGoal(String description, double amountGoal) {
+        this.description = description;
+        if(amountGoal < 0) {
+            amountGoal = 0;
+        }
+        this.amountGoal = amountGoal;
+        this.amountInvested = 0;
+    }
+    /**
+     * Getting the description of the SavingsGoal
+     * @return the SavingsGoal´s description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Getting the amount needed to achieve the SavingsGoal
+     * @return the SavingsGoal´s needed amount.
+     */
+    public double getAmountGoal() {
+        return amountGoal;
+    }
+
+    /**
+     * Getting the amount invested into the SavingsGoal.
+     * @return the SavingsGoal´s amount invested.
+     */
+    public double getAmountInvested() {
+        return amountInvested;
+    }
+
+    /**
+     * Check if the SavingsGoal is achieved.
+     *
+     * @return boolean
+     */
+    public boolean isAchieved() {
+        return achieved;
+    }
+    /**
+     * Setting the description of the SavingsGoal.
+     *
+     * @param description the new description you want to use.
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * Setting the amountGoal of the SavingsGoal.
+     *
+     * @param amount the new amount you want to use.
+     */
+    public void setAmountGoal(double amount) throws IllegalArgumentException{
+        if(amount < 0) {
+            this.amountGoal = 0;
+        } else {
+            this.amountGoal = amount;
+        }
+        achieved = amountInvested >= amountGoal;
+
+    }
+
+    /**
+     * Adding an amount to the amountInvested of the SavingsGoal.
+     *
+     * @param amount the amount you want to add.
+     */
+    public void addAmountInvested(double amount) throws IllegalArgumentException{
+        this.amountInvested += amount;
+        achieved = amountInvested >= amountGoal;
+    }
+}
diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java
index 55ea6e9f..22467b8e 100644
--- a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java
+++ b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java
@@ -122,6 +122,12 @@ class GeneralBudgetTest {
 
     }
 
+    @Test
+    void addToSavingsThrowsExceptionWhenItShould() {
+        GeneralBudget generalBudget = new GeneralBudget(1000);
+        assertThrows(IllegalArgumentException.class, () -> generalBudget.addToSavings(1500));
+    }
+
 
    /* @Test
     @DisplayName("Gets the number of days left in the month. 17 has to be changed to the actual number of days left in the month.")
diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoalTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoalTest.java
new file mode 100644
index 00000000..1429a517
--- /dev/null
+++ b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsGoalTest.java
@@ -0,0 +1,80 @@
+package no.ntnu.idatt1002.demo.data.Budget;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.time.Month;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class SavingsGoalTest {
+
+    @Test
+    void constructorSetsAmountToZeroIfAmountInvestedIsNegative() {
+        SavingsGoal savingsGoal = new SavingsGoal("",-50,0);
+        assertEquals(0, savingsGoal.getAmountInvested());
+    }
+
+    @Test
+    void constructorSetsAmountToZeroIfAmountGoalIsNegative() {
+        SavingsGoal savingsGoal = new SavingsGoal("",0,-50);
+        assertEquals(0, savingsGoal.getAmountGoal());
+    }
+
+    @Test
+    void setAmountGoalWillSetToZeroIfItGetsANegativeValue() {
+        SavingsGoal savingsGoal = new SavingsGoal("",50);
+        savingsGoal.setAmountGoal(-50);
+        assertEquals(0, savingsGoal.getAmountGoal());
+    }
+
+    @Nested
+    class testIfSavingsGoalIsAchievedWhenItsSupposedTo{
+        SavingsGoal savingsGoalNotAchieved;
+        SavingsGoal savingsGoalAchieved;
+        @BeforeEach
+        void createSavingsGoals() {
+            savingsGoalNotAchieved = new SavingsGoal("", 50, 100);
+            savingsGoalAchieved = new SavingsGoal("", 100, 50);
+        }
+
+
+        @Test
+        void savingsGoalIsAchievedWhenItsSupposedTo() {
+            assertTrue(savingsGoalAchieved.isAchieved());
+        }
+
+        @Test
+        void savingsGoalIsNotAchievedWhenItsSupposedTo() {
+            assertFalse(savingsGoalNotAchieved.isAchieved());
+        }
+
+        @Test
+        void addAmountInvestedSoItsHigherThanAmountGoalWillMakeItAchieved() {
+            savingsGoalNotAchieved.addAmountInvested(100);
+            assertTrue(savingsGoalNotAchieved.isAchieved());
+        }
+
+        @Test
+        void setAmountGoalLowerThanAmountInvestedWillMakeItAchieved() {
+            savingsGoalNotAchieved.setAmountGoal(25);
+            assertTrue(savingsGoalNotAchieved.isAchieved());
+        }
+
+        @Test
+        void addAmountInvestedSoItsLowerThanAmountGoalWillMakeItNotAchieved() {
+            savingsGoalAchieved.addAmountInvested(-75);
+            assertFalse(savingsGoalAchieved.isAchieved());
+        }
+
+        @Test
+        void setAmountGoalHigherThanAmountInvestedWillMakeItNotAchieved() {
+            savingsGoalAchieved.setAmountGoal(150);
+            assertFalse(savingsGoalAchieved.isAchieved());
+        }
+
+    }
+}
diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsTest.java
new file mode 100644
index 00000000..76b03cfb
--- /dev/null
+++ b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/SavingsTest.java
@@ -0,0 +1,50 @@
+package no.ntnu.idatt1002.demo.data.Budget;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+public class SavingsTest {
+    SavingsGoal savingsGoal1;
+    SavingsGoal savingsGoal2;
+    SavingsGoal savingsGoal3;
+    Savings savings;
+    @BeforeEach
+    void addSavingsGoalToSavings() {
+        savingsGoal1 = new SavingsGoal("", 50, 20);
+        savingsGoal2 = new SavingsGoal("", 75, 50);
+        savingsGoal3 = new SavingsGoal("", 20, 100);
+
+        savings = new Savings(100);
+        savings.addSavingsGoal(savingsGoal1);
+        savings.addSavingsGoal(savingsGoal2);
+        savings.addSavingsGoal(savingsGoal3);
+    }
+    @Test
+    void getTotalSavingsGivesExpectedAmount() {
+        assertEquals(245, savings.getTotalSavings());
+    }
+
+    @Test
+    void getAchievedSavingsGoalGivesExpected() {
+        List<SavingsGoal> savingsGoalsAchieved = new ArrayList<>();
+        savingsGoalsAchieved.add(savingsGoal1);
+        savingsGoalsAchieved.add(savingsGoal2);
+
+        assertEquals(savingsGoalsAchieved, savings.getAchievedSavingsGoal());
+    }
+
+    @Test
+    void addToSavingsGoalThrowsExceptionWhenTryingToAddMoreThanIsAvailable() {
+        assertThrows(IllegalArgumentException.class, () -> savings.addToSavingsGoal(1000, savingsGoal1));
+    }
+
+    @Test
+    void addToSavingsGoalThrowsExceptionWhenTryingToAddToASavingGoalThatIsNotAddedToSavings() {
+        assertThrows(IllegalArgumentException.class, () -> savings.addToSavingsGoal(0, new SavingsGoal("not exist",50)));
+    }
+}
+
-- 
GitLab