From 21b3bd922c005b984f8843c4d2e2b114772e8c45 Mon Sep 17 00:00:00 2001
From: lzq
Date: Mon, 19 Sep 2022 16:19:42 +0800
Subject: [PATCH] Fixes some bugs - Throws error when no parameter commands are
called with command - Fixes program not exiting when a fatal error occurs
when running - Allows save data to be created through nested folders - Fixed
notification of when parsing corrupted lines
---
src/main/java/duke/command/ByeCommand.java | 12 +++++-
src/main/java/duke/command/ListCommand.java | 13 +++++-
.../java/duke/command/NoParamCommand.java | 29 +++++++++++++
.../java/duke/command/ResetAliasCommand.java | 13 +++++-
.../java/duke/command/SwapFaceCommand.java | 16 ++++++-
.../java/duke/inputoutput/DukeAbstractIo.java | 5 +++
src/main/java/duke/inputoutput/DukeIo.java | 7 ++++
src/main/java/duke/main/Duke.java | 25 ++++-------
src/main/java/duke/util/DataParser.java | 12 +++---
src/main/java/duke/util/Storage.java | 42 +++++++++++++------
10 files changed, 131 insertions(+), 43 deletions(-)
create mode 100644 src/main/java/duke/command/NoParamCommand.java
diff --git a/src/main/java/duke/command/ByeCommand.java b/src/main/java/duke/command/ByeCommand.java
index 8e9e71a942..0acdbdf44f 100644
--- a/src/main/java/duke/command/ByeCommand.java
+++ b/src/main/java/duke/command/ByeCommand.java
@@ -2,17 +2,23 @@
import java.io.IOException;
+import duke.exceptions.UnknownCommandException;
import duke.inputoutput.DukeCliSettings;
import duke.inputoutput.DukeIo;
+import duke.util.ParsedData;
import duke.util.Storage;
import duke.util.TaskList;
/**
* Command class that exit the program. When bye is entered
*/
-public class ByeCommand implements Command {
+public class ByeCommand extends NoParamCommand {
private static final String OUTRO = "Pff.. Not like I want to see you again";
+ public ByeCommand(ParsedData data) {
+ super(data);
+ }
+
/**
* Returns true when asked if program should exit.
*
@@ -27,9 +33,11 @@ public boolean isExit() {
* {@inheritDoc} Prints goodbye message and exits program.
*
* @throws IOException raised if an error occured when saving
+ * @throws UnknownCommandException when extra parameters is included
*/
@Override
- public void execute(TaskList tasks, DukeIo io, Storage storage) throws IOException {
+ public void execute(TaskList tasks, DukeIo io, Storage storage) throws IOException, UnknownCommandException {
+ checkSingleArgumentGuard();
io.printTask(OUTRO, DukeCliSettings.WRAP_INDENT);
storage.saveTasks(tasks);
}
diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java
index c25c380ed6..4ef6bdf583 100644
--- a/src/main/java/duke/command/ListCommand.java
+++ b/src/main/java/duke/command/ListCommand.java
@@ -1,13 +1,19 @@
package duke.command;
+import duke.exceptions.UnknownCommandException;
import duke.inputoutput.DukeIo;
+import duke.util.ParsedData;
import duke.util.Storage;
import duke.util.TaskList;
/**
* Command to list out all the current tasks.
*/
-public class ListCommand implements Command {
+public class ListCommand extends NoParamCommand {
+
+ public ListCommand(ParsedData data) {
+ super(data);
+ }
/**
* {@inheritDoc} List command does not exit
@@ -19,9 +25,12 @@ public boolean isExit() {
/**
* Prints out all the current tasks added.
+ *
+ * @throws UnknownCommandException when extra parameters is included
*/
@Override
- public void execute(TaskList tasks, DukeIo io, Storage storage) {
+ public void execute(TaskList tasks, DukeIo io, Storage storage) throws UnknownCommandException {
+ checkSingleArgumentGuard();
io.printNumberedList(tasks.getTasks());
}
diff --git a/src/main/java/duke/command/NoParamCommand.java b/src/main/java/duke/command/NoParamCommand.java
new file mode 100644
index 0000000000..104540371d
--- /dev/null
+++ b/src/main/java/duke/command/NoParamCommand.java
@@ -0,0 +1,29 @@
+package duke.command;
+
+import duke.exceptions.UnknownCommandException;
+import duke.util.ParsedData;
+
+/**
+ * Abstract class to handle commands that requires no argument
+ */
+abstract class NoParamCommand implements Command {
+
+ private boolean invalid;
+
+ NoParamCommand(ParsedData data) {
+ if (data.description.isEmpty()) {
+ invalid = false;
+ } else {
+ invalid = true;
+ }
+ }
+
+ /**
+ * Guards to ensure commands contains no extra parameters
+ */
+ protected void checkSingleArgumentGuard() throws UnknownCommandException {
+ if (invalid) {
+ throw new UnknownCommandException();
+ }
+ }
+}
diff --git a/src/main/java/duke/command/ResetAliasCommand.java b/src/main/java/duke/command/ResetAliasCommand.java
index a795b8f919..9e70370955 100644
--- a/src/main/java/duke/command/ResetAliasCommand.java
+++ b/src/main/java/duke/command/ResetAliasCommand.java
@@ -2,16 +2,23 @@
import java.io.IOException;
+import duke.exceptions.UnknownCommandException;
import duke.inputoutput.DukeIo;
+import duke.util.ParsedData;
import duke.util.Storage;
import duke.util.TaskList;
/**
* Command class that resets set aliases
*/
-public class ResetAliasCommand implements Command {
+public class ResetAliasCommand extends NoParamCommand {
+
private static final String OUTRO = "Back to beginning!";
+ public ResetAliasCommand(ParsedData data) {
+ super(data);
+ }
+
/**
* Returns true when asked if program should exit.
*
@@ -26,9 +33,11 @@ public boolean isExit() {
* {@inheritDoc} Resets all added aliases.
*
* @throws IOException raised if an error occured when saving
+ * @throws UnknownCommandException when extra parameters is included
*/
@Override
- public void execute(TaskList tasks, DukeIo io, Storage storage) throws IOException {
+ public void execute(TaskList tasks, DukeIo io, Storage storage) throws IOException, UnknownCommandException {
+ checkSingleArgumentGuard();
io.printTask(OUTRO);
CommandSelector.reset();
}
diff --git a/src/main/java/duke/command/SwapFaceCommand.java b/src/main/java/duke/command/SwapFaceCommand.java
index 7ff94d86fe..f1188dd0c3 100644
--- a/src/main/java/duke/command/SwapFaceCommand.java
+++ b/src/main/java/duke/command/SwapFaceCommand.java
@@ -6,9 +6,11 @@
import duke.exceptions.GuiOnlyException;
import duke.exceptions.ImageDownloadFailedException;
import duke.exceptions.OperatonIsStillRunningException;
+import duke.exceptions.UnknownCommandException;
import duke.gui.GuiDataController;
import duke.inputoutput.DukeGuiIo;
import duke.inputoutput.DukeIo;
+import duke.util.ParsedData;
import duke.util.Storage;
import duke.util.TaskList;
import javafx.concurrent.Task;
@@ -17,7 +19,7 @@
/**
* Command to list out all the current tasks.
*/
-public class SwapFaceCommand implements Command {
+public class SwapFaceCommand extends NoParamCommand {
private static final String RESPONSE = "I'm gonna replace us! We are not real after all! Goodbye!";
private static final String SUCCESS = "Nice to meet you, I am duke.";
private static final String ANIME_FAKE_IMAGE = "https://www.thiswaifudoesnotexist.net/example-%d.jpg";
@@ -25,6 +27,10 @@ public class SwapFaceCommand implements Command {
private static boolean isRunning = false;
+ public SwapFaceCommand(ParsedData data) {
+ super(data);
+ }
+
/**
* {@inheritDoc} List command does not exit
*/
@@ -35,10 +41,16 @@ public boolean isExit() {
/**
* Prints out all the current tasks added.
+ *
+ * @throws GuiOnlyException when called via CLI mode
+ * @throws OperatonIsStillRunningException when another swap face command is running
+ * @throws UnknownCommandException when extra parameters is included
*/
@Override
public void execute(TaskList tasks, DukeIo io, Storage storage)
- throws GuiOnlyException, OperatonIsStillRunningException {
+ throws GuiOnlyException, OperatonIsStillRunningException, UnknownCommandException {
+
+ checkSingleArgumentGuard();
if (!(io instanceof DukeGuiIo)) {
throw new GuiOnlyException();
}
diff --git a/src/main/java/duke/inputoutput/DukeAbstractIo.java b/src/main/java/duke/inputoutput/DukeAbstractIo.java
index 1b50f085aa..9827feeb30 100644
--- a/src/main/java/duke/inputoutput/DukeAbstractIo.java
+++ b/src/main/java/duke/inputoutput/DukeAbstractIo.java
@@ -104,6 +104,11 @@ public void printError(Exception e) {
printTask(String.format("🙄 OOPS!!! %s", e.getMessage()));
}
+ @Override
+ public void printError(String msg) {
+ printError(new Exception(msg));
+ }
+
protected boolean isBitFlag(int bitsValue, DukeCliSettings flagEnum) {
return (bitsValue & flagEnum.value) == flagEnum.value;
}
diff --git a/src/main/java/duke/inputoutput/DukeIo.java b/src/main/java/duke/inputoutput/DukeIo.java
index b432ff55a8..7f0dc9c054 100644
--- a/src/main/java/duke/inputoutput/DukeIo.java
+++ b/src/main/java/duke/inputoutput/DukeIo.java
@@ -44,6 +44,13 @@ public interface DukeIo {
*/
void printError(Exception e);
+ /**
+ * Prints the message in the format of an exception
+ *
+ * @param msg message to print
+ */
+ void printError(String msg);
+
/**
* Prints Text with selected features
*
diff --git a/src/main/java/duke/main/Duke.java b/src/main/java/duke/main/Duke.java
index a1ccf1b7c7..38eb5945cf 100644
--- a/src/main/java/duke/main/Duke.java
+++ b/src/main/java/duke/main/Duke.java
@@ -16,8 +16,8 @@
*/
public class Duke {
private static final String LOGO =
- "Welcome to\n" + " ____ _ \n" + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n" + " Chatbot!\n";
+ "Welcome to\n" + " ____ _ \n" + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n"
+ + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n" + " Chatbot!\n";
private static final String INTRO = "Hey hey hey! I'm Duke\n" + "What can I do for you?";
@@ -48,9 +48,11 @@ public boolean handleInput(String txt) {
c.execute(tasks, userInputOutput, dukeData);
} catch (DukeException e) {
userInputOutput.printError(e);
+ return true;
} catch (IOException e) {
userInputOutput.printError(e);
- return true;
+ userInputOutput.printError(FATAL_EXIT);
+ return false;
}
return !c.isExit();
@@ -84,18 +86,7 @@ public static Duke createApplication() {
* @return returns an instance of Duke
*/
public static Duke createApplication(DukeIo userIo) {
- Storage dukeData;
- TaskList tasks;
- try {
- dukeData = Storage.createStorage();
- tasks = new TaskList(dukeData.readFile());
- } catch (IOException e) {
- userIo.printError(e);
- userIo.printTask(FATAL_EXIT);
- return null;
- }
-
- return new Duke(tasks, dukeData, userIo);
+ return createApplication(userIo, "");
}
/**
@@ -110,10 +101,10 @@ public static Duke createApplication(DukeIo userIo, String filePath) {
TaskList tasks;
try {
dukeData = Storage.createStorage(filePath);
- tasks = new TaskList(dukeData.readFile());
+ tasks = new TaskList(dukeData.readFile(userIo));
} catch (IOException e) {
userIo.printError(e);
- userIo.printTask(FATAL_EXIT);
+ userIo.printError(FATAL_EXIT);
return null;
}
diff --git a/src/main/java/duke/util/DataParser.java b/src/main/java/duke/util/DataParser.java
index 374c0ae686..bdb4a4eddf 100644
--- a/src/main/java/duke/util/DataParser.java
+++ b/src/main/java/duke/util/DataParser.java
@@ -71,9 +71,13 @@ public static Command dataToCommand(ParsedData data) {
switch (CommandSelector.getCs().getCommand(data.command)) {
case BYE:
- return new ByeCommand();
+ return new ByeCommand(data);
case LIST:
- return new ListCommand();
+ return new ListCommand(data);
+ case SWAP:
+ return new SwapFaceCommand(data);
+ case RESETALIAS:
+ return new ResetAliasCommand(data);
case MARK:
return new MarkCommand(data);
case UNMARK:
@@ -94,10 +98,6 @@ public static Command dataToCommand(ParsedData data) {
return new AliasCommand(data);
case DELETECOMMAND:
return new DeleteAliasCommand(data);
- case SWAP:
- return new SwapFaceCommand();
- case RESETALIAS:
- return new ResetAliasCommand();
case INVALID:
default:
return new InvalidCommand();
diff --git a/src/main/java/duke/util/Storage.java b/src/main/java/duke/util/Storage.java
index 728f4a7d7f..5398b18455 100644
--- a/src/main/java/duke/util/Storage.java
+++ b/src/main/java/duke/util/Storage.java
@@ -9,6 +9,7 @@
import java.util.Scanner;
import duke.exceptions.CorruptedLineException;
+import duke.inputoutput.DukeIo;
import duke.task.Task;
/**
@@ -17,6 +18,7 @@
public class Storage {
private static final String DEFAULT_SAVE_PATH = "data/SavedData.duke";
+ private static final String PARSE_FAIL = "I was unable to parse line %s of the save file!";
private File file;
private Storage(File file) {
@@ -31,12 +33,11 @@ private Storage(File file) {
* @throws IOException Throws if pathing cannot exist.
*/
public static Storage createStorage(String path) throws IOException {
- File newFile = new File(path);
- File parentFolder = newFile.getParentFile();
- if (parentFolder != null) {
- parentFolder.mkdir();
+ if (path.trim().isEmpty()) {
+ path = DEFAULT_SAVE_PATH;
}
- newFile.createNewFile();
+ File newFile = new File(path);
+ ensureExistance(newFile);
return new Storage(newFile);
}
@@ -50,13 +51,24 @@ public static Storage createStorage() throws IOException {
return createStorage(DEFAULT_SAVE_PATH);
}
+ private static void ensureExistance(File file) throws IOException {
+ if (file.exists()) {
+ return;
+ }
+ File parentFolder = file.getParentFile();
+ if (parentFolder != null) {
+ parentFolder.mkdirs();
+ }
+ file.createNewFile();
+ }
+
/**
* Read the save file and convert it to a list of Task.
*
* @return List of Tasks
* @throws FileNotFoundException Throws when save file does not exist
*/
- public List readFile() throws FileNotFoundException {
+ public List readFile(DukeIo io) throws FileNotFoundException {
List ret = new ArrayList<>();
List corruptedLines = new ArrayList<>();
@@ -75,6 +87,16 @@ public List readFile() throws FileNotFoundException {
}
}
sc.close();
+ if (corruptedLines.size() == 0) {
+ return ret;
+ }
+ StringBuilder joinedList = corruptedLines.stream().collect(StringBuilder::new, (sb, num) -> {
+ sb.append(num);
+ sb.append(", ");
+ }, StringBuilder::append);
+ // removes the ", " of the last string
+ joinedList.setLength(joinedList.length() - 2);
+ io.printError(String.format(PARSE_FAIL, joinedList.toString()));
return ret;
}
@@ -85,9 +107,7 @@ public List readFile() throws FileNotFoundException {
* @throws IOException Throws when save file doesn't exist
*/
public void saveData(ParsedData[] dataList) throws IOException {
- if (!file.exists()) {
- file.createNewFile();
- }
+ ensureExistance(file);
assert file.exists();
StringBuilder sb = new StringBuilder();
@@ -117,9 +137,7 @@ public void saveTasks(TaskList tl) throws IOException {
* @throws IOException Throws when save file is missing
*/
public void saveTask(Task task) throws IOException {
- if (!file.exists()) {
- file.createNewFile();
- }
+ ensureExistance(file);
assert file.exists();
FileWriter fw = new FileWriter(file, true);