diff --git a/README.md b/README.md index 8715d4d9..a8111be7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Duke project template +# duke.duke project template This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. @@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version. 1. If there are any further prompts, accept the defaults. 1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
In the same dialog, set the **Project language level** field to the `SDK default` option. -3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: +3. After that, locate the `src/main/java/duke.duke.java` file, right-click it, and choose `Run duke.duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: ``` Hello from ____ _ diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..dda93802 --- /dev/null +++ b/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' +} + +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "duke.Duke" +} + +shadowJar { + archiveBaseName = "duke" + archiveClassifier = null +} + +checkstyle { + toolVersion = '8.29' +} + +run{ + standardInput = System.in +} diff --git a/duke.txt b/duke.txt new file mode 100644 index 00000000..39424621 --- /dev/null +++ b/duke.txt @@ -0,0 +1,14 @@ +T | 0 | eat | 0 +T | 0 | read sales report | 2 +T | 0 | read sales report | 2 +T | 0 | eat | 0 +T | 0 | sleep | 0 +D | 0 | return book | 2021-11-05 | 22:00 +D | 1 | read book | 2021-11-05 | 15:00 +D | 0 | borrow book | 2021-11-05 | 11:00 +E | 0 | project meeting | 2021-11-05 | 14:00 | 16:00 +E | 0 | family dinner | 2021-11-05 | 18:00 | 21:00 +T | 0 | submit claim | 0 +T | 0 | read sales report | 2 +D | 0 | return book | 2021-11-05 | 22:00 +E | 0 | family dinner | 2021-11-05 | 18:00 | 21:00 diff --git a/fixedDurationTask.txt b/fixedDurationTask.txt new file mode 100644 index 00000000..e786b73e --- /dev/null +++ b/fixedDurationTask.txt @@ -0,0 +1,4 @@ +read sales report | 2 +read book | 1 +do homework | 4 +submit claims | 1 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..f3d88b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..b7c8c5db --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..2fe81a7d --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..62bd9b9c --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334..00000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java new file mode 100644 index 00000000..783fd500 --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,55 @@ +package duke; + +import duke.exception.DukeException; +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + + +public class Duke { + private static StorageTaskList storageTaskList; + private UI ui; + private TaskList taskList; + + /** + * Initializes entire duke. + * + * @param filePath - filepath to storage. + */ + public Duke(String filePath) { + ui = new UI(); + ui.showWelcome(); + storageTaskList = new StorageTaskList(filePath); + try { + taskList = new TaskList(storageTaskList.load()); + } catch (DukeException e) { + ui.showLoadingError(); + taskList = new TaskList(); + } + } + + public void run() throws DukeException { + boolean isExit = false; + + while (!isExit) { + try { + String fullCommand = ui.readCommand(); + ui.showLine(); // show the divider line ("_______") + Command c = CommandParser.parse(fullCommand); + c.execute(taskList, ui, storageTaskList); + isExit = c.isExit(); + } catch (DukeException e) { + ui.showError(e); + } finally { + ui.showLine(); + } + } + ui.showExit(); + } + + public static void main(String[] args) throws DukeException { + new Duke("duke.txt").run(); + } +} diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java new file mode 100644 index 00000000..7104bc7d --- /dev/null +++ b/src/main/java/duke/exception/DukeException.java @@ -0,0 +1,16 @@ +package duke.exception; + +public class DukeException extends RuntimeException{ + /** + * Throws base class for self-defined exceptions. + * + * @param message the pre-defined message. + */ + public DukeException(String message) { + super(message); + } + + + public DukeException() {//testing + } +} diff --git a/src/main/java/duke/exception/EmptyDescriptionException.java b/src/main/java/duke/exception/EmptyDescriptionException.java new file mode 100644 index 00000000..926835c7 --- /dev/null +++ b/src/main/java/duke/exception/EmptyDescriptionException.java @@ -0,0 +1,14 @@ +package duke.exception; + +public class EmptyDescriptionException extends DukeException{ + + /** + * Throws when user did not give a description for the task. + * + * @param message the pre-defined message. + */ + public EmptyDescriptionException(String message) { + super(message); + } + +} diff --git a/src/main/java/duke/exception/EmptyTaskListException.java b/src/main/java/duke/exception/EmptyTaskListException.java new file mode 100644 index 00000000..8b95d89a --- /dev/null +++ b/src/main/java/duke/exception/EmptyTaskListException.java @@ -0,0 +1,16 @@ +package duke.exception; + + +public class EmptyTaskListException extends DukeException{ + + /** + * Throws when the task list is empty. + * + * @param message Printing message overload. + */ + public EmptyTaskListException(String message) { + super(message); + } + /* + */ +} diff --git a/src/main/java/duke/exception/SavingException.java b/src/main/java/duke/exception/SavingException.java new file mode 100644 index 00000000..07da9d8c --- /dev/null +++ b/src/main/java/duke/exception/SavingException.java @@ -0,0 +1,14 @@ +package duke.exception; + +public class SavingException extends DukeException{ + /** + * Throws when there is problem saving the current task list. + * + * @param message the pre-defined message. + * + */ + public SavingException(String message) { + super(message); + } + +} diff --git a/src/main/java/duke/exception/TaskNotFoundException.java b/src/main/java/duke/exception/TaskNotFoundException.java new file mode 100644 index 00000000..15e6181e --- /dev/null +++ b/src/main/java/duke/exception/TaskNotFoundException.java @@ -0,0 +1,13 @@ +package duke.exception; + +public class TaskNotFoundException extends DukeException{ + /** + * Throws when failed to identify task, either given wrong information or task does not exist. + * + * @param message the pre-defined message. + */ + public TaskNotFoundException(String message) { + super(message); + } +} + diff --git a/src/main/java/duke/exception/TimeManagementException.java b/src/main/java/duke/exception/TimeManagementException.java new file mode 100644 index 00000000..9fb69947 --- /dev/null +++ b/src/main/java/duke/exception/TimeManagementException.java @@ -0,0 +1,8 @@ +package duke.exception; + +public class TimeManagementException extends DukeException{ + + /** Throws when date-time not given for deadline/event task. */ + public TimeManagementException() { + } +} diff --git a/src/main/java/duke/exception/TimeParseException.java b/src/main/java/duke/exception/TimeParseException.java new file mode 100644 index 00000000..60e9507d --- /dev/null +++ b/src/main/java/duke/exception/TimeParseException.java @@ -0,0 +1,13 @@ +package duke.exception; + + +public class TimeParseException extends DukeException{ + /** + * Throws when error occurred while parsing time. + * + * @param message the pre-defined message. + */ + public TimeParseException(String message) { + super(message); + } +} diff --git a/src/main/java/duke/exception/UnknownSyntaxException.java b/src/main/java/duke/exception/UnknownSyntaxException.java new file mode 100644 index 00000000..854663cc --- /dev/null +++ b/src/main/java/duke/exception/UnknownSyntaxException.java @@ -0,0 +1,12 @@ +package duke.exception; + +public class UnknownSyntaxException extends DukeException{ + /** + * Throws when user input does not categorize under any of the pre-defined message. + * + * @param message the pre-defined message. + */ + public UnknownSyntaxException(String message) { + super(message); + } +} diff --git a/src/main/java/duke/parser/Command.java b/src/main/java/duke/parser/Command.java new file mode 100644 index 00000000..3862440a --- /dev/null +++ b/src/main/java/duke/parser/Command.java @@ -0,0 +1,49 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class Command { + + /** Declares CommandBase Object. */ + private CommandBase commandBase; + + /** Checks if the input is "bye". */ + private boolean shouldExit; + + /** + * Checks if to exit or continue the runtime after each execution. + * + * @param taskList task list object + * @param ui ui object + * @param storageTaskList storage task list object + */ + public void execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + this.shouldExit = commandBase.execute(taskList, ui, storageTaskList); + } + + /** + * Checks if isExit true. + * + * @return isExit true or false. + */ + public boolean isExit() { + + return this.shouldExit; + } + + /** + * Returns CommandBase object. + * + * @return CommandBase object. + */ + public CommandBase getCommandBase() { + return commandBase; + } + + /** Sets CommandBase object. */ + public void setCmd(CommandBase commandBase) { + this.commandBase = commandBase; + } +} \ No newline at end of file diff --git a/src/main/java/duke/parser/CommandAdd.java b/src/main/java/duke/parser/CommandAdd.java new file mode 100644 index 00000000..cd77e8ca --- /dev/null +++ b/src/main/java/duke/parser/CommandAdd.java @@ -0,0 +1,13 @@ +package duke.parser; + +public class CommandAdd extends CommandBase { + + /** + * Creates Add Command Constructor. + * + * @param command the full command. + */ + public CommandAdd(String command) { + super(command); + } +} diff --git a/src/main/java/duke/parser/CommandBase.java b/src/main/java/duke/parser/CommandBase.java new file mode 100644 index 00000000..4fb4959a --- /dev/null +++ b/src/main/java/duke/parser/CommandBase.java @@ -0,0 +1,113 @@ +package duke.parser; + +import duke.exception.EmptyDescriptionException; +import duke.exception.EmptyTaskListException; +import duke.exception.TaskNotFoundException; +import duke.exception.UnknownSyntaxException; +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.ReturnMessages; +import duke.ui.UI; + +/** + * Creates base command class. + * CommandBase is the base class of all command objects. It contains some public attributes and methods. + * Each class that inherits CommandBase only needs to perform its own duty. + */ +public class CommandBase { + + /** Declares command user input. */ + protected String fullCommand; + + /** Declares command to be executed. */ + protected String keyword; + + /** Declares command parameters. */ + protected String detail; + + /** Returns message object. */ + private static ReturnMessages returnMessage = new ReturnMessages(); + + /** + * Tells the command to parse into keyword and detail(If needed). + * + * @param command full command of user input. + * @throws IndexOutOfBoundsException thrown when able to identify keyword but not the rest of the descriptions + * @throws UnknownSyntaxException thrown when syntax is unreadable + * @throws EmptyDescriptionException thrown after detecting description is empty + */ + public CommandBase(String command) throws ArrayIndexOutOfBoundsException, UnknownSyntaxException, EmptyDescriptionException{ + this.fullCommand = command; + this.keyword = ""; + this.detail = ""; + if(command.contains(CommandEnums.TODO.getName()) || command.contains(CommandEnums.DEADLINE.getName()) || command.contains(CommandEnums.EVENT.getName()) || command.contains(CommandEnums.VIEW.getName()) || command.contains(CommandEnums.FIND.getName())){ + try { + String[] toWords = command.split(" ", 2); + this.keyword = toWords[0]; + this.detail = toWords[1]; + } catch(ArrayIndexOutOfBoundsException aio) { + if(command.contains(CommandEnums.TODO.getName()) || command.contains(CommandEnums.DEADLINE.getName()) || command.contains(CommandEnums.EVENT.getName())){ + throw new EmptyDescriptionException(keyword); + } else { + throw new UnknownSyntaxException(command); + } + } + } + } + + public CommandBase() { + + } + + /** + * Executes command. + * + * @param taskList user generate. + * @param ui show interactive information. + * @param storageTaskList info where to storage. + * @return if true, the program stops, otherwise it starts. + */ + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList){ + return false; + } + + /** + * Replies a done/add command. + * + * @param taskList gets the full task list. + * @throws EmptyTaskListException thrown if task list is empty. + * @throws UnknownSyntaxException thrown if syntax is unknown. + * @throws TaskNotFoundException thrown if task is not found. + */ + public void reply(TaskList taskList) throws EmptyTaskListException, UnknownSyntaxException, TaskNotFoundException { + if(fullCommand.contains("done")){ + assert fullCommand.contains("done"):"It should have confirmed a done command by this stage"; + try { + String[] doneCommand = fullCommand.split(" "); + if(Integer.parseInt(doneCommand[1]) - 1 >= taskList.getListSize()){ + throw new TaskNotFoundException("you only have "+taskList.getListSize()+" and you entered "+Integer.parseInt(doneCommand[1])); + } + if(taskList.getTask(Integer.parseInt(doneCommand[1]) - 1).isDone()){ + returnMessage.taskAlreadyDoneFeedback(); + } else{ + taskList.getTask(Integer.parseInt(doneCommand[1]) - 1).setDone(); + returnMessage.taskDoneFeedback(); + System.out.println(" " + taskList.getTask(Integer.parseInt(doneCommand[1]) - 1).toString()); + } + returnMessage.separator(); + return; + } catch(NumberFormatException nf){ + throw new TaskNotFoundException("task does not exist"); + } + } + returnMessage.taskAddFeedback(); + assert taskList.getListSize()>0:"There should at least have 1 task"; + try { + System.out.println(" " + taskList.getLastTask().toString()); + System.out.println(" Now you have " + taskList.getListSize() + " tasks in the list."); + returnMessage.separator(); + } catch(ArrayIndexOutOfBoundsException a){ + throw new EmptyTaskListException("empty task"); + } + } +} diff --git a/src/main/java/duke/parser/CommandBye.java b/src/main/java/duke/parser/CommandBye.java new file mode 100644 index 00000000..c087ef93 --- /dev/null +++ b/src/main/java/duke/parser/CommandBye.java @@ -0,0 +1,30 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class CommandBye extends CommandBase { + /** + * Creates bye command constructor. + * + * @param command Full command. + */ + public CommandBye(String command){ + super(command); + } + + /** + * Executes of bye command. + * + * @param taskList user generate. + * @param ui show interactive information. + * @param storageTaskList info where to storage. + * @return if true, the program stops, otherwise it starts. + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + storageTaskList.save(taskList); + return true; + } +} diff --git a/src/main/java/duke/parser/CommandDeadline.java b/src/main/java/duke/parser/CommandDeadline.java new file mode 100644 index 00000000..5683fe7a --- /dev/null +++ b/src/main/java/duke/parser/CommandDeadline.java @@ -0,0 +1,71 @@ +package duke.parser; + +import duke.exception.TimeManagementException; +import duke.exception.TimeParseException; +import duke.exception.UnknownSyntaxException; +import duke.parser.timeHelper.DateTimeParse; +import duke.storage.StorageTaskList; +import duke.task.Deadline; +import duke.task.Task; +import duke.task.TaskList; +import duke.ui.UI; + +import java.time.LocalDateTime; + + +public class +CommandDeadline extends CommandBase { + + private DateTimeParse timeHelp = new DateTimeParse(); + + /** + * Creates deadline constructor. + * + * @param command full command. + */ + public CommandDeadline(String command){ + super(command); + } + + + /** + * Executes deadline command. + * + * @param taskList user generate. + * @param ui show interactive information. + * @param storageTaskList info where to storage. + * @return if true, the program stops, otherwise it starts. + * @throws TimeManagementException thrown when datetime not specified + * @throws TimeParseException thrown when datetime format is wrong + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) throws TimeManagementException, TimeParseException{ + boolean isSuccess = false; + try { + if (!CommandEnums.DEADLINE.getName().equals(super.keyword)){ + throw new UnknownSyntaxException(super.keyword); + } + String[] deadlineCommand = super.detail.split("/by", 2); + //region time parse + String[] dateTimes = deadlineCommand[1].split(" ", 2); + LocalDateTime dateT = timeHelp.dateAndTimeParse(dateTimes[1]); + //endregion + Task task = new Deadline(deadlineCommand[0], dateT); + if(taskList.addTask(task)){ + isSuccess = true; + assert taskList.getListSize()>0:"There should at least have 1 task"; + } + } catch (IndexOutOfBoundsException e) { + throw new TimeManagementException(); + } catch (TimeParseException e) { + throw new TimeParseException(e.getMessage()); + } + + if (isSuccess) { + reply(taskList); + } + + return false; + } + +} diff --git a/src/main/java/duke/parser/CommandDelete.java b/src/main/java/duke/parser/CommandDelete.java new file mode 100644 index 00000000..98494092 --- /dev/null +++ b/src/main/java/duke/parser/CommandDelete.java @@ -0,0 +1,31 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class CommandDelete extends CommandBase { + + /** + * Creates delete command constructor. + * + * @param command full command. + */ + public CommandDelete(String command) { + super(command); + } + + /** + * Executes delete command. + * + * @param taskList user generate. + * @param ui show interactive information. + * @param storageTaskList info where to storage. + * @return if true, the program stops, otherwise it starts. + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + taskList.deleteTask(Integer.parseInt(super.fullCommand.split(" ", 2)[1])); + return false; + } +} diff --git a/src/main/java/duke/parser/CommandDone.java b/src/main/java/duke/parser/CommandDone.java new file mode 100644 index 00000000..f8076f71 --- /dev/null +++ b/src/main/java/duke/parser/CommandDone.java @@ -0,0 +1,30 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class CommandDone extends CommandBase { + /** + * Creates done command constructor. + * + * @param command full command + */ + public CommandDone(String command) { + super(command); + } + + /** + * Executes done command. + * + * @param taskList user generate. + * @param ui show interactive information. + * @param storageTaskList info where to storage. + * @return if true, the program stops, otherwise it starts. + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + reply(taskList); + return false; + } +} \ No newline at end of file diff --git a/src/main/java/duke/parser/CommandEnums.java b/src/main/java/duke/parser/CommandEnums.java new file mode 100644 index 00000000..a19facd0 --- /dev/null +++ b/src/main/java/duke/parser/CommandEnums.java @@ -0,0 +1,34 @@ +package duke.parser; + +public enum CommandEnums { + LIST("list"), + DONE("done"), + DELETE("delete"), + BYE("bye"), + SAVE("save"), + TODO("todo"), + EVENT("event"), + DEADLINE("deadline"), + FIND("find"), + VIEW("view") + ; + + /** + * Creates Enum constructor + * + * @param name the keyword for the command + */ + CommandEnums(String name) { + this.name = name; + } + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/duke/parser/CommandError.java b/src/main/java/duke/parser/CommandError.java new file mode 100644 index 00000000..5887f947 --- /dev/null +++ b/src/main/java/duke/parser/CommandError.java @@ -0,0 +1,17 @@ +package duke.parser; + +import duke.exception.UnknownSyntaxException; + +public class CommandError extends CommandBase { + + /** + * Creates error command constructor. + * Used when unknown syntax is detected. + * + * @param command full command + * @throws UnknownSyntaxException throws unknown syntax if unable to identify + */ + public CommandError(String command) throws UnknownSyntaxException{ + throw new UnknownSyntaxException(command); + } +} diff --git a/src/main/java/duke/parser/CommandEvent.java b/src/main/java/duke/parser/CommandEvent.java new file mode 100644 index 00000000..a2caac8a --- /dev/null +++ b/src/main/java/duke/parser/CommandEvent.java @@ -0,0 +1,72 @@ +package duke.parser; + +import duke.exception.TimeManagementException; +import duke.exception.TimeParseException; +import duke.exception.UnknownSyntaxException; +import duke.parser.timeHelper.DateTimeParse; +import duke.storage.StorageTaskList; +import duke.task.Events; +import duke.task.Task; +import duke.task.TaskList; +import duke.ui.UI; + +import java.time.LocalDate; + +public class CommandEvent extends CommandBase { + + private DateTimeParse timeHelp = new DateTimeParse(); + + /** + * Creates event Command Constructor + * + */ + public CommandEvent(String command) { + super(command); + } + + + /** + * Executes event command. + * + * @param taskList user generate. + * @param ui show interactive information. + * @param storageTaskList info where to storage. + * @return if true, the program stops, otherwise it starts. + * @throws TimeManagementException time management exception if no datetime is given + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) throws TimeManagementException{ + boolean isSuccess = false; + try { + if (!CommandEnums.EVENT.getName().equals(super.keyword)){ + throw new UnknownSyntaxException(super.keyword); + } + String[] dt = super.detail.split("/at", 2); + String description = dt[0]; + String dateTime = dt[1].substring(1); + LocalDate date = timeHelp.dateParse(dateTime); + String[] dateTimeInformation = dateTime.split(" ", 2); + String timeRange = dateTimeInformation[1]; + String from = timeRange.split("-", 2)[0]; + String to = timeRange.split("-", 2)[1]; + Task task = new Events(description, date, timeHelp.timeParse(timeHelp.get24HrFormat(from)),timeHelp.timeParse(timeHelp.get24HrFormat(to))); + if(taskList.addTask(task)){ + isSuccess = true; + assert taskList.getListSize()>0:"There should at least have 1 task"; + } + } catch (IndexOutOfBoundsException e) { + throw new TimeManagementException(); + } + + if (isSuccess) { + reply(taskList); + } + + return false; + } + + + + + +} \ No newline at end of file diff --git a/src/main/java/duke/parser/CommandFind.java b/src/main/java/duke/parser/CommandFind.java new file mode 100644 index 00000000..9eaa84fc --- /dev/null +++ b/src/main/java/duke/parser/CommandFind.java @@ -0,0 +1,34 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class CommandFind extends CommandBase { + /** + * Creates find Command Constructor. + * + * @param command the full command. + */ + public CommandFind(String command) { + super(command); + } + + /** + * Executes done command. + * + * @param taskList the full task list for saving purpose. + * @param ui UI object. + * @param storageTaskList storage object. + * @return returns false as this command does not end the runtime + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + try{ + taskList.printFoundTaskList(super.detail); + } catch(Exception e){ + System.out.println(e.getMessage()); + } + return false; + } +} diff --git a/src/main/java/duke/parser/CommandList.java b/src/main/java/duke/parser/CommandList.java new file mode 100644 index 00000000..b0e7b452 --- /dev/null +++ b/src/main/java/duke/parser/CommandList.java @@ -0,0 +1,29 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class CommandList extends CommandBase { + /** + * Creates list Command Constructor + * + */ + public CommandList(String command) { + super(command); + } + + /** + * Executes list command + * + * @param taskList the full task list for saving purpose + * @param ui UI object + * @param storageTaskList storage object + * + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + taskList.printTaskList(); + return false; + } +} \ No newline at end of file diff --git a/src/main/java/duke/parser/CommandParser.java b/src/main/java/duke/parser/CommandParser.java new file mode 100644 index 00000000..ae4bc189 --- /dev/null +++ b/src/main/java/duke/parser/CommandParser.java @@ -0,0 +1,37 @@ +package duke.parser; + +public class CommandParser { + + /** + * Generates different CMD objects according to the input parameters + * @see CommandBase + */ + public static Command parse(String fullCommand) { + Command command = new Command(); + if (fullCommand.contains(CommandEnums.DONE.getName())) { + command.setCmd(new CommandDone(fullCommand)); + } else if (fullCommand.contains(CommandEnums.LIST.getName())) { + command.setCmd(new CommandList(fullCommand)); + } else if (fullCommand.contains(CommandEnums.DELETE.getName())) { + command.setCmd(new CommandDelete(fullCommand)); + } else if (fullCommand.contains(CommandEnums.BYE.getName())) { + command.setCmd(new CommandBye(fullCommand)); + } else if (fullCommand.contains(CommandEnums.SAVE.getName())) { + command.setCmd(new CommandSave(fullCommand)); + } else if (fullCommand.contains(CommandEnums.TODO.getName())) { + command.setCmd(new CommandTodo(fullCommand)); + } else if (fullCommand.contains(CommandEnums.EVENT.getName())) { + command.setCmd(new CommandEvent(fullCommand)); + } else if (fullCommand.contains(CommandEnums.DEADLINE.getName())) { + command.setCmd(new CommandDeadline(fullCommand)); + } else if(fullCommand.contains(CommandEnums.FIND.getName())) { + command.setCmd(new CommandFind(fullCommand)); + } else if(fullCommand.contains(CommandEnums.VIEW.getName())) { + command.setCmd(new CommandView(fullCommand)); + } else { + command.setCmd(new CommandError(fullCommand)); + } + + return command; + } +} diff --git a/src/main/java/duke/parser/CommandSave.java b/src/main/java/duke/parser/CommandSave.java new file mode 100644 index 00000000..cd3e651a --- /dev/null +++ b/src/main/java/duke/parser/CommandSave.java @@ -0,0 +1,29 @@ +package duke.parser; + +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + +public class CommandSave extends CommandBase { + /** + * Creates save Command Constructor + * + */ + public CommandSave(String command){ + super(command); + } + + /** + * Executes save command + * + * @param taskList the full task list for saving purpose + * @param ui UI object + * @param storageTaskList storage object + * + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + storageTaskList.save(taskList); + return false; + } +} diff --git a/src/main/java/duke/parser/CommandTodo.java b/src/main/java/duke/parser/CommandTodo.java new file mode 100644 index 00000000..2ee1056e --- /dev/null +++ b/src/main/java/duke/parser/CommandTodo.java @@ -0,0 +1,61 @@ +package duke.parser; + +import duke.exception.UnknownSyntaxException; +import duke.storage.StorageTaskList; +import duke.storage.StorageFixedDurationReference; +import duke.task.Task; +import duke.task.TaskList; +import duke.task.ToDos; +import duke.task.FixedDurationTaskList; +import duke.ui.UI; + +public class CommandTodo extends CommandBase { + private static StorageFixedDurationReference loadFixedDurationRecord; + private static FixedDurationTaskList fixedDurationTaskList; + /** + * Creates TO DO Command + * + */ + public CommandTodo(String command) { + super(command); + } + + /** + * Executes TO DO command + * + * @param taskList the full task list for saving purpose + * @param ui UI object + * @param storageTaskList storage object + * + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) { + boolean isSuccess = false; + try { + if (!CommandEnums.TODO.getName().equals(super.keyword)){ + throw new UnknownSyntaxException(super.keyword); + } + loadFixedDurationRecord = new StorageFixedDurationReference(); + fixedDurationTaskList = new FixedDurationTaskList(loadFixedDurationRecord.load()); + int duration = fixedDurationTaskList.findRecord(super.detail); + Task task; + if (duration > 0) { + task = new ToDos(super.detail, duration); + } else{ + task = new ToDos(super.detail); + } + if(taskList.addTask(task)){ + isSuccess = true; + assert taskList.getListSize()>0:"There should at least have 1 task"; + } + } catch (IndexOutOfBoundsException e) { + throw new UnknownSyntaxException(super.keyword); + } + + if (isSuccess) { + reply(taskList); + } + + return false; + } +} diff --git a/src/main/java/duke/parser/CommandView.java b/src/main/java/duke/parser/CommandView.java new file mode 100644 index 00000000..19ea3d7a --- /dev/null +++ b/src/main/java/duke/parser/CommandView.java @@ -0,0 +1,48 @@ +package duke.parser; + +import duke.exception.EmptyTaskListException; +import duke.exception.UnknownSyntaxException; +import duke.parser.timeHelper.DateTimeParse; +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; + + +import java.time.LocalDate; + +public class CommandView extends CommandBase{ + + private DateTimeParse timeHelp = new DateTimeParse(); + + /** + * Creates view schedule command constructor. + * + * @param command the full command. + */ + public CommandView(String command){super(command);} + + + /** + * Executes view schedule command + * + * @param taskList the full task list for sorting purpose. + * @param ui show interactive information. + * @param storageTaskList storage object. + * @return returns false as this command does not end the runtime + * @throws EmptyTaskListException when task list is empty no schedule to sort + */ + @Override + public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) throws EmptyTaskListException{ + try{ + if (!CommandEnums.VIEW.getName().equals(super.keyword)){ + throw new UnknownSyntaxException(super.keyword); + } + LocalDate scheduleDate = timeHelp.dateParse(super.detail); + taskList.printAsSchedule(scheduleDate); + } catch(EmptyTaskListException e){ + throw new EmptyTaskListException("Empty"); + } + return false; + } + +} diff --git a/src/main/java/duke/parser/timeHelper/DateTimeParse.java b/src/main/java/duke/parser/timeHelper/DateTimeParse.java new file mode 100644 index 00000000..35dae3d2 --- /dev/null +++ b/src/main/java/duke/parser/timeHelper/DateTimeParse.java @@ -0,0 +1,112 @@ +package duke.parser.timeHelper; + +import duke.exception.TimeParseException; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +public class DateTimeParse { + + static final int dateLength = 3; + + /** + * Returns parsed time in format {DD-MM-YYYY}. + * + * @param str - the string of datetime. + * @return - Date in its correct format. + * @throws TimeParseException thrown when time format is wrong + */ + public LocalDate dateParse(String str) throws TimeParseException{ + if (!str.contains("/")){ + throw new TimeParseException("Date Format YYYY/MM/DD"); + } + // gen yyyy,mm,dd ssss + String[] date = str.split("/", 3); + if (date.length < dateLength){ + throw new TimeParseException("Date Format YYYY/MM/DD"); + } + + // gen time + String[] time = date[2].split(" ", 2); + int year = Integer.parseInt(date[0]); + int month = Integer.parseInt(date[1]); + int dayOfMth = Integer.parseInt(time[0]); + + LocalDate localDate; + try { + localDate = LocalDate.of(year,month,dayOfMth); + } catch (DateTimeException e) { + throw new TimeParseException(e.getMessage()); + } + + return localDate; + } + + + /** + * Returns parsed time as format {DD-MM-YYYY}. + * + * @param str - the string of datetime. + * @return - Date in its correct format. + * @throws TimeParseException thrown when date format is wrong + */ + public LocalDateTime dateAndTimeParse(String str) throws TimeParseException{ + if (!str.contains("/")){ + throw new TimeParseException("Date Format YYYY/MM/DD"); + } + // gen yyyy,mm,dd ssss + String[] date = str.split("/", 3); + if (date.length < dateLength){ + throw new TimeParseException("Date Format YYYY/MM/DD"); + } + + // gen time + String[] time = date[2].split(" ", 2); + int year = Integer.parseInt(date[0]); + int month = Integer.parseInt(date[1]); + int dayOfMth = Integer.parseInt(time[0]); + int hour = get24HrFormat(time[1]); + + LocalDateTime localDateTime; + try { + localDateTime = LocalDateTime.of(year,month,dayOfMth,hour,0,0,0); + } catch (DateTimeException e) { + throw new TimeParseException(e.getMessage()); + } + + return localDateTime; + } + + /** + * Transforms time to 24hour format. + * + * @param t string such as [1AM] [10PM]. + * @return integer time such as 1, 22. + */ + public int get24HrFormat(String t){ + int timeInterval = 12; + int timeValue; + if(t.toUpperCase().contains("AM")){ + timeValue = Integer.parseInt(t.replace("AM", "").stripTrailing()); + } else if(t.toUpperCase().contains("PM")){ + timeValue = Integer.parseInt(t.replace("PM", "").stripTrailing()); + timeValue += timeInterval; + }else{ + throw new TimeParseException("Time Format 1AM/1PM"); + } + + return timeValue; + } + + /** + * Returns time in LocalTime format. + * + * @param t the integer time [1] [22] + * @return time in LocalTime [01:00:00] [22:00:00] + */ + public LocalTime timeParse(int t){ + return LocalTime.of(t,0,0); + } +} diff --git a/src/main/java/duke/storage/StorageFixedDurationReference.java b/src/main/java/duke/storage/StorageFixedDurationReference.java new file mode 100644 index 00000000..c8069bd3 --- /dev/null +++ b/src/main/java/duke/storage/StorageFixedDurationReference.java @@ -0,0 +1,88 @@ +package duke.storage; + +import duke.exception.DukeException; +import duke.task.FixedDurationTask; +import duke.task.FixedDurationTaskList; +import duke.ui.ReturnMessages; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +public class StorageFixedDurationReference { + + protected boolean isExist; + protected String fileName; + protected File file; + private static ReturnMessages returnMessage = new ReturnMessages(); + + + /** Creates Storage_Unscheduled object. */ + public StorageFixedDurationReference() { + this.file = new File(System.getProperty("user.dir") + "/fixedDurationTask.txt"); // create a File for the given file path + this.fileName = file.getName(); + } + + /** + * loads info from hard disk. + * + * @return task list from hard disk. + */ + public FixedDurationTaskList load() throws DukeException { + FixedDurationTaskList unscheduledRecords = new FixedDurationTaskList(); + assert file.exists():"The file should exist by now"; + if (file.exists()) { + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line; + while ((line = br.readLine()) != null) { + // process the line + unscheduledRecords.addTask(decodeStrToFixedDurationTask(line)); + } + } catch (IOException e) { + //fail to parse + throw new DukeException("file parse fail"); + } + } else { + try { + createFile(); + } catch (IOException e) { + //fail to create file + throw new DukeException("create file fail"); + } + } + return unscheduledRecords; + } + + + /** + * Creates File if not exist. + * + * @exception IOException throws a IO Exception if file exists. + * + */ + public void createFile() throws IOException { + try { + boolean create = file.createNewFile(); + } catch (IOException ioe) { + this.isExist = true; + System.out.println("File exists"); + } + this.isExist = true; + returnMessage.createSuccessFeedback(file.getName()); + } + + + /** + * Decodes the str to unscheduled task records with description and duration. + * + * @param str the full string per line. + * @return created task object. + */ + public FixedDurationTask decodeStrToFixedDurationTask(String str) { + String[] line = str.split(" \\| "); + FixedDurationTask unscheduledRecord; + unscheduledRecord = new FixedDurationTask(line[0], Integer.parseInt(line[1])); + return unscheduledRecord; + } +} diff --git a/src/main/java/duke/storage/StorageTaskList.java b/src/main/java/duke/storage/StorageTaskList.java new file mode 100644 index 00000000..c16aacd8 --- /dev/null +++ b/src/main/java/duke/storage/StorageTaskList.java @@ -0,0 +1,162 @@ +package duke.storage; + +import duke.exception.DukeException; +import duke.task.FixedDurationTaskList; +import duke.task.TaskList; +import duke.task.Task; +import duke.task.ToDos; +import duke.task.Events; +import duke.task.Deadline; +import duke.ui.ReturnMessages; + +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +public class StorageTaskList { + protected boolean isExist; + protected String fileName; + protected File file; + private static ReturnMessages returnMessage = new ReturnMessages(); + private static StorageFixedDurationReference loadFixedDurationRecord; + private static FixedDurationTaskList fixedDurationTaskList; + + /** + * Checks current file existence status. + * + * @return true or false. + */ + public boolean existence(){ + return isExist; + } + + /** + * Creates Storage object. + * + * @param fileName the file saving the information of task list + * + */ + public StorageTaskList(String fileName) { + this.fileName = fileName; + this.file = new File(System.getProperty("user.dir") + "/"+fileName); // create a File for the given file path + } + + /** + * Loads info from hard disk. + * + * @return task list from hard disk. + */ + public TaskList load() throws DukeException { + TaskList taskList = new TaskList(); + assert file.exists():"The file should exist by now"; + if (file.exists()) { + returnMessage.loadingFileFeedback(); + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line; + while ((line = br.readLine()) != null) { + // process the line + taskList.addTask(decodeStrToTask(line)); + } + } catch (IOException e) { + //fail to parse + throw new DukeException("file parse fail"); + } + } else { + try { + createFile(); + } catch (IOException e) { + //fail to create file + throw new DukeException("create file fail"); + } + } + returnMessage.loadSuccessFeedback(); + return taskList; + } + + /** + * Creates File if not exist. + * + * @exception IOException throws a IO Exception if file exists. + * + */ + public void createFile() throws IOException { + try { + boolean create = file.createNewFile(); + } catch (IOException ioe) { + this.isExist = true; + System.out.println("File exists"); + } + this.isExist = true; + returnMessage.createSuccessFeedback(file.getName()); + } + + /** + * Saves task list to hard disk. + * + * @param taskList - data to save. + */ + public void save(TaskList taskList) { + assert this.isExist:true; + FileWriter myWriter; + try { + myWriter = new FileWriter(file.getAbsoluteFile(), false); + FileWriter finalMyWriter = myWriter; + taskList.getTaskList().forEach((task) -> { + try { + finalMyWriter.write(task.encodeTask() + "\n"); + } catch (IOException e) { + // + throw new DukeException(e.getMessage()); + } + }); + myWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + throw new DukeException(e.getMessage()); + } + returnMessage.saveSuccessFeedback(); + } + + /** + * Decodes the str to its individual task format. + * + * @param str the full string per line. + * @return created task object. + */ + public Task decodeStrToTask(String str) { + String[] lines = str.split(" \\| "); + Task task = null; + switch (lines[0]) { + case "T": + loadFixedDurationRecord = new StorageFixedDurationReference(); + fixedDurationTaskList = new FixedDurationTaskList(loadFixedDurationRecord.load()); + int duration = fixedDurationTaskList.findRecord(lines[2]); + if (duration > 0) { + task = new ToDos(lines[2], duration); + } else{ + task = new ToDos(lines[2]); + } + break; + case "D": + LocalDate date = LocalDate.parse(lines[3]); + LocalTime time = LocalTime.parse(lines[4]); + task = new Deadline(lines[2], LocalDateTime.of(date,time)); + break; + case "E": + task = new Events(lines[2], LocalDate.parse(lines[3]), LocalTime.parse(lines[4]), LocalTime.parse(lines[5])); + break; + } + if (Task.DONE.equals(lines[1])) { + if (task != null) { + task.setDone(); + } + } + return task; + } +} diff --git a/src/main/java/duke/storage/duke.txt b/src/main/java/duke/storage/duke.txt new file mode 100644 index 00000000..8a409a9d --- /dev/null +++ b/src/main/java/duke/storage/duke.txt @@ -0,0 +1,15 @@ +T | 0 | read book | 1 +D | 0 | return book | 2021-10-24 | 22:00 +D | 0 | return book | 2021-10-24 | 22:00 +E | 0 | project meeting | 2021-10-24 | 14:00 | 16:00 +D | 0 | return book | 2021-11-05 | 22:00 +E | 0 | project meeting | 2022-07-30 | 14:00 | 16:00 +E | 0 | new year | 2022-02-02 | 00:00 | 12:00 +D | 0 | return book | 2020-10-29 | 03:00 +D | 0 | return book | 2021-12-25 | 16:00 +T | 0 | eat | 0 +E | 0 | Finish Homework | 2021-12-25 | 16:00 | 18:00 +E | 0 | new year | 2022-02-02 | 00:00 | 12:00 +T | 1 | read book | 1 +T | 1 | study book | 0 +E | 0 | meeting | 2021-12-25 | 00:00 | 15:00 diff --git a/src/main/java/duke/storage/fixedDurationTask.txt b/src/main/java/duke/storage/fixedDurationTask.txt new file mode 100644 index 00000000..71285f2f --- /dev/null +++ b/src/main/java/duke/storage/fixedDurationTask.txt @@ -0,0 +1,4 @@ +read sales report | 2 +read book | 1 +do homework | 4 +submit claims | 1 diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java new file mode 100644 index 00000000..83485f46 --- /dev/null +++ b/src/main/java/duke/task/Deadline.java @@ -0,0 +1,43 @@ +package duke.task; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +public class Deadline extends Task { + + protected LocalDateTime by; + protected LocalDate date; + + /** + * Creates Deadline task. + * + * @param description - the task for the deadline. + * @param by - the deadline's datetime. + */ + public Deadline(String description, LocalDateTime by) { + super(description, "deadline", by.toLocalDate(), by.toLocalTime()); + this.by = by; + this.date = by.toLocalDate(); + } + + /** Prints task by its own style. */ + @Override + public String toString() { + return "[D]" + super.toString() + "(by: " + by.toLocalDate().toString() + "["+ by.toLocalDate().getDayOfWeek() +"] "+ by.toLocalTime().toString()+")"; + } + + /** Encodes function for storage within text file. */ + @Override + public String encodeTask() { + return "D" + super.encodeTask() + " | " + by.toLocalDate().toString() + " | " + by.toLocalTime().toString(); + } + + public LocalDate getDate(){ + return this.date; + } + + public LocalTime getTime(){ + return this.by.toLocalTime(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/Events.java b/src/main/java/duke/task/Events.java new file mode 100644 index 00000000..31a52c42 --- /dev/null +++ b/src/main/java/duke/task/Events.java @@ -0,0 +1,43 @@ +package duke.task; + +import java.time.LocalDate; +import java.time.LocalTime; + +public class Events extends Task { + protected LocalDate date; + protected LocalTime start; + protected LocalTime end; + + /** + * Creates Event task. + * + * @param description - Description of Event. + * @param start - Date/Time event is held. + * @param end - Date/Time event ends. + * @param date - the date event is held. + */ + public Events(String description, LocalDate date, LocalTime start, LocalTime end) { + super(description, "event", date, start); + this.date = date; + this.start = start; + this.end = end; + } + /** Prints task by its own style. */ + @Override + public String toString() { + return "[E]" + super.toString() + " (on:" + date.toString() + "[" + date.getDayOfWeek().toString() + "] from:" + start.toString() +" to:" + end.toString() +")"; + } + /** Encodes function for storage within text file */ + @Override + public String encodeTask() { + return "E" + super.encodeTask() + " | " + date.toString() + " | " + start.toString() + " | " + end.toString(); + } + + public LocalDate getDate(){ + return this.date; + } + + public LocalTime getTime(){ + return this.start; + } +} diff --git a/src/main/java/duke/task/FixedDurationTask.java b/src/main/java/duke/task/FixedDurationTask.java new file mode 100644 index 00000000..7ced5f7e --- /dev/null +++ b/src/main/java/duke/task/FixedDurationTask.java @@ -0,0 +1,26 @@ +package duke.task; + +public class FixedDurationTask { + private String description; + private int duration; + + /** + * Creates FixedDuration Task. + * + * @param desc its fixed description. + * @param duration its fixed duration. + */ + public FixedDurationTask(String desc, int duration){ + this.description = desc; + this.duration = duration; + } + + public String getDesc(){ + return this.description; + } + + public int getDuration(){ + return this.duration; + } + +} diff --git a/src/main/java/duke/task/FixedDurationTaskList.java b/src/main/java/duke/task/FixedDurationTaskList.java new file mode 100644 index 00000000..a18f8bc1 --- /dev/null +++ b/src/main/java/duke/task/FixedDurationTaskList.java @@ -0,0 +1,60 @@ +package duke.task; + +import java.util.ArrayList; + +public class FixedDurationTaskList { + + protected int listSize; + private ArrayList unscheduleTaskList; + + + /** Creates Fixed Duration Task List */ + public FixedDurationTaskList() { + unscheduleTaskList = new ArrayList<>(); + } + + /** + * Creates Fixed Duration Task List with records within. + * + * @param load - the task list that already contained task. + */ + public FixedDurationTaskList(FixedDurationTaskList load) { + this.listSize = load.listSize; + this.unscheduleTaskList = load.unscheduleTaskList; + } + + /** + * Gets the list size. + * + * @return - list size in integer. + */ + public int getListSize(){ + return this.listSize; + } + + + /** + * Adds an fixed duration task record to list. + * + * @param task - the full task information. + */ + public void addTask(FixedDurationTask task){ + this.unscheduleTaskList.add(task); + this.listSize++; + } + + /** + * Finds if a fixed duration task exists in record. + * + * @param description find by description. + * @return the task ID if exists. + */ + public int findRecord(String description){ + for(FixedDurationTask ut : unscheduleTaskList){ + if(description.equals(ut.getDesc())){ + return ut.getDuration(); + } + } + return 0; + } +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java new file mode 100644 index 00000000..295b69f2 --- /dev/null +++ b/src/main/java/duke/task/Task.java @@ -0,0 +1,95 @@ +package duke.task; + +import java.time.LocalDate; +import java.time.LocalTime; + +public class Task { + protected String description; + protected boolean isDone; + protected String taskType; + protected LocalDate date; + protected LocalTime time; + + public static final String DONE = "1"; + public static final String UNDONE = "0"; + + /** + * Creates Task base. + * + * @param description - the description string. + */ + public Task(String description, String taskType, LocalDate date, LocalTime time) { + this.description = description; + this.isDone = false; + this.taskType = taskType; + this.date = date; + this.time = time; + } + + /** + * Returns task's current status. + * + * @return - done or not done. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + /** + * Returns task's current status for code usage. + * + * @return - 0 or 1. + */ + public String getStatusCode() { + return (isDone ? DONE : UNDONE); // mark done task with 1 + } + + /** + * Returns the full description of each task. + * + * @return - returns task description. + */ + public String getTaskInfo(){ + return description; + } + + public String getTaskType(){ + return taskType; + } + + /** Gets the task done condition. */ + public boolean isDone(){ + return isDone; + } + + /** Sets the task to Done. */ + public void setDone(){ + isDone = true; + } + + /** + * Prints task on its own syntax. + * + * @return tasks [] TASK. + */ + public String toString() { + return "["+getStatusIcon()+"] " + description; + } + + /** + * Encodes task for storage. + * + * @return | X | TASK. + */ + public String encodeTask() { + return " | " + getStatusCode() + " | " + description; + } + + public LocalDate getDate(){ + return this.date; + } + + public LocalTime getTime(){ + return this.time; + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/TaskEnums.java b/src/main/java/duke/task/TaskEnums.java new file mode 100644 index 00000000..d4ab162f --- /dev/null +++ b/src/main/java/duke/task/TaskEnums.java @@ -0,0 +1,8 @@ +package duke.task; + +/** Enumerate for Task */ +public enum TaskEnums { + TODO, + DEADLINE, + EVENT, +} diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java new file mode 100644 index 00000000..bc2a12ae --- /dev/null +++ b/src/main/java/duke/task/TaskList.java @@ -0,0 +1,158 @@ +package duke.task; + +import duke.exception.EmptyTaskListException; +import duke.exception.TaskNotFoundException; +import duke.ui.ReturnMessages; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Comparator; + +public class TaskList { + protected int listSize; + private ArrayList taskList; + private static ReturnMessages printer = new ReturnMessages(); + + + /** Creates task list. */ + public TaskList() {taskList = new ArrayList<>();} + + /** + * Creates Task list with tasks within. + * + * @param load - the task list that already contained task. + */ + public TaskList(TaskList load) { + this.listSize = load.listSize; + this.taskList = load.taskList; + } + + /** + * Deletes a specific task uniquely identified via taskID. + * + * @param taskID - the unique identifier for each task. + * @throws TaskNotFoundException - when a task is not found. + * @throws EmptyTaskListException - when the task list is empty. + */ + public void deleteTask(int taskID) throws TaskNotFoundException, EmptyTaskListException { + int taskPosition = taskID -1; + if(taskPosition > this.listSize || taskPosition < 0){ + throw new TaskNotFoundException("task not found"); + } + System.out.println(" Noted. I've removed this task: " ); + System.out.println(" " + taskList.get(taskPosition).toString()); + this.taskList.remove(taskPosition); + this.listSize--; + if(this.listSize == 0){ + throw new EmptyTaskListException("empty task"); + } + System.out.println(" Now you have " + this.listSize + " tasks in the list."); + printer.separator(); + } + + /** + * Adds a task to task list. + * + * @param task - the full task information. + */ + public boolean addTask(Task task){ + if(this.taskList.add(task)){ + this.listSize++; + return true; + } + return false; + } + + /** + * Gets a task via its task ID. + * + * @param ID - the unique identifier for a task. + * @return - returns the task. + */ + public Task getTask(int ID){ + return taskList.get(ID); + } + + /** + * Gets the last task added. + * + * @return - return the task. + */ + public Task getLastTask(){ + return taskList.get(listSize-1); + } + + /** + * Gets the list size. + * + * @return - list size in integer. + */ + public int getListSize(){ + return this.listSize; + } + + + + /** + * Prints the tasks within the task list. + * + * @throws EmptyTaskListException - thrown if task list is empty. + */ + public void printTaskList() throws EmptyTaskListException { + if(this.listSize == 0){ + throw new EmptyTaskListException("empty task"); + } + printer.printFullTaskList(taskList); + } + + /** + * Getter for getting the task list. + * + * @return - returns entire task list. + */ + public ArrayList getTaskList() { + return taskList; + } + + + /** + * Finds tasks containing specific keyword. + * + * @param keyword - the keyword to find. + * @throws EmptyTaskListException - thrown if task list is empty. + */ + public void printFoundTaskList(String keyword) throws EmptyTaskListException { + + if(this.listSize == 0){ + throw new EmptyTaskListException("empty task"); + } + printer.taskFoundFeedback(keyword, taskList); + } + + /** + * prints schedule order by date + * + * @param dateToPrint the date that the schedule is needed + * @throws EmptyTaskListException if task list is empty, throws exception on empty task list + */ + public void printAsSchedule(LocalDate dateToPrint) throws EmptyTaskListException{ + if(this.listSize == 0){ + throw new EmptyTaskListException("There's nothing in task list yet."); + } + ArrayList tempTaskList = new ArrayList<>(); + for(Task t : taskList){ + if(!t.getTaskType().equals("todo") && t.getDate().equals(dateToPrint)){ + tempTaskList.add(t); + } + } + sortByTime(tempTaskList); + printer.taskSchedulingFeedback(dateToPrint, tempTaskList); + } + + // Comparison done using compareTo function + protected static void sortByTime(ArrayList list) + { + list.sort(Comparator.comparing(Task::getTime)); + } + +} diff --git a/src/main/java/duke/task/ToDos.java b/src/main/java/duke/task/ToDos.java new file mode 100644 index 00000000..64484a92 --- /dev/null +++ b/src/main/java/duke/task/ToDos.java @@ -0,0 +1,47 @@ +package duke.task; + +public class ToDos extends Task { + protected int duration; + + /** + * Creates To Do task + * + * @param description - Description of To Do task. + */ + public ToDos(String description) { + this(description,0); + + } + /** + * Creates To Do task. + * + * @param description - Description of To Do task. + * @param duration - unscheduled fixed duration. + */ + public ToDos(String description, int duration) { + super(description, "todo", null, null); + this.duration = duration; + } + public int getDuration(){ + return this.duration; + } + + public void setDuration(int duration){ + this.duration = duration; + } + + /** Prints task by its own style. */ + @Override + public String toString() { + if(this.duration>0){ + return "[T]" + super.toString()+ " (requires: " + duration + " Hour)"; + } + return "[T]" + super.toString(); + } + + /** Encodes function for storage within text file. */ + @Override + public String encodeTask() { + return "T" + super.encodeTask() + " | " + duration; + } +} diff --git a/src/main/java/duke/ui/ReturnMessages.java b/src/main/java/duke/ui/ReturnMessages.java new file mode 100644 index 00000000..32d76266 --- /dev/null +++ b/src/main/java/duke/ui/ReturnMessages.java @@ -0,0 +1,227 @@ +package duke.ui; + +import duke.exception.TaskNotFoundException; +import duke.task.Task; + +import java.time.LocalDate; +import java.util.ArrayList; + + +/** Handles message output. */ +public class ReturnMessages { + public void separator(){ + System.out.println(" ____________________________________________________________"); + } + + /** Feedbacks when marking a task done. */ + public void taskDoneFeedback(){ + separator(); + System.out.println(" Nice! I've marked this task as done:"); + } + + /** Feedbacks when a task is already done. */ + public void taskAlreadyDoneFeedback(){ + separator(); + System.out.println(" This task is already done."); + } + + + /** Feedbacks when adding a task. */ + public void taskAddFeedback(){ + separator(); + System.out.println(" Got it. I've added this task:"); + } + + /** Feedbacks on program startup. */ + public void welcomeFeedback(){ + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println("Hello from\n" + logo); + separator(); + System.out.println(" Hello! I'm Duke"); + System.out.println(" Here are my functionality...."); + System.out.println(" Check Existing Tasks: list"); + System.out.println(" Mark a Task done: done {taskID}"); + System.out.println(" Delete a Task: delete {taskID}"); + System.out.println(" Find a Task: find {keyword}"); + System.out.println(" View Schedule: view {date by YYYY/MM/DD}"); + System.out.println(" Save Current State: save"); + System.out.println(" Add a Todo Task: todo {action}"); + System.out.println(" Add a Event Task: event xxxx /at {date by YYYY/MM/DD} {startTime}AM/PM-{endTime}AM/PM"); + System.out.println(" Add a Deadline Task: deadline XXXX /by {date by YYYY/MM/DD} {Time}AM/PM"); + System.out.println(" End the program: bye"); + separator(); + } + + /** Feedbacks on program exit. */ + public void exitFeedback(){ + separator(); + System.out.println(" Bye. Hope to see you again soon!"); + separator(); + } + + /** Feedbacks when loading file. */ + public void loadingFileFeedback(){ + separator(); + System.out.println(" Loading File..."); + separator(); + } + + /** Feedbacks on file load success. */ + public void loadSuccessFeedback(){ + separator(); + System.out.println(" File Loaded Successfully, use command 'list' to view..."); + separator(); + } + + /** Feedbacks on file save. */ + public void saveSuccessFeedback(){ + separator(); + System.out.println(" Successfully wrote to the file."); + separator(); + } + + /** Feedbacks on file create. */ + public void createSuccessFeedback(String name){ + separator(); + System.out.println("File created: " + name); + separator(); + } + + /** + * Returns full task list with numbering. + * + * @param list the full task list. + */ + public void printFullTaskList(ArrayList list){ + separator(); + int numbering = 1; + System.out.println(" Here are the tasks in your list:"); + for(Task t : list){ + System.out.println(" "+numbering+"."+t.toString()); + numbering++; + } + separator(); + } + + public void taskSchedulingFeedback(LocalDate datePrint, ArrayList list){ + separator(); + System.out.println(" Here are the tasks in your list scheduled for: " +datePrint.toString() + ", "+datePrint.getDayOfWeek()); + for(Task t : list){ + System.out.println(" "+t.toString()); + } + separator(); + } + + + /** + * Returns task found with keyword with its correct numbering. + * + * @param key keyword. + * @param list full task list. + */ + public void taskFoundFeedback(String key, ArrayList list){ + assert !list.isEmpty():"Should be caught by emptyTaskListException"; + ArrayList tempList = new ArrayList<>(); + for(Task t : list){ + if(t.getTaskInfo().contains(key)){ + tempList.add(t); + } + } + if(tempList.isEmpty()){ + throw new TaskNotFoundException("No task found with keyword ["+key+"]."); + }else{ + separator(); + int numbering = 1; + System.out.println(" Here are the matching tasks in your list:"); + for(Task t : tempList){ + System.out.println(" "+numbering+"."+t); + numbering++; + } + separator(); + } + } + + /** + * Feedbacks message on emptyDescription Exception thrown. + * + * @param taskType The type of task (To Do, Event, Deadline). + */ + public void exception_feedback_emptyDescription(String taskType){ + separator(); + System.out.printf(" OOPS!!! The description of a %s cannot be empty.\n", taskType); + separator(); + } + + /** Feedbacks message on emptyTaskList Exception thrown. */ + public void exception_feedback_emptyTaskList(){ + separator(); + System.out.println(" OOPS!!! The list is empty ^_^"); + separator(); + } + + /** + * Feedbacks message on unknownSyntax Exception thrown. + * + * @param message - user input. + */ + public void exception_feedback_unknownSyntax(String message){ + separator(); + System.out.printf(" OOPS!!! I'm sorry, but I don't know what [%s] means :-(\n", message); + separator(); + } + + /** + * Feedbacks message on task not found Exception thrown. + * + * @param message - the task description. + */ + public void exception_feedback_taskNotFound(String message){ + separator(); + System.out.printf(" OOPS!!! Task was not found [%s]\n", message); + separator(); + } + + /** Feedbacks message on noTimeConcept Exception thrown. */ + public void exception_feedback_noTimeConcept(){ + separator(); + System.out.println(" HEY!!! Please give a due date for deadlines and events or the syntax could be wrong"); + separator(); + } + + /** Feedbacks message on Time Parse Exception thrown. */ + public void exception_feedback_timeParse(String message){ + separator(); + System.out.printf(" There seems to have problem with your time format [%s]\n", message); + separator(); + } + + /** Feedbacks message on Saving Exception thrown. */ + public void exception_feedback_cantSave(){ + separator(); + System.out.println(" OOPS!!! Exception caught while saving >_<|||"); + separator(); + } + + /** Feedbacks message on Loading Exception thrown. */ + public void exception_feedback_loadingError(){ + separator(); + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println(" OOPS!!! Something went wrong while loading"); + separator(); + } + + /** Feedbacks message on an Unknown Exception thrown. */ + public void exception_feedback_unknownError(){ + separator(); + System.out.println(" Sorry, An unknown error occurred"); + separator(); + } +} diff --git a/src/main/java/duke/ui/UI.java b/src/main/java/duke/ui/UI.java new file mode 100644 index 00000000..ad6a60c1 --- /dev/null +++ b/src/main/java/duke/ui/UI.java @@ -0,0 +1,78 @@ +package duke.ui; + + + + +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.exception.EmptyTaskListException; +import duke.exception.SavingException; +import duke.exception.TaskNotFoundException; +import duke.exception.TimeManagementException; +import duke.exception.UnknownSyntaxException; +import duke.exception.TimeParseException; + +import java.util.Scanner; + +public class UI{ + + private static ReturnMessages returnMessage = new ReturnMessages(); + + private Scanner in; + + public void showWelcome(){ + returnMessage.welcomeFeedback(); + } + + public void showLoadingError(){ + returnMessage.exception_feedback_loadingError(); + } + + /** + * Reads cmd user input. + * + * @return - command read from user Input. + */ + public String readCommand() { + boolean end = false; + String command; + in = new Scanner(System.in); + command = in.nextLine(); + return command; + } + + public void showLine() { + returnMessage.separator(); + } + + + /** + * Returns the error msg will output by this. + * All exceptions inherit DukeException. + * + * @param e the exception object. + */ + public void showError(DukeException e) { + if (e instanceof EmptyDescriptionException) { + returnMessage.exception_feedback_emptyDescription(e.getMessage()); + } else if (e instanceof EmptyTaskListException) { + returnMessage.exception_feedback_emptyTaskList(); + } else if (e instanceof SavingException) { + returnMessage.exception_feedback_cantSave(); + } else if (e instanceof TaskNotFoundException) { + returnMessage.exception_feedback_taskNotFound(e.getMessage()); + } else if (e instanceof TimeManagementException) { + returnMessage.exception_feedback_noTimeConcept(); + } else if (e instanceof UnknownSyntaxException){ + returnMessage.exception_feedback_unknownSyntax(e.getMessage()); + } else if (e instanceof TimeParseException){ + returnMessage.exception_feedback_timeParse(e.getMessage()); + } else { + returnMessage.exception_feedback_unknownError(); + } + } + + public void showExit() { + returnMessage.exitFeedback(); + } +} diff --git a/src/test/java/duke/parsertest/CommandByeTest.java b/src/test/java/duke/parsertest/CommandByeTest.java new file mode 100644 index 00000000..074c6dfa --- /dev/null +++ b/src/test/java/duke/parsertest/CommandByeTest.java @@ -0,0 +1,44 @@ +package duke.parsertest; + +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.ui.UI; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CommandByeTest { + private static Command c; + private static StorageTaskList storageTaskList; + private static UI ui; + private static TaskList taskList; + private static String sampleCmd = "bye"; + + @BeforeAll + static void init(){ + ui = new UI(); + storageTaskList = new StorageTaskList("/byeTest.txt"); + taskList = new TaskList(); + } + + @Test + void byeCommand_byeTask_successAndTrue(){ + c = CommandParser.parse(sampleCmd); + c.execute(taskList, ui, storageTaskList); + assertTrue(c.isExit()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/byeTest.txt"); // create a File for the given file path + assertTrue(cleanUP.delete()); + } +} diff --git a/src/test/java/duke/parsertest/CommandDeadlineTest.java b/src/test/java/duke/parsertest/CommandDeadlineTest.java new file mode 100644 index 00000000..22fb6538 --- /dev/null +++ b/src/test/java/duke/parsertest/CommandDeadlineTest.java @@ -0,0 +1,52 @@ +package duke.parsertest; + +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.Deadline; +import duke.task.TaskList; +import duke.ui.UI; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CommandDeadlineTest { + + private static Command c; + private static StorageTaskList storageTaskList; + private static UI ui; + private static TaskList taskList; + private static String sampleCmd = "deadline submit abc/by 2021/12/25 11PM"; + Deadline deadline = new Deadline("submit abc", LocalDateTime.of(2021,12,25,23,0,0)); + + @BeforeAll + static void init(){ + ui = new UI(); + storageTaskList = new StorageTaskList("/deadlineTest.txt"); + taskList = new TaskList(); + } + + @Test + void deadlineCommand_deadlineTask_successAndFalse(){ + c = CommandParser.parse(sampleCmd); + c.execute(taskList, ui, storageTaskList); + assertEquals(deadline.toString(), taskList.getLastTask().toString()); + assertFalse(c.isExit()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/deadlineTest.txt"); + if(cleanUP.exists()){ + assertTrue(cleanUP.delete()); + } + } +} diff --git a/src/test/java/duke/parsertest/CommandDeleteTest.java b/src/test/java/duke/parsertest/CommandDeleteTest.java new file mode 100644 index 00000000..ac32e665 --- /dev/null +++ b/src/test/java/duke/parsertest/CommandDeleteTest.java @@ -0,0 +1,58 @@ +package duke.parsertest; + +import duke.exception.EmptyTaskListException; +import duke.exception.TimeParseException; +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.Deadline; +import duke.task.TaskList; +import duke.task.ToDos; +import duke.ui.UI; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CommandDeleteTest { + + private static Command c; + private static StorageTaskList storageTaskList; + private static UI ui; + private static TaskList taskList; + private static String sampleCmd = "delete 1"; + @BeforeAll + static void init(){ + ui = new UI(); + storageTaskList = new StorageTaskList("/deleteTest.txt"); + taskList = new TaskList(); + ToDos sampleData = new ToDos("sleep"); + taskList.addTask(sampleData); + } + + @Test + void deleteCommand_deleteTask_successAndFalse(){ + c = CommandParser.parse(sampleCmd); + EmptyTaskListException exception = assertThrows(EmptyTaskListException.class, () -> { + c.execute(taskList, ui, storageTaskList); + assertEquals(0, taskList.getListSize()); + }); + String errorMsg = exception.getMessage(); + assertEquals("empty task", errorMsg); + assertFalse(c.isExit()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/deleteTest.txt"); + if(cleanUP.exists()){ + assertTrue(cleanUP.delete()); + } + } +} diff --git a/src/test/java/duke/parsertest/CommandDoneTest.java b/src/test/java/duke/parsertest/CommandDoneTest.java new file mode 100644 index 00000000..15ed3f0a --- /dev/null +++ b/src/test/java/duke/parsertest/CommandDoneTest.java @@ -0,0 +1,53 @@ +package duke.parsertest; + +import duke.exception.EmptyTaskListException; +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.task.ToDos; +import duke.ui.UI; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CommandDoneTest { + + private static Command c; + private static StorageTaskList storageTaskList; + private static UI ui; + private static TaskList taskList; + private static String sampleCmd = "done 1"; + @BeforeAll + static void init(){ + ui = new UI(); + storageTaskList = new StorageTaskList("/doneTest.txt"); + taskList = new TaskList(); + ToDos sampleData = new ToDos("sleep"); + taskList.addTask(sampleData); + } + + @Test + void doneCommand_doneTask_successAndFalse(){ + c = CommandParser.parse(sampleCmd); + c.execute(taskList, ui, storageTaskList); + assertTrue(taskList.getTask(0).isDone()); + assertFalse(c.isExit()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/doneTest.txt"); + if(cleanUP.exists()){ + assertTrue(cleanUP.delete()); + } + } +} diff --git a/src/test/java/duke/parsertest/CommandEventTest.java b/src/test/java/duke/parsertest/CommandEventTest.java new file mode 100644 index 00000000..1e37f219 --- /dev/null +++ b/src/test/java/duke/parsertest/CommandEventTest.java @@ -0,0 +1,53 @@ +package duke.parsertest; + +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.Events; +import duke.task.TaskList; +import duke.ui.UI; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.time.LocalDate; +import java.time.LocalTime; + +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CommandEventTest { + + private static Command c; + private static StorageTaskList storageTaskList; + private static UI ui; + private static TaskList taskList; + private static String sampleCmd = "event project meeting/at 2021/12/25 11AM-2PM"; + Events event = new Events("project meeting", LocalDate.of(2021,12,25), LocalTime.of(11,0), LocalTime.of(14,0)); + + @BeforeAll + static void init(){ + ui = new UI(); + storageTaskList = new StorageTaskList("/eventTest.txt"); + taskList = new TaskList(); + } + + @Test + void eventCommand_eventTask_successAndFalse(){ + c = CommandParser.parse(sampleCmd); + c.execute(taskList, ui, storageTaskList); + assertEquals(event.toString(), taskList.getLastTask().toString()); + assertFalse(c.isExit()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/eventTest.txt"); + if(cleanUP.exists()){ + assertTrue(cleanUP.delete()); + } + } +} diff --git a/src/test/java/duke/parsertest/CommandTodoTest.java b/src/test/java/duke/parsertest/CommandTodoTest.java new file mode 100644 index 00000000..01439cfe --- /dev/null +++ b/src/test/java/duke/parsertest/CommandTodoTest.java @@ -0,0 +1,51 @@ +package duke.parsertest; + +import duke.parser.Command; +import duke.parser.CommandParser; +import duke.storage.StorageTaskList; +import duke.task.TaskList; +import duke.task.ToDos; +import duke.ui.UI; + +import java.io.File; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; + +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CommandTodoTest { + + private static Command c; + private static StorageTaskList storageTaskList; + private static UI ui; + private static TaskList taskList; + private static String sampleCmd = "todo eat"; + ToDos todo = new ToDos("eat", 0); //since its testing command with the fixed duration database. assume it does not exist. + + @BeforeAll + static void init(){ + ui = new UI(); + storageTaskList = new StorageTaskList("/todoTest.txt"); + taskList = new TaskList(); + } + + @Test + void todoCommand_todoTask_successAndFalse(){ + c = CommandParser.parse(sampleCmd); + c.execute(taskList, ui, storageTaskList); + assertEquals(todo.toString(), taskList.getLastTask().toString()); + assertFalse(c.isExit()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/todoTest.txt"); + if(cleanUP.exists()){ + assertTrue(cleanUP.delete()); + } + } +} diff --git a/src/test/java/duke/parsertest/DateTimeParseTest.java b/src/test/java/duke/parsertest/DateTimeParseTest.java new file mode 100644 index 00000000..d408f010 --- /dev/null +++ b/src/test/java/duke/parsertest/DateTimeParseTest.java @@ -0,0 +1,66 @@ +package duke.parsertest; + +import duke.exception.TimeParseException; +import duke.parser.timeHelper.DateTimeParse; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import java.time.LocalDate; +import java.time.LocalTime; + +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class DateTimeParseTest { + private static final String wrongDate = "20211225"; + private static final String wrongDT = "20211225 10PM"; + private static final String rDwT = "2021/12/25 10"; + private static final String correctDate = "2021/12/25"; + private static DateTimeParse timeObject; + + @BeforeAll + static void init(){ + timeObject = new DateTimeParse(); + } + + @Test + void dateParse_correctFormattedDate_success(){ + LocalDate sample = LocalDate.of(2021,12,25); + assertEquals(sample, timeObject.dateParse(correctDate)); + } + + @Test + void timeParse_integerTimeToConvert_success(){ + LocalTime sample = LocalTime.of(10,0,0); + assertEquals(sample, timeObject.timeParse(10)); + } + + + @Test + void dateParse_wrongFormattedDate_exceptionThrown() { + TimeParseException exception = assertThrows(TimeParseException.class, () -> { + timeObject.dateParse(wrongDate); + }); + String errorMsg = exception.getMessage(); + assertEquals("Date Format YYYY/MM/DD", errorMsg); + } + + @Test + void dateTimeParse_wrongFormattedDateTime_exceptionThrown() { + TimeParseException exception = assertThrows(TimeParseException.class, () -> { + timeObject.dateAndTimeParse(wrongDT); + }); + String errorMsg = exception.getMessage(); + assertEquals("Date Format YYYY/MM/DD", errorMsg); + } + + @Test + void dateTimeParse_wrongFormattedTime_exceptionThrown() { + TimeParseException exception1 = assertThrows(TimeParseException.class, () -> { + timeObject.dateAndTimeParse(rDwT); + }); + String errorMsg1 = exception1.getMessage(); + assertEquals("Time Format 1AM/1PM", errorMsg1); + } +} diff --git a/src/test/java/duke/storagetest/StorageTaskListTest.java b/src/test/java/duke/storagetest/StorageTaskListTest.java new file mode 100644 index 00000000..02e706e9 --- /dev/null +++ b/src/test/java/duke/storagetest/StorageTaskListTest.java @@ -0,0 +1,70 @@ +package duke.storagetest; + +import duke.storage.StorageTaskList; +import duke.task.Deadline; +import duke.task.Events; +import duke.task.TaskList; +import duke.task.ToDos; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Order; +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class StorageTaskListTest { + private static TaskList tasks; + private static ToDos toDos; + private static Deadline deadline; + private static Events event; + private static StorageTaskList store; + + @BeforeAll + static void init(){ + LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0); + tasks = new TaskList(); + toDos = new ToDos("eat"); + deadline = new Deadline("return book", sample); + event = new Events("Finish Homework",sample.toLocalDate(),sample.toLocalTime(),sample.toLocalTime().plusHours(2)); + tasks.addTask(toDos); + assert tasks.getListSize()==1:"There should exist 1 task"; + tasks.addTask(deadline); + assert tasks.getListSize()==2:"There should exist 2 task"; + tasks.addTask(event); + assert tasks.getListSize()==3:"There should exist 3 task"; + store = new StorageTaskList("Testing.txt"); + } + + @Test + @Order(1) + public void fileNotCreated_checkExistenceFunction_false(){ + assertFalse(store.existence()); + } + + @Test + @Order(2) + public void fileCreated_checkExistenceFunction_true() throws IOException { + store.createFile(); + store.save(tasks); + assertTrue(store.existence()); + } + + @Test + @Order(3) + public void checkFileLoadStatus_anotherSameFile_true(){ + StorageTaskList store2 = new StorageTaskList("Testing.txt"); + assertEquals(tasks.getLastTask().toString(), store2.load().getLastTask().toString()); + } + + @AfterAll + static void wrapUp(){ + File cleanUP = new File(System.getProperty("user.dir") + "/Testing.txt"); // create a File for the given file path + assertTrue(cleanUP.delete()); + } +} diff --git a/src/test/java/duke/tasktest/DeadlineTest.java b/src/test/java/duke/tasktest/DeadlineTest.java new file mode 100644 index 00000000..9687c39b --- /dev/null +++ b/src/test/java/duke/tasktest/DeadlineTest.java @@ -0,0 +1,30 @@ +package duke.tasktest; + + +import duke.task.Deadline; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DeadlineTest { + private static Deadline deadline; + + @BeforeAll + static void init(){ + LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0); + deadline = new Deadline("return book", sample); + } + @Test + void printDeadlineSyntax_deadlineTaskSample_success(){ + assertEquals("[D][ ] return book(by: 2021-12-25[SATURDAY] 16:00)", deadline.toString()); + } + + @Test + void deadlineEncodeTest_deadlineTask_success(){ + assertEquals("D | 0 | return book | 2021-12-25 | 16:00", deadline.encodeTask()); + } + +} diff --git a/src/test/java/duke/tasktest/EventsTest.java b/src/test/java/duke/tasktest/EventsTest.java new file mode 100644 index 00000000..b04328b1 --- /dev/null +++ b/src/test/java/duke/tasktest/EventsTest.java @@ -0,0 +1,29 @@ +package duke.tasktest; + +import duke.task.Events; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EventsTest { + + private static Events event; + + @BeforeAll + static void init(){ + LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0); + event = new Events("Finish Homework",sample.toLocalDate(),sample.toLocalTime(),sample.toLocalTime().plusHours(2)); + } + @Test + void printEventSyntax_eventTaskSample_success(){ + assertEquals("[E][ ] Finish Homework (on:2021-12-25[SATURDAY] from:16:00 to:18:00)", event.toString()); + } + + @Test + void eventEncodeTest_eventTask_success(){ + assertEquals("E | 0 | Finish Homework | 2021-12-25 | 16:00 | 18:00", event.encodeTask()); + } +} diff --git a/src/test/java/duke/tasktest/TaskListTest.java b/src/test/java/duke/tasktest/TaskListTest.java new file mode 100644 index 00000000..3090e366 --- /dev/null +++ b/src/test/java/duke/tasktest/TaskListTest.java @@ -0,0 +1,65 @@ +package duke.tasktest; + +import duke.task.*; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Order; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TaskListTest { + private static TaskList tasks; + private static ToDos toDo; + private static Events event; + private static Deadline deadline; + private static LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0); + @BeforeAll + static void init(){ + tasks = new TaskList(); + } + + @Test + @Order(1) + void addTodo(){ + toDo = new ToDos("eat"); + assertTrue(tasks.addTask(toDo)); + } + + @Test + @Order(2) + void addDeadline_deadlineTask_success(){ + deadline = new Deadline("return book", sample); + assertTrue(tasks.addTask(deadline)); + } + + @Test + @Order(3) + void addEvent_eventTask_success(){ + event = new Events("Finish Homework",sample.toLocalDate(),sample.toLocalTime(),sample.toLocalTime().plusHours(2)); + assertTrue(tasks.addTask(event)); + } + @Test + @Order(4) + void checkSize_taskListSize_success(){ + assertEquals(3, tasks.getListSize()); + } + + @Test + @Order(5) + void getLastTask_retrieveLastTask_success(){ + assertEquals(event,tasks.getLastTask()); + } + + @Test + @Order(6) + void getTaskByID_retrieveTaskID_success(){ + assertEquals(toDo, tasks.getTask(0)); + } +} diff --git a/src/test/java/duke/tasktest/ToDosTest.java b/src/test/java/duke/tasktest/ToDosTest.java new file mode 100644 index 00000000..97533a42 --- /dev/null +++ b/src/test/java/duke/tasktest/ToDosTest.java @@ -0,0 +1,45 @@ +package duke.tasktest; + +import duke.task.ToDos; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Order; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class ToDosTest { + + private static ToDos toDos; + + @BeforeAll + static void init(){ + toDos = new ToDos("eat"); + } + @Test + @Order(1) + void printToDoSyntax_todoTaskSampleWithoutDuration_success(){ + assertEquals("[T][ ] eat", toDos.toString()); + } + + @Test + @Order(3) + void printToDoSyntax_todoTaskSampleWithDuration_success(){ + toDos.setDuration(1); + assertEquals("[T][ ] eat (requires: 1 Hour)", toDos.toString()); + } + + @Test + @Order(2) + void todoEncodeTest_toDoWithNoDuration_success(){ + assertEquals("T | 0 | eat | 0", toDos.encodeTask()); + } + + @Test + @Order(4) + void todoEncodeTest_toDoWithDuration_success(){ + assertEquals("T | 0 | eat | 1", toDos.encodeTask()); + } +} diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6..2ac693cf 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -5,3 +5,36 @@ Hello from | |_| | |_| | < __/ |____/ \__,_|_|\_\___| + ____________________________________________________________ + Hello! I'm duke.duke + What can I do for you? + ____________________________________________________________ + ____________________________________________________________ + Got it. I've added this task: + [T][ ] return book (by: June 6th) + Now you have 2 tasks in the list. + ____________________________________________________________ + ____________________________________________________________ + Got it. I've added this task: + [D][ ] return book (by: June 6th) + Now you have 2 tasks in the list. + ____________________________________________________________ + ____________________________________________________________ + Got it. I've added this task: + [E][ ] project meeting (at: Aug 6th 2-4pm) + Now you have 3 tasks in the list. + ____________________________________________________________ + ____________________________________________________________ + 1. [ ] read book + 2. [ ] return book + 3. [ ] buy bread + ____________________________________________________________ + ____________________________________________________________ + Nice! I've marked this task as done: + [X] return book + ____________________________________________________________ + ____________________________________________________________ + 1. [ ] read book + 2. [X] return book + 3. [ ] buy bread + ____________________________________________________________ \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29b..18b02372 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,25 @@ +to do read book +deadline return book +deadline return book /by 2021-10-24 10PM +deadline return book /by 2021/10/24 10PM +event project meeting +event project meeting /at 2021-10-24 2-4PM +event project meeting /at 2021/10/24 2PM-4PM +to do join sports club +to do borrow book +list +deadline borrow book /by 2021/11/5 11AM +deadline read book /by 2021/11/5 3PM +deadline return book /by 2021/11/5 10PM +event project meeting /at 2021/11/5 2PM-4PM +event family dinner /at 2021/11/5 6PM-9PM +event new year /at 2022/2/2 0AM-12AM +save +list +done 1 +done 2 +list +done project meeting +done 3 +done 5 +done 6 diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 08737446..bca3a295 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -7,7 +7,7 @@ REM delete output from previous run if exist ACTUAL.TXT del ACTUAL.TXT REM compile the code into the bin folder -javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java +javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\duke.duke.java IF ERRORLEVEL 1 ( echo ********** BUILD FAILURE ********** exit /b 1 @@ -15,7 +15,7 @@ IF ERRORLEVEL 1 ( REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Duke < input.txt > ACTUAL.TXT +java -classpath ..\bin duke.duke < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100644 new mode 100755 index c9ec8700..8433cd0b --- a/text-ui-test/runtest.sh +++ b/text-ui-test/runtest.sh @@ -13,7 +13,7 @@ then fi # compile the code into the bin folder, terminates if error occurred -if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java +if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/Duke.java then echo "********** BUILD FAILURE **********" exit 1