Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bug-Fixes to the Saving and Loading of RecurringExpensesFile #203

52 changes: 49 additions & 3 deletions src/main/java/seedu/budgetbuddy/Storage.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.Currency;
import java.time.LocalDate;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -30,6 +31,9 @@ public class Storage {

private final String filePath;

private ArrayList<String> expenseCategories = new ArrayList<>(Arrays.asList("Housing"
, "Groceries", "Utility", "Transport", "Entertainment", "Others"));

public Storage(String filePath) {
this.filePath = filePath;
ensureDirectoryExists();
Expand All @@ -47,6 +51,39 @@ private void ensureDirectoryExists() {
}
}

private void checkValidAmount(Double amount) throws BudgetBuddyException{
if (amount <= 0) {
throw new BudgetBuddyException("Invalid Amount detected. Possible Corrupted File");
}
}

private void checkValidCategory(String category) throws BudgetBuddyException {
if (!expenseCategories.contains(category)) {
throw new BudgetBuddyException("Invalid Category detected. Possible Corrupted File");
}
}

private void checkValidDescription(String description) throws BudgetBuddyException {
if (description.contains("|") || description.contains("!") || description.isEmpty()) {
throw new BudgetBuddyException("Invalid description detected. Possible Corrupted File");
}
}

private void checkValidTitle(String line) throws BudgetBuddyException {
int indexOfEndExclamation = line.indexOf("!!!", 4);
int endIndexOfEndExclamation = indexOfEndExclamation + "!!!".length();

if (endIndexOfEndExclamation != line.length() || line.contains("|")) {
throw new BudgetBuddyException("Invalid ListName title detected. Possible Corrupted File");
}
}

private void checkValidListName(String listName) throws BudgetBuddyException {
if (listName.contains("!") || listName.contains("|") || listName.isEmpty()) {
throw new BudgetBuddyException("Invalid listName detected. Possible Corrupted File");
}
}

/**
* Loads a list of expenses from a file.
* If an exception occurs during the loading process (e.g., if the file is corrupted),
Expand Down Expand Up @@ -214,15 +251,17 @@ public void parseRecurringExpensesFile(ArrayList<ExpenseList> recurringExpenses,
throws BudgetBuddyException{

if (line.startsWith("!!!")) {
checkValidTitle(line);
int indexOfStartExclamation = line.indexOf("!!!", 0);
int indexOfStartOfListName = indexOfStartExclamation + 3;

int indexOfEndExclamation = line.indexOf("!!!", 4);
int indexOfEndOfListName = indexOfEndExclamation;

String name = line.substring(indexOfStartOfListName, indexOfEndOfListName).trim();
ExpenseList expenses = new RecurringExpenseList(name, new ArrayList<>());
checkValidListName(name);

ExpenseList expenses = new RecurringExpenseList(name, new ArrayList<>());
recurringExpenses.add(expenses);
} else {
String[] parts = line.split("\\|");
Expand All @@ -234,9 +273,16 @@ public void parseRecurringExpensesFile(ArrayList<ExpenseList> recurringExpenses,

int listNumber = Integer.parseInt(parts[0].trim());
LocalDate dateAdded = LocalDate.parse(parts[1].trim());

String category = parts[2].trim();
checkValidCategory(category);

double amount = Double.parseDouble(parts[3].trim());
checkValidAmount(amount);

String description = parts[4].trim();
checkValidDescription(description);

Expense expense = new Expense(dateAdded, category, amount, description);

int listNumberAsArrayIndex = listNumber - 1;
Expand Down Expand Up @@ -266,7 +312,7 @@ public RecurringExpenseLists loadRecurringExpensesList() throws IOException{
return recurringExpenseLists;
} catch (Exception e) {
LOGGER.log(Level.INFO, "Exception successfully caught. Error has been handled");
System.out.println(e.getMessage());
System.out.println("Error Detected : " + e.getMessage());
System.out.println("You Recurring Expenses File is corrupted, resetting the file....");
resetRecurringExpensesListFile();
return new RecurringExpenseLists();
Expand Down
18 changes: 17 additions & 1 deletion src/main/java/seedu/budgetbuddy/command/FindExpensesCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Represents a command that finds and lists expenses based on a provided criteria.
* Criteria can include description, minimum and maximum amounts
*/
public class FindExpensesCommand extends Command {
private static final Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
private ExpenseList expenses;
Expand All @@ -16,6 +20,15 @@ public class FindExpensesCommand extends Command {
private Double maxAmount;
private Ui ui;

/**
* Constructs a FindExpenseCommand with the specified expense list, description, minimum amount and maximum amount
*
*
* @param expenses The expenseList to filter the expenses
* @param description The description to be filtered, can be null or empty
* @param minAmount The minimum amount of expense to be filtered, can be null
* @param maxAmount The maximum amount of expense to be filtered, can be null
*/
public FindExpensesCommand(ExpenseList expenses, String description, Double minAmount, Double maxAmount) {
if (minAmount != null && maxAmount != null) {
assert minAmount < maxAmount : "Minimum amount cannot be larger than Maximum Amount";
Expand All @@ -33,7 +46,10 @@ public FindExpensesCommand(ExpenseList expenses, String description, Double minA
this.maxAmount = maxAmount;
}


/**
* Prints an initialization message that informs user of the parameters used when filtering. Diplays
* an N.A. for filters which would not be used
*/
private void printInitializationMessage() {
ui.printDivider();
System.out.println("Looking for Expenses with the following parameters : ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ public FindExpensesCommandCreator(String input, ExpenseList expenses) {
this.expenses = expenses;
}


/**
* Checks the order of parameters in the provided input.
*
* @param input The user input
* @throws BudgetBuddyException If the parameters are not in the order of d/, morethan/ , lessthan/.
*/
private void checkForOutOfOrderParameters(String input) throws BudgetBuddyException {
int indexOfDescriptionPrefix = input.indexOf(DESCRIPTION_PREFIX);
int indexOfMinAmountPrefix = input.indexOf(MINAMOUNT_PREFIX);
Expand All @@ -40,12 +47,25 @@ private void checkForOutOfOrderParameters(String input) throws BudgetBuddyExcept

}

private static void checkForInvalidParameters(String input) {
/**
* Checks for the absence of the required parameters `d/`, `morethan/` and `lessthan/`
*
* @param input The user input
* @throws IllegalArgumentException If any of the three required parameters are missing
*/
private static void checkForInvalidParameters(String input) throws IllegalArgumentException {
if (!input.contains("d/") || !input.contains("morethan/") || !input.contains("lessthan/")) {
throw new IllegalArgumentException("Please Ensure that you include d/, morethan/ and lessthan/");
}
}

/**
* Parses and returns the maximum amount from the `lessthan/` prefix in the input string
*
* @param input The user input
* @return The extracted maximum amount, or null if amount is not specified
* @throws NumberFormatException If the maximum amount obtained is not a valid double
*/
private Double parseMaxAmount(String input) throws NumberFormatException{
int indexOfMaxAmountPrefix = input.indexOf(MAXAMOUNT_PREFIX);
int startIndexOfMaxAmount = indexOfMaxAmountPrefix + MAXAMOUNT_PREFIX.length();
Expand All @@ -63,7 +83,14 @@ private Double parseMaxAmount(String input) throws NumberFormatException{
return maxAmount;
}

private Double parseMinAmount(String input) {
/**
* Parses and returns the minimum amount from the `morethan/` prefix in the input string
*
* @param input The user input
* @return The extracted minimum amount, or null if amount is not specified
* @throws NumberFormatException If the minimum amount obtained is not a valid double
*/
private Double parseMinAmount(String input) throws NumberFormatException {
int indexOfMinAmountPrefix = input.indexOf(MINAMOUNT_PREFIX);
int startIndexOfMinAmount = indexOfMinAmountPrefix + MINAMOUNT_PREFIX.length();

Expand All @@ -80,6 +107,13 @@ private Double parseMinAmount(String input) {

return minAmount;
}

/**
* Parses and returns the description from the `d/` prefix in the input string
*
* @param input The user input
* @return The obtained description, or null if the description is empty
*/
private String parseDescription(String input) {

int indexOfDescriptionPrefix = input.indexOf(DESCRIPTION_PREFIX);
Expand All @@ -97,7 +131,14 @@ private String parseDescription(String input) {
return description;
}

private static void checkForDuplicateParameters(String input, String parameter) {
/**
* Checks for duplicate occurrences of a prefix in the input string
*
* @param input The user input
* @param parameter The parameter to check for duplicates
* @throws IllegalArgumentException If the parameter appears more than once
*/
private static void checkForDuplicateParameters(String input, String parameter) throws IllegalArgumentException{

int count = 0;

Expand All @@ -114,6 +155,14 @@ private static void checkForDuplicateParameters(String input, String parameter)

}

/**
* Compares the minimum and maximum amounts and throws an exception if the minimum amount
* is larger than the maximum amount
*
* @param minAmount The minimum amount
* @param maxAmount The maximum amount
* @throws BudgetBuddyException If the minimum amount > maximum amount
*/
private static void compareMinAndMaxAmount(Double minAmount, Double maxAmount) throws BudgetBuddyException{

if (minAmount != null && maxAmount != null) {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/seedu/budgetbuddy/commons/CurrencyConverter.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package seedu.budgetbuddy.commons;

import seedu.budgetbuddy.Ui;

import java.util.Currency;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -9,6 +11,8 @@ public class CurrencyConverter {

private static final Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
private Map<Currency, Double> exchangeRates;
private Ui ui = new Ui();

public CurrencyConverter() {
this.exchangeRates = new HashMap<>();
// Initialize exchange rates with default values
Expand All @@ -22,6 +26,7 @@ public CurrencyConverter() {
exchangeRates.put(Currency.getInstance("HKD"), 5.80);
}


/**
* Converts an amount from one currency to another using exchange rates.
*
Expand Down Expand Up @@ -184,13 +189,18 @@ public void convertRecurringExpensesCurrency(Currency newCurrency, RecurringExpe

int numberOfExpenseList = recurringExpenseLists.getSize();

ui.printDivider();
System.out.println("Conversion for expenses in Recurring Expenses : ");

for (int i = 0; i < numberOfExpenseList; i++) {
int arrayIndexAsListNumber = i + 1;
ExpenseList reccuringExpenseList = recurringExpenseLists.getExpenseListAtListNumber(arrayIndexAsListNumber);
System.out.print("Changing the default currency for " + reccuringExpenseList.getName() + ": ");
convertExpenseCurrency(newCurrency, reccuringExpenseList);
}

System.out.println("Default currency for Recurring Expenses changed to " + newCurrency);
ui.printDivider();
}

public void convertBudgetCurrency(Currency newCurrency, ExpenseList expenseList) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public void createCommand_duplicateParameters_returnsNull() {
assertNull(initializeFindExpensesCommandCreator(inputWithDuplicateMaxAmount).createCommand());
}

@Test
public void createCommand_outOfOrderParameters_returnsNull() {
String inputWithOutOfOrderAmountParameters = "find expenses d/23 lessthan/40 morethan/";
String inputWithOutOfOrderDescriptionParameter = "find expenses morethan/ d/23 lessthan/40";
assertNull(initializeFindExpensesCommandCreator(inputWithOutOfOrderAmountParameters).createCommand());
assertNull(initializeFindExpensesCommandCreator(inputWithOutOfOrderDescriptionParameter).createCommand());
}
@Test
public void createCommand_invalidMinAmount_returnsNull() {
String validInputWithEmptyDescription = "find expenses d/hello morethan/dsfefew lessthan/20";
Expand Down
Loading