termiNus Developer Guide
- Introduction
- Setting up, Getting Started
- Design
- Implementation
- Appendix: Requirements
- Appendix: Instructions for manual testing
Introduction
termiNus is an interactive Command Line Interface (CLI) task manager for undergraduate students in NUS. This program will help them achieve a better grip on their school life as well as assist in better management of their daily expenses and be reminded of any library loans.
This guide gives an overview understanding of the architectural design and implementation of termiNus. It will
assist developers in the knowledge they require to further build upon this application. We hope you have a clearer picture
after reading through our Developer Guide.
Pre-requisite: Proficient in comprehending UML diagrams and notations.
Setting up, Getting Started
Setting up the project in your local machine
Ensure that you have JDK 11 or above installed on your computer.
First, fork this repo, and clone the fork to your local machine.
If you plan to use IntelliJ IDEA (highly recommended):
- Ensure IntelliJ IDEA is configured to use JDK 11.
- Open IntelliJ and a welcome screen should appear.
- Click on
Configure
->Structure for New Projects
->Project Settings
->Project
. - Under the
Project SDK:
section, select java version “11.0.8” or higher).
- Import the project as a Gradle project.
- Ensure Gradle plugin is enabled by going to
File
->Settings
->Plugins
. - Under the
Installed
section go toBuild Tools
and enable Gradle. - At the welcome page, click on
Open or Import
. - Locate the
build.gradle
file within the folder that contains the clone repo and select it. - Choose the
Open as Project
option when asked. - Accept all default settings and wait for the project to import.
- Ensure Gradle plugin is enabled by going to
- Verify the setup.
- Under the
seedu.duke
package, locate theDuke
class and run it. - Try a few commands. You may want to refer to the user guide.
- Under the
Before writing the code
- Configure the coding style
- If using IntelliJ IDEA, follow this guide to set up IDEA’s coding style to match ours.
- Set up CI
- This project comes with a GitHub Actions config files (in
.github/workflows
folder). When GitHub detects those files, it will run the CI for the project automatically at each push to themaster
branch or to any PR. No setup is required for this.
- This project comes with a GitHub Actions config files (in
- Learn the design
- When you are ready to start coding, we recommend that you refer to termiNus’s architecture to get a better idea of the overall design.
Design
Architecture
Architecture Diagram
Below is an architecture diagram of termiNus.
Duke
is the main object of the program and handles all the logic and models related to the program.Ui
is the main object that provides an interface betweenDuke
and the user.Command
represents a command that is provided by the user.Ui
reads the command before it is sent toParser
to create a newCommand
object.Parser
creates a command object by parsing the user’s arguments and sending them toCommandCreator
, which returns aCommand
object. For instances where no arguments are needed (such asByeCommand
), Parser creates theCommand
object directly.Duke
executes theCommand
and shows the output to the user throughUi
.Command
object modifies the state ofModel
, which consists of multiple lists for different types ofItems
.Storage
takes the state ofModel
and stores it to file.
Sequence Diagram
Below is a sequence diagram of how the main program functions.
- First, the
main
function of theDuke
class creates an instance ofDuke
. - During the instantiation of
Duke
, aModel
object is created. Duke
loads the state ofModel
from file by calling theload()
method ofModel
.- After
Duke
is initialized, theDuke
class calls therun()
method ofDuke
. Duke
calls methods fromUi
class and shows messages to the user.Duke
reads user commands using theUi
class (which acts as an interface betweenDuke
and the user).Command
object is returned toDuke
which is executed.Command
object interacts withModel
and changes its state.Duke
saves the state ofModel
to file by calling thesave()
method ofModel
.Duke
continues reading commands until aByeCommand
is generated by the user.
Ui component
The Ui component is a user interface which reads user input command and output interacting messages.
The Ui
component represents a Ui
class and acts as an interface between Duke
and the user.
The Ui
component:
- Reads input from the user.
- Prints the output to the user, for example during the execution of a
Command
. - Displays other types of output to the user, such as a calendar.
Parser component
The Parser
class is a class forming part of the logic of termiNus. The Parser
parses user commands and
returns a Command
subclass which corresponds to the full command with arguments.
Command component
The Command
component represents an abstract object with state corresponding to a single line of the user’s input.
Every basic command inherits the abstract Command
class, with their own attributes and execute operations. After
user input is parsed by Parser
, CommandCreator
will create and return the corresponding command to be execute.
The Command
object:
- Modifies the state of
Model
object which depends on the state and type ofCommand
object. - Exposes its
execute()
method so that it can be passed around before theCommand
is executed. - Is executed by the
Duke
object. - Prints the output to the user through the
Ui
component.
CommandCreator component
The CommandCreator
represents a class with methods that generate Commands
from parsed arguments from Parser
class.
The CommandCreator
class:
- Takes in arguments as needed by
Parser
class. - Splits the arguments further into more parts if the
Command
has more arguments in the description. - Returns a
Command
subclass object depending on the method that was called.
Storage component
The Storage
class is a class loading data from files when termiNus starts and saving data to files after each command.
The Storage
object:
- Is referenced only by
Model
. - Expose functions to allow
Model
to pass in the state and saves it to file. - Expose functions to load the state of
Model
from file.
Item component
Item
is a super class with 5 subclasses inheriting it: Task
, Expense
, Module
, Link
, Book
.
Here is the class diagram for Item
class and its subclasses.
The Item
class and its subclasses:
- Contains getters and setters to retrieve and set the attributes.
Model Component
The Model
component represents the state of the various lists stored in memory.
The Model
component:
- Stores and loads program state to file using the
Storage
API. - Expose references to its
ItemList
objects so that other objects such asCommand
can modify it.
Implementation
This section describes how certain features are implemented.
Parser
The Parser
class is a class that takes in a single line of the user’s command and returns a corresponding Command
that can be executed.
The Parser
object:
- Expose functions to allow
Model
to pass in the user’s full command to be parsed. - Uses regular expressions to parse the user’s arguments into several parts.
- Passes these parts to
CommandCreator
to create the corresponding command. - Returns the
Command
toModel
that can be executed.
High level description
The Parser.parse()
method takes in fullCommand
as an argument, which is the full command entered by the user.
Example commands:
add task tP meeting c/cs2113 p/0
add module CS2113 mc/4 ay/2021S1 g/A
The fullCommand
is composed of several parts, which consists of a root command (add
), description (module CS2113
)
and optional arguments (mc/4 ay/2021S1 g/A
).
An optional argument consists of 2 parts, which is delimited by a forward slash. In the example above, there are 3 optional
arguments, which are mc/4
, ay/2021S1
and g/A
. Each optional argument can be represented in this form: <key>/<value>
.
In some commands, the optional arguments may be compulsory and is checked by the Parser
at runtime.
The parse
method parses the fullCommand
into these parts before passing them as arguments to CommandCreator
methods and returns a Command
object with the corresponding arguments.
The following sequence diagram shows how the Parser
works.
The following diagram shows how a command should be parsed into its separate parts.
Implementation details
- The
parse
method ofParser
is invoked by the calling object. In termiNus, the only object that invokes this method isDuke
. ThefullCommand
is passed an argument, which is the full command entered by the user. - The method parses
fullCommand
into two separateStrings
, which arerootCommand
andcommandString
.rootCommand
contains the first word of the command andcommandString
contains the rest of the command with the first word removed. This is done using thesplit
method of theString
class, then removing therootCommand
from thefullCommand
before storing it incommandString
. - The method then invokes the
removeArgumentsFromCommand
method to parse and remove optional arguments from the full command. This is done using regular expression parsing which is detailed in the next section. The results are returned to theparse
method and stored indescription
. - The method then invokes the
getArgumentsFromRegex
method when therootCommand
is not"find"
to parse the optional arguments from the full command. The results are stored in aHashMap<String, String>
, which is aHashMap
of key-value pairs, similar to the form of the optional argument (<key>/<value>
). The results are returned to theparse
method and stored asargumentsMap
. - The method then checks the
rootCommand
and decides whichCommand
to return, which callsCommandCreator
methods with the parsedargumentsMap
,description
, andcommandString
. - For certain commands,
checkAllowedArguments
method is called to ensure that the user did not pass in invalid arguments for that given command, and throws an error if there are invalid arguments. - For single-word commands like
bye
,checkFullCommand
method is called to ensure that the full command corresponds to the command word, and rejects commands likebye 3
. - The results of the
CommandCreator
methods are returned as aCommand
back to the invoker of theparse
method.
Regular expression parsing
Two of the previously mentioned methods, removeArgumentsFromCommand
and getArgumentsFromRegex
make use of regular
expressions to parse the optional arguments.
The diagram below illustrates how the regular expression matches an optional argument.
- The regular expression that parses these optional arguments is
([\w]+/[^\s]+)
. This regular expression matches 1 or more alphanumeric characters (denoted by[\w]+
), followed by a forward slash, then 1 or more non-whitespace character (denoted by[^\s]+
). - The expression also uses capturing parenthesis to ensure that the parser does not parse the same argument twice.
Design considerations
- The results of
getArgumentsFromRegex
are stored as aHashMap
instead ofArrayList
or simply returned as a value. This allows the same method to be reused for different commands, which may accept different optional arguments with different key-value pairs. This ensures that the code follows DRY principles. - The regular expressions parsing means that we do not need to manually parse every different command with different arguments, thus reducing code complexity and SLOC.
Storage
This section describes how the Storage
class works
High level description
Methods handling data loading (i.e. loadTask()
, loadBook()
, loadLinks()
, loadModule()
, loadExpense()
methods)
return an ArrayList
of items (i.e. Task
, Book
, Link
, Module
, Expense
). These will be the initial values of
the item list (i.e. TaskList
, BookList
, LinkList
, ModuleList
, ExpenseList
). The save()
method takes an
inherited instance of ItemList
and a String
specifying the path to which the file will be saved. The ItemList
will
be parsed and saved into files (each ItemList
will be saved to a separate file) at the specified path.
Formats of the files:
tasks.txt
:
There are 6 fields stored for each Task
:
- String
T
for “Task” - Whether the
Task
has been done or not (1 for done, 0 for not done) - Description of the
Task
- Priority of the
Task
(an Integer) - Category of the
Task
- Date of the
Task
All the fields are separated by |
with a leading and a trailing space. Each Task
is stored as one line.
Example: T | 0 | borrow book | 1 | book | 28-10-2020
books.txt
:
There are 5 fields stored for each Book
:
- String
B
for “Book” - Whether the
Book
has been returned or not (1 for returned, 0 for not returned) - Name/Description of the
Book
- Borrow date of the
Book
- Return date of the
Book
All the fields are separated by |
with a leading and a trailing space. Each Book
is stored as one line.
Example: B | 0 | cooking book | 11-11-2011 | 11-12-2011
links.txt
:
There are 3 fields stored for each Link
:
- Module of the
Link
- Use of the
Link
- URL of the
Link
All the fields are separated by |
with a leading and a trailing space. Each Link
is stored as one line.
Example: CS2113 | lecture | https://cs2113Lecture.zoom.com
modules.txt
:
There are 4 fields for each Module
:
- Module code
- Grade
- Modular credits
- Academic year and semester
All the fields are separated by |
with a leading and a trailing space. Each Module
is stored as one line.
expenses.txt
There are 4 fields for each Expense
:
- Description
- Value
- Currency
- Date
All the fields are separated by |
with a leading and a trailing space. Each Module
is stored as one line.
Currency has default value “SGD”.
Date has default value of the date that the spend
command is executed.
Date will be in the format of yyyy-MM-dd
, e.g. 2020-11-09
.
Implementation details
The following sequence diagram shows how the Storage
works.
- At the start of
Duke
, a newStorage
object will be created. Duke
calls loading methods (i.e.loadTask()
,loadBook()
,loadLinks()
,loadModule()
,loadExpense()
) sequentially. Each loading method calls the corresponding helper method (i.e.loadTaskFromLine()
,loadBookFromLine()
,loadLinkFromLine()
,loadModuleFromLine()
,loadExpenseFromLine()
) to loadItem
s from each line in the file.- After each command,
Duke
calls thesave()
method ofStorage
to save all theItem
s in the list to files.
List feature
List tasks
The list tasks feature allows the user to list all the tasks tracked.
This feature is facilitated by ListCommand
.
- The user inputs the command
list tasks
. (Assuming the task list is not empty) - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListCommand
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordtasks
, and returns aListCommand
for the whole task list. - The command is executed and the complete list of all the tracked tasks is displayed.
List tasks with priority
The list tasks with priority feature allows the user to list tasks of a certain priority.
This feature is facilitated by Parser
and ListCommand
.
- The user inputs the command
list tasks p/3
. (Assuming the tasks of priority 3 exist.) - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListCommand
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordtasks
andp/
, and returns aListCommand
for the task list of priority level 3. - The command is executed and the list of tasks with priority 3 is displayed.
List tasks with category
The list tasks with category feature allows the user to list tasks of a certain category.
This feature is facilitated by Parser
and ListCommand
.
- The user inputs the command
list tasks c/CS2113
. (Assuming the tasks of CS2113 exist.) - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListCommand
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordtasks
andc/
, and returns aListCommand
for the task list under CS2113 category. - The command is executed and the list of tasks categorized by CS2113 is displayed.
Add links
The add links feature allows the user to add and save zoom meeting links of modules.
This feature is faclitated by Parser
, AddCommand
and Storage
.
- The user inputs
add links m/CS2113 t/lecture u/https://nus.sg.zoom.us/cs2113/lecture
. - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aAddCommand
. - The method
createAddCommand()
inCommandCreator
further parses the input by identifying the keywordlink
, and returns aAddCommand
. - The command is excuted and the link is added into the link list with module name and online class type.
Storage
saves the added link by writing it into thelinks.txt
file.
List links
The list link feature allows the user to list all the zoom meeting links.
This feature is facilitated by Parser
and AddCommand
.
- The user inputs
list links
. (Assuming the link list is not empty). - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListCommand
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordlinks
, and returns aListCommand
for the link list. - The command is excuted and the complete list of links is displayed.
List expenses
The list expenses feature allows the user to list all the expense items in the expense list together with a summary message displaying the total amount of expenses listed for each currency.
This feature is facilitated by Parser
and ListExpenseCommand
.
- The user inputs
list expenses
. - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListExpense Command
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
, and calls the static methodcreateListExpenseCommand()
in classListExpenseCommand
. - The static method
creatListExpenseCommand()
in classListExpenseCommand
further parses the arguments and returns a newListExpenseCommand
for the expense list. - The command is executed and the complete expense list is displayed together with the summary information.
- If the expense list is empty, the message
There are no expense items to be listed in your expense list.
will be displayed.
List expenses with currency
The list expenses with currency feature allows the user to list expense items of a curtain currency together with a summary message displaying the total amount of expenses listed for each currency.
This feature is facilitated by Parser
and ListExpenseCommand
.
- The user inputs the command
list expenses currency/USD
. - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListExpense Command
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
, and calls the static methodcreateListExpenseCommand()
in classListExpenseCommand
. - The static method
creatListExpenseCommand()
in classListExpenseCommand
further parses the arguments by identifying keywordcurrency
, and returns a newListExpenseCommand
for the expense list. - The command is executed and the expense list with
currency
USD
is displayed together with the summary information.
- If the expense list is empty, the message
There are no expense items to be listed in your expense list.
will be displayed.
List expenses with date
The list expenses with date feature allows the user to list expense items of a curtain date together with a summary message displaying the total amount of expenses listed for each currency.
This feature is facilitated by Parser
and ListExpenseCommand
.
- The user inputs the command
list expenses date/2020-11-09
. - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListExpense Command
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
, and calls the static methodcreateListExpenseCommand()
in classListExpenseCommand
. - The static method
creatListExpenseCommand()
in classListExpenseCommand
further parses the arguments by identifying keyworddate
, and returns a newListExpenseCommand
for the expense list. - The command is executed and the expense list with
date
2020-11-09
is displayed together with the summary information.
-
If the expense list is empty, the message
There are no expense items to be listed in your expense list.
will be displayed. -
The
date
argument must be in the format ofdate/<yyyy-MM-dd>
. If thedate
argument does not follow the correct format, an error messagePlease input a valid date string in the format "yyyy-MM-dd"
will be displayed.
List expenses with date
The list expenses with date feature allows the user to list expense items of a curtain date together with a summary message displaying the total amount of expenses listed for each currency.
This feature is facilitated by Parser
and ListExpenseCommand
.
- The user inputs the command
list expenses date/2020-11-09
. - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListExpense Command
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
, and calls the static methodcreateListExpenseCommand()
in classListExpenseCommand
. - The static method
creatListExpenseCommand()
in classListExpenseCommand
further parses the arguments by identifying keyworddate
, and returns a newListExpenseCommand
for the expense list. - The command is executed and the expense list with
date
2020-11-09
is displayed together with the summary information.
-
If the expense list is empty, the message
There are no expense items to be listed in your expense list.
will be displayed. -
The
date
argument must be in the format ofdate/<yyyy-MM-dd>
. If thedate
argument does not follow the correct format, an error messagePlease input the date string in the format "yyyy-MM-dd"
will be displayed.
List expenses for a certain date range
The list expenses for a certain date range feature allows the user to list expense items of a curtain date range (i.e. today/this week/this month/this year) together with a summary message displaying the total amount of expenses listed for each currency.
This feature is facilitated by Parser
and ListExpenseCommand
.
- The user inputs the command
list expenses for/WEEK
. - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aListExpense Command
. - The method
createListCommand()
inCommandCreator
further parses the input by identifying the keywordfor
, and calls the static methodcreateListExpenseCommand()
in classListExpenseCommand
. - The static method
creatListExpenseCommand()
in classListExpenseCommand
further parses the arguments by identifying keywordfor
, and returns a newListExpenseCommand
for the expense list. - The command is executed and the expense list for the currency week is displayed together with the summary information.
-
If the expense list is empty, the message
There are no expense items to be listed in your expense list.
will be displayed. -
The
for
argument is case-insensitive. For example, bothlist expenses for/MONTH
andlist expenses for/month
are valid commands.
Calendar feature
Calendar command
The calendar command allows users to print out a calendar view of their tasks within the next X
days, where X
is a parameter passed by the user.
CalendarCommand
obtains a list of tasks fromTaskList
by using itsgetTaskList
method, which returns anArrayList
ofTask
objects.- The list of tasks is converted into a
Stream
. - The
Task
objects without dates are filtered out. - The
Task
objects outside the range of the current date andX
days of the current date are filtered out. - The
ArrayList
is sorted by task dates, which uses aComparator
defined in the parameters. - The
Stream
is collected back into anArrayList
, which has sorted dates of tasks within the nextX
days. - The
ArrayList
ofTask
objects are passed to theUi.dukePrintCalendar
method, which prints the tasks as a calendar. - The
dukePrintCalendar
method groups tasks by date and a new heading is printed for each day. This is done by comparing eachTask
in the loop with the previous task to check if they have the same date, and to print a new heading if not.
The filtering of the tasks by date is done using this code, which is called on a Stream
object.
.filter(task -> currentDate.until(task.getDate(), ChronoUnit.DAYS) >= 0)
.filter(task -> currentDate.until(task.getDate(), ChronoUnit.DAYS) <= daysToPrint)
The sorting of tasks by date is done using this code, which is also called on a Stream
object.
.sorted(Comparator.comparing(Task::getDate))
This sorts the stream using a Comparator
which is defined inline. The Comparator
makes use of the Task.getDate()
method to do the comparisons.
This is done instead of defining a new Comparator
class as toCompare
is already implemented in the LocaDate
API, and doing this simplifies the code.
Delete feature
Delete tasks by index
The delete tasks by index feature allows the user to delete a task identified by a certain index.
This feature is facilitated by Parser
and DeleteCommand
.
- The user inputs the command
delete task 2
. (Assuming the task of index2
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordtask
, and returns aDeleteCommand
with the task index. - The command is executed and the task with index
2
is deleted. The deleted task is displayed.
- If the task does not exist in the task list, the error message
~Error~ This task index does not exist. Please try again.
will be displayed.
Delete tasks with priority
The delete tasks with priority feature allows the user to delete all the tasks of a certain priority.
This feature is facilicated by Parser
and DeleteCommand
.
- The user inputs the command
delete tasks p/2
. (Assuming the tasks of priority2
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordtasks
andp/
, and returns aDeleteCommand
for the task list of priority level2
. - The command is executed and all tasks with priority level
2
are deleted. The deleted tasks are displayed.
- If the priority does not exist in the task list, the error message
~Error~ Invalid priority number.
will be displayed.
Delete tasks with category
The delete tasks with category feature allows the user to delete all the tasks of a certain category.
This feature is facilicated by Parser
and DeleteCommand
.
- The user inputs the command
delete tasks c/cs2113
. (Assuming the tasks of categorycs2113
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordtasks
andc/
, and returns aDeleteCommand
for the task list of categorycs2113
. - The command is executed and all tasks with category
cs2113
are deleted. The deleted tasks are displayed.
- If the priority does not exist in the task list, the error message
~Error~ Invalid category.
will be displayed.
Delete links by index
The delete links by index feature allows the user to delete a link identified by a certain index.
This feature is facilitated by Parser
and DeleteCommand
.
- The user inputs the command
delete link 2
. (Assuming the link of index2
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordlink
, and returns aDeleteCommand
with the link index. - The command is executed and the link with index
2
is deleted. The deleted link is displayed.
- If the link does not exist in the link list, the error message
~Error~ This link index does not exist. Please try again.
will be displayed.
Delete modules by index
The delete modules by index feature allows the user to delete a module identified by a certain index.
This feature is facilitated by Parser
and DeleteCommand
.
- The user inputs the command
delete module 2
. (Assuming the module of index2
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordmodule
, and returns aDeleteCommand
with the module index. - The command is executed and the module with index
2
is deleted. The deleted module is displayed.
- If the module does not exist in the module list, the error message
~Error~ This module index does not exist. Please try again.
will be displayed.
Delete expenses by index
The delete expenses by index feature allows the user to delete an expense item identified by a certain index.
This feature is facilitated by Parser
and DeleteExpenseCommand
.
- The user inputs
delete expense 2
. (Assuming the expense item of index2
exist.) - The full command string will be parsed by
Parser
, whoseparse()
method returns aCommandCreator
object to create aDeleteExpenseCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
, and returns aDeleteExpenseCommand
with the expense index. - The command is executed and the expense item with index
2
is deleted. the deleted expense item is displayed.
- If the expense item does not exist in the expense list, the error message
~Error~ This expense item does not exist. Please try again.
will be displayed.
Delete expenses with currency
The delete expenses with currency feature allows the user to delete all the expense items of a certain currency.
This feature is facilicated by Parser
and DeleteExpenseCommand
.
- The user inputs the command
delete expenses currency/USD
. (Assuming the expenses of currencyUSD
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteExpenseCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
andcurrency/
, and returns aDeleteExpenseCommand
for the task list of currencyUSD
. - The command is executed and all expense items with currency
USD
are deleted. The deleted expense items are displayed.
- If the currency does not exist in the task list, the error message
There is no expense item deleted.
will be displayed.
Deleting expenses with date
The delete expenses with date feature allows the user to delete all the expense items of a certain date.
This feature is facilicated by Parser
and DeleteExpenseCommand
.
- The user inputs the command
delete expenses date/2020-11-09
. (Assuming the expenses of date2020-11-09
exist.) - The full command string will be parsed by
Parser
, whoseparse()
command returns aCommandCreator
object to create aDeleteExpenseCommand
. - The method
createDeleteCommand()
inCommandCreator
further parses the input by identifying the keywordexpenses
anddate/
, and returns aDeleteExpenseCommand
for the task list of date2020-11-09
. - The command is executed and all expense items with date
2020-11-09
are deleted. The deleted expense items are displayed.
-
If the currency does not exist in the task list, the error message
There is no expense item deleted.
will be displayed. -
The
date
argument must be in the format ofdate/<yyyy-MM-dd>
. If thedate
argument does not follow the correct format, an error messagePlease input a valid date string in the format "yyyy-MM-dd"
will be displayed.
Appendix: Requirements
Product scope
Target user profile
Undergraduate students of National University of Singapore who:
- require help to better manage their school work.
- forgets to return their loan books to the library on time.
- wants a timetable planner for easy reference.
- are lazy to create separate module folders every semester.
- wish to calculate their CAP.
Value proposition
termiNus is an application which helps NUS undergraduates to better manage their school life, by providing daily task or borrowed books tracking, and module-related functions. This increase users’ efficiency and make their life more organized.
User Stories
Version | Priority | As a … | I want to … | So that I can … |
---|---|---|---|---|
v1.0 | High | student | add tasks into a list | keep track of the things I need to do |
v1.0 | High | student | assign priorities to tasks | focus on the more important things first |
v1.0 | Medium | student | assign categories to tasks | have a more organised task list |
v1.0 | High | student | mark tasks as done | keep track of the remaining tasks to do |
v1.0 | Medium | student | list all tasks in my list | have a better overview |
v1.0 | High | student | be able to delete unwanted tasks | focus on the tasks which I need |
v1.0 | High | student | save all data after using the application | retrieve the data upon running the application |
v2.0 | Medium | student | automatically create folders for my modules | I do not have to manually create them |
v2.0 | High | student | add recurring tasks | avoid adding the same tasks every week |
v2.0 | High | student | have a calendar | I can view my current and upcoming tasks |
v2.0 | High | student | be able to set a tracker my borrowed books | avoid overdue fines |
v2.0 | Medium | student | sort my tasks based on highest priority | focus on those tasks first |
v2.0 | High | student | save zoom links in a centralized place | easily attend my online classes instead of looking through my email for the link |
v2.0 | High | student | add modules and calculate my CAP | have a better projection of my grades and efforts |
v2.0 | Low | student | login with a password | my system is protected |
Non-Functional Requirements
-
Should work on any mainstream OS as long as it has
Java 11
or above installed. -
Should be able to respond to any command in less than 2 seconds.
-
A user should be able to complete majority of tasks faster using CLI than GUI.
Glossary
Acronym | Full form | Meaning |
---|---|---|
CI | Continuous Integration | Combining parts of a software product to form a whole |
SDK | Software Development Kit | A set of software tools by software vendors |
IntelliJ | IntelliJ | An Integrated Development Environment written in Java |
UML | Unified Modeling Language | A modeling language which to visualize the design of a system |
CLI | Command Line Interface | A program that accepts text inputs to execute operating system functions |
GUI | Graphical User Interface | An interface that allows users to interact through graphical icons |
Mainstream OS | Windows, Linux, Unix, OS-X | Operating systems |
SLOC | Source Lines of Code | The number of lines in a program’s source code |
DRY | Don’t Repeat Yourself | Every piece of knowledge must have a single, unambiguous, authoritative representation within a system |
CAP | Cumulative Average Point | The weighted average grade point of all modules taken by a student |
Appendix: Instructions for manual testing
Below are the steps required for manual testing of termiNus
Launch and shutdown
- Initial launch
- Download the latest version of
termiNus
from here and copy the jar file to an empty folder. - Open a command line window in the same directory and launch termiNus by typing
java -jar termiNus.jar
and press enter.
- Download the latest version of
- Shutdown
- Input
bye
to exit the program.
- Input
Adding items
- Adding a task
- Test case:
add task tP submission c/CS2113 p/1 date/09-11-2020
Expected: tasktP submission
is added to the task list, with priority of1
, category ofCS2113
, and a date of09 Nov 2020
.
- Test case:
- Adding a recurring task
-
Test case:
addr tP meeting s/26-10-2020 e/27-11-2020 day/tue c/CS2113 p/2
Expected: recurring taskstP meeting
are added to the task list, with priority of2
, category ofCS2113
, and the recurring dates of the Tuesdays during the start and end period. -
Test case:
addr game club c/CCA <br>
Expected: an error message is printed since the compulsory argumentss/
,e/
,day/
are all required for a recurring task.
-
- Adding a module
-
Test case:
add module CS1010 d/1 g/A+ mc/4 ay/1920S1
Expected: moduleCS1010
completed inAY1920S1
is added to the module list, with the gradeA+
and MCs of4
. -
Test case:
add module STT233 d/1 g/A+ mc/4 ay/1920S1
Expected: an error message is printed since the module name is in incorrect format. -
Test case:
add module ST2334 mc/4 ay/1920S1
Expected: an error message is printed since the compulsory argumentsg/
,mc/
,ay/
are all required for a module.
-
- Adding a link
-
Test case:
add link m/CS2113 t/lecture u/https://cs2113lecture.zoom.com
Expected: the Zoom meeting link forlecture
of moduleCS2113
is added to the link list. -
Test case:
add link m/CS2113 t/meeting u/https://cs2113meeting.zoom.com
Expected: an error message is printed since the input fort/
argument can only belecture
,tutorial
,lab
, orproject
.
-
- borrowing a book
- Test case:
borrow Harry Potter date/10-11-2020
Expected: the bookHarry Potter
is added to the book list with the loan date10 Nov 2020
and due date10 Dec 2020
.
- Test case:
- Adding an expense item
-
Test case:
spend lunch v/4 currency/SGD date/2020-11-08
Expected: a4.00
SGD
expense onlunch
onSunday, November 8,2020
is added to the expense list. -
Test case:
spend book v/15
Expected: a15.00
SGD
expense onbook
on the current day is added to the expense list. (By default, ifcurrency/
anddate/
arguments are not specified, termiNus will assume the currency isSGD
and the date is the current day.)
-
Creating module folders
- Test case:
makefolders
Expected: sub-folders (Lecture Notes
andTutorials
) are created at the output directories for each module in the module list.
Displaying items
- Displaying tasks
-
Test case:
list tasks
Expected: the complete list of tasks is displayed. -
Test case:
list tasks p/1
Expected: the list of tasks under priority1
is displayed. -
Test case:
list tasks p/-1
Expected: an error message is printed, since the priority of a task can only be a non-zero integer. -
Test case:
list tasks p/4
Expected: an error message is printed, since there is no task of this priority. -
Test case:
list tasks c/CS2113
Expected: the list of tasks under categoryCS2113
is displayed. -
Test case:
list tasks c/work
Expected: an error message is printed, since there is no task of this category.
-
- Displaying modules
- Test case:
list modules
Expected: the complete list of modules is displayed.
- Test case:
- Displaying links
- Test case:
list links
Expected: the complete list of links is displayed.
- Test case:
- Displaying books
- Test case:
list books
Expected: the complete list of books is displayed.
- Test case:
- Displaying expenses
-
Test case:
list expenses
Expected: the complete list of expenses is displayed, followed by the total expenses calculated for the current day, week, month, and year. -
Test case:
list expenses date/2020-11-09
Expected: the list of expenses onSunday, November 8, 2020
is displayed, followed by the total expenses caculated for the given day. -
Test case:
list expenses for/week
Expected: the list of expenses for the current week is displayed.
-
Marking an item as done
Prerequisite: list the desired item list using list
command. Multiple items in the list.
- Marking a task as done
- Test case:
done task 1
Expected: the first task in the task list is marked as doneY
.
- Test case:
- Marking a module as completed
- Test case:
done module 1
Expected: the first module in the module list is marked as completedCM
.
- Test case:
- Marking a book as returned
- Test case:
return 2
Expected: the second book in the book list is marked as returnedR
.
- Test case:
Setting the priority of a task
Prerequisite: list the complete task list using list
command. Multiple tasks in the list.
- Test case:
set 3 p/2
Expected: the priority of the third task in the task list is set as2
.
Setting the category of a task
Prerequisite: list the complete task list using list
command. Multiple tasks in the list.
- Test case:
category 2 c/CS2113
Expected: the category of the second task in the task list is set asCS2113
.
Setting the date of a task
Prerequisite: list the complete task list using list
command. Multiple tasks in the list.
- Test case:
date 2 date/02-01-2021
Expected: the date of the second task in the task list is set as02 Jan 2021
.
Printing the task calendar
- Test case:
calendar d/3
Expected: the tasks for the current day and for the next3
days are output separately as a calendar.
Searching for tasks with keywords
-
Test case:
find tP
Expected: the tasks containing the keywordtP
are displayed. -
Test case:
find t
Expected: an information is printed out to informing there is no matching tasks, since there is no keywordt
in any task in the list and incomplete keywords are not allowed.
Deleting items
Prerequisite: list the desired item list using list
command. Multiple items in the list.
- Deleting a task/tasks
-
Test case:
delete task 1
Expected: the first task in the task list is deleted. -
Test case:
delete tasks p/1
Expected: the tasks that under priority1
are deleted. -
Test case:
delete task p/0
Expected: an error message is printed indicating invalid index, since the delete command for tasks under a certain priority should usetasks
instead oftask
in the input. -
Test case:
delete tasks p/10
Expected: an error message is printed indicating invalid index, since there is no task of priority10
in the list. -
Test case:
delete tasks c/CS2113
Expected: the tasks that under categoryCS2113
are deleted. -
Test case:
delete task c/CS2113
Expected: an error message is printed indicating invalid index, since the delete command for tasks under a certain category should usetasks
instead oftask
in the input. -
Test case:
delete tasks c/work
Expected: an error message is printed indicating invalid category, since there is no task of categorywork
in the list.
-
- Deleting a module
-
Test case:
delete module 2
Expected: the second module in the module list is deleted. -
Test case:
delete module 8
Expected: an error message is printed, since the module index does not exist.
-
- Deleting a link
-
Test case:
delete link 1
Expected: the first link in the link list is deleted. -
Test case:
delete link 7
Expected: an error message is printed, since the link index does not exist.
-
- Deleting an expense
-
Test case:
delete expense 1
Expected: the first expense in the expense list is deleted. -
Test case:
delete expense 10
Expected: an error message is printed, since the expense index does not exist. -
Test case:
delete expenses date/2020-11-09
Expected: all the expenses onSunday, November 8, 2020
are removed from the expense list. -
Test case:
delete expense date/2020-11-09
Expected: an error message is printed indicating invalid index, since the delete command for expenses on a certain day should beexpenses
instead ofexpense
in the input.
-
Clearing all items
- Test case:
clear all
Expected: all the tasks, modules, links, books, and expenses are removed.
Getting help
- Test case:
help
Expected: all the available commands and their usages are displayed in the help message.