Skip to content

Commit

Permalink
Add more error handling
Browse files Browse the repository at this point in the history
Separated out all Earl style responses from utility classes. Only
Handlers and Earl will generate user text. Added StorageException
and ParserException to replace previous use of EarlException in
such cases.
  • Loading branch information
yisiox committed Feb 16, 2024
1 parent e3bbfce commit 05a726c
Show file tree
Hide file tree
Showing 15 changed files with 98 additions and 65 deletions.
20 changes: 17 additions & 3 deletions src/main/java/earl/Earl.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package earl;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.exceptions.StorageException;
import earl.logic.Handler;
import earl.util.Storage;
import earl.util.TaskList;
Expand All @@ -27,8 +29,8 @@ public Earl(String filePath) {
storage = new Storage(filePath);
tasks = new TaskList(storage.load(TaskStorageParser::parse));
if (!storage.wasLoadSuccessful()) {
ui.makeResponse("Failed to read from storage.",
"Starting with empty file...");
ui.makeResponse("Storage hath succumb to corruption... ",
"initiating an unfortunate state of emptiness.");
}
ui.showGreeting();
}
Expand All @@ -53,16 +55,21 @@ public void run() {
try {
Handler handler = InputParser.parse(input);
handler.handle(tasks, ui);

} catch (EarlException e) {
ui.makeResponse(e.getMessage());

} catch (ParserException e) {
ui.makeResponse("Input defies parsing:" + e.getMessage());

} finally {
input = ui.getUserInput();
}
}
// save to file
try {
storage.save(tasks.getAsStorageStringStream());
} catch (EarlException e) {
} catch (StorageException e) {
ui.makeResponse(e.getMessage());
}
ui.showGoodbye();
Expand All @@ -87,6 +94,13 @@ public String getResponse(String input) {
} catch (EarlException e) {
ui.makeResponse(e.getMessage());
return ui.getResponse();
} catch (StorageException e) {
ui.makeResponse("Alas, a grievous misfortune occurred "
+ "during the endeavour to save.");
return ui.getResponse();
} catch (ParserException e) {
ui.makeResponse("Input defies parsing:" + e.getMessage());
return ui.getResponse();
}
}
}
14 changes: 14 additions & 0 deletions src/main/java/earl/exceptions/ParserException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package earl.exceptions;

/**
* Class representing exceptions encountered by the {@code Parser} classes.
*/
public class ParserException extends Exception {

public ParserException() {
super();
}
public ParserException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/earl/exceptions/StorageException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package earl.exceptions;

/**
* Class representing errors encountered by the {@code Storage} class.
*/
public class StorageException extends Exception {
}
7 changes: 5 additions & 2 deletions src/main/java/earl/logic/DeleteHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package earl.logic;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.util.TaskList;
import earl.util.Ui;

Expand Down Expand Up @@ -28,8 +29,10 @@ public void handle(TaskList tasks, Ui ui) throws EarlException {
}
addDisplayEntry("Item(s) heretofore have been expunged.");
ui.makeResponse(getDisplay());
} catch (EarlException e) {
throw e;
} catch (ParserException e) {
throw new EarlException(
"The indices' format is fraught with invalidity."
+ " Example format: 1 4-7 9-10");
} catch (Exception e) {
throw new EarlException("Command hath faltered: "
+ "obscure employment of delete.");
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/earl/logic/MarkHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package earl.logic;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.util.TaskList;
import earl.util.Ui;

Expand Down Expand Up @@ -35,8 +36,10 @@ public void handle(TaskList tasks, Ui ui) throws EarlException {
}
addDisplayEntry("Item(s) duly accomplished.");
ui.makeResponse(getDisplay());
} catch (EarlException e) {
throw e;
} catch (ParserException e) {
throw new EarlException(
"The indices' format is fraught with invalidity."
+ " Example format: 1 4-7 9-10");
} catch (Exception e) {
throw new EarlException("Command hath faltered: "
+ "obscure employment of mark.");
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/earl/logic/MassOperableHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.util.Collections;
import java.util.List;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.util.TaskList;
import earl.util.parsers.IntervalParser;

Expand All @@ -23,13 +23,13 @@ public MassOperableHandler(String args) {
/**
* Returns an array of unique valid indices in reverse sorted order.
*
* @param tasks a {@code TaskList} object
* @param args user input arguments
* @return an array of valid indices
* @throws EarlException if the user input is incomprehensible
* @param tasks a {@code TaskList} object
* @param args user input arguments
* @return an array of valid indices
* @throws ParserException if the user input is incomprehensible
*/
protected Integer[] getValidIndices(TaskList tasks,
String args) throws EarlException {
String args) throws ParserException {
return IntervalParser.parse(args)
.filter((idx) -> 0 <= idx && idx < tasks.getSize())
.toArray(Integer[]::new);
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/earl/logic/UnmarkHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package earl.logic;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.util.TaskList;
import earl.util.Ui;

Expand Down Expand Up @@ -33,8 +34,10 @@ public void handle(TaskList tasks, Ui ui) throws EarlException {
}
addDisplayEntry("Item(s) persist as undone.");
ui.makeResponse(getDisplay());
} catch (EarlException e) {
throw e;
} catch (ParserException e) {
throw new EarlException(
"The indices' format is fraught with invalidity."
+ " Example format: 1 4-7 9-10");
} catch (Exception e) {
throw new EarlException("Command hath faltered: "
+ "obscure employment of unmark.");
Expand Down
15 changes: 9 additions & 6 deletions src/main/java/earl/util/Storage.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.util.Scanner;
import java.util.stream.Stream;

import earl.exceptions.EarlException;
import earl.exceptions.StorageException;
import earl.util.parsers.ParseFunction;

/**
Expand Down Expand Up @@ -39,13 +39,16 @@ public Storage(String filePath) {
*/
public <T> Stream<T> load(ParseFunction<T> parse) {
try {
// Ensure file exists
File file = new File(filePath);
boolean isFolderMade = file.getParentFile().mkdirs();
boolean isFileMade = file.createNewFile();
assert file.exists();
if (isFolderMade || isFileMade) {
return Stream.empty();
}

// Read lines from file
Scanner sc = new Scanner(file);
List<T> result = new ArrayList<>();
while (sc.hasNext()) {
Expand All @@ -54,6 +57,7 @@ public <T> Stream<T> load(ParseFunction<T> parse) {
}
wasLoadSuccessful = true;
return result.stream();

} catch (Exception e) {
return Stream.empty();
}
Expand All @@ -67,10 +71,10 @@ public boolean wasLoadSuccessful() {
/**
* Saves given stream of {@code String} onto the disk.
*
* @param dataStream a {@code Stream} of {@code String} to be saved
* @throws EarlException if the file could not be written to
* @param dataStream a {@code Stream} of {@code String} to be saved
* @throws StorageException if the file could not be written to
*/
public void save(Stream<String> dataStream) throws EarlException {
public void save(Stream<String> dataStream) throws StorageException {
try (FileWriter fw = new FileWriter(filePath)) {
dataStream.map((str) -> str + "\n")
.forEach((str) -> {
Expand All @@ -81,8 +85,7 @@ public void save(Stream<String> dataStream) throws EarlException {
}
});
} catch (Exception e) {
throw new EarlException("Alas, a grievous misfortune occurred "
+ "during the endeavour to save.");
throw new StorageException();
}
}
}
12 changes: 6 additions & 6 deletions src/main/java/earl/util/parsers/InputParser.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package earl.util.parsers;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.logic.Handler;
import earl.logic.HandlerType;

Expand All @@ -12,11 +12,11 @@ public class InputParser implements Parser<Handler> {
/**
* Returns a new {@code Handler} object based on user input.
*
* @param input text input by the user
* @return a {@code Handler} object of the relevant type
* @throws EarlException if user input is of unexpected format
* @param input text input by the user
* @return a {@code Handler} object of the relevant type
* @throws ParserException if user input is of unexpected format
*/
public static Handler parse(String input) throws EarlException {
public static Handler parse(String input) throws ParserException {
try {
// all valid input is expected to be of the format
// <command> [<arg1>, <arg2>, ...]
Expand All @@ -26,7 +26,7 @@ public static Handler parse(String input) throws EarlException {
HandlerType handlerType = HandlerType.valueOf(command);
return handlerType.createHandler(args);
} catch (Exception e) {
throw new EarlException("Input defies parsing: " + input);
throw new ParserException(input);
}
}
}
16 changes: 6 additions & 10 deletions src/main/java/earl/util/parsers/IntervalParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;

/**
* Class responsible for interpreting complex ranges input by the user.
Expand All @@ -14,11 +14,11 @@ public class IntervalParser implements Parser<Stream<Integer>> {
/**
* Returns a stream of unique indices in reverse sorted order.
*
* @param input the user input ranges
* @return a {@code Stream} of indices
* @throws EarlException if the user input is incomprehensible
* @param input the user input ranges
* @return a {@code Stream} of indices
* @throws ParserException if the user input is incomprehensible
*/
public static Stream<Integer> parse(String input) throws EarlException {
public static Stream<Integer> parse(String input) throws ParserException {
try {
String[] args = input.split("\\s+");
Stream<Integer> result = Stream.empty();
Expand All @@ -36,12 +36,8 @@ public static Stream<Integer> parse(String input) throws EarlException {
IntStream.range(start, end).boxed());
}
return result.distinct().sorted(Collections.reverseOrder());
} catch (IndexOutOfBoundsException | NumberFormatException e) {
throw new EarlException(
"The indices' format is fraught with invalidity."
+ " Example format: 1 4-7 9-10");
} catch (Exception e) {
throw new EarlException("The argument format is most confounding.");
throw new ParserException();
}
}
}
4 changes: 1 addition & 3 deletions src/main/java/earl/util/parsers/ParseFunction.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package earl.util.parsers;

import earl.exceptions.EarlException;

/**
* Custom functional interface for parse functions.
*
* @param <T> the type that the parser returns
*/
@FunctionalInterface
public interface ParseFunction<T> {
T apply(String str) throws EarlException;
T apply(String str) throws Exception;
}
16 changes: 6 additions & 10 deletions src/main/java/earl/util/parsers/TaskStorageParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.Arrays;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.tasks.Task;
import earl.tasks.TaskType;

Expand All @@ -14,11 +14,11 @@ public class TaskStorageParser implements Parser<Task> {
/**
* Returns a {@code Task} object based on the stored string.
*
* @param entry storage entry string
* @return a {@code Task} object
* @throws EarlException if the storage entry is incomprehensible
* @param entry storage entry string
* @return a {@code Task} object
* @throws ParserException if the storage entry is incomprehensible
*/
public static Task parse(String entry) throws EarlException {
public static Task parse(String entry) throws ParserException {
try {
String[] data = entry.split(",");
String type = data[0];
Expand All @@ -30,12 +30,8 @@ public static Task parse(String entry) throws EarlException {
task.markAsDone();
}
return task;
} catch (IllegalArgumentException e) {
throw new EarlException("Storage hath succumb to corruption... "
+ "initiating an unfortunate state of emptiness.");
} catch (Exception e) {
throw new EarlException("An enigmatic malady has manifested and "
+ "obstructed the parsing of the storage file");
throw new ParserException();
}
}
}
6 changes: 3 additions & 3 deletions src/test/java/earl/util/parsers/InputParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import org.junit.jupiter.api.Test;

import earl.exceptions.EarlException;
import earl.exceptions.ParserException;
import earl.logic.Handler;
import earl.logic.TodoHandler;

Expand All @@ -25,8 +25,8 @@ void parse_invalidInput_exceptionThrown() {
try {
InputParser.parse("TODO ip");
fail();
} catch (EarlException e) {
assertEquals("Input defies parsing: TODO ip", e.getMessage());
} catch (ParserException e) {
assertEquals("TODO ip", e.getMessage());
}
}
}
Loading

0 comments on commit 05a726c

Please sign in to comment.