- Acknowledgements
- Design and Implementation
- Product Scope
- User Stories
- Non-Functional Requirements
- Glossary
- Instructions for Manual Testing
Third party libraries:
API : command.parser
The Parser classes is responsible for receiving user input and converting it into commands which are directly passed to respective classes.
The simplified class diagram below is an overview of relationship between Parser classes and other classes.
How the parsing works:
NoCap
passes the user input toParser
which separates the input into useful information such as taskType, taskDescription, Module, etc.- When commands include listing tasks, the taskDescription is passed to
ListParser
which determines the method of sorting and creates filteredOverallTaskList
andTaskList
accordingly. - Otherwise, the taskDescription is passed to
Command
which calls the corresponding commands inSemesterList
,Semester
,ModuleList
,Module
,Task
,Gradable Task
. For clarity purposes, associations are shown but dependencies are not. ParserChecks
is a class that handles various error checking and string searching methods such asParserSearch#getTaskFromIndex()
andParserSearch#getTaskFromKeyword()
.Command
utilizes these methods to verify the Strings before passing them to other classes. In NoCap, Parser verifies the validity of input (Whether it exists in the right format). Input content is verified by individual classes for correctness.DateParser
handles parsing String into LocalDateTime format and displaying LocalDateTime as String. It is utilized byTask
. Additional date formats can be added inDateParser#inputFormatter()
Below is a step by step example of how the parser receives and decipher a user input. In this example, the user enters
list task sortbydate
.
The Sequence Diagram below illustrates the process
Note: The alternate paths are omitted from the diagram for clarity.
Step 1: The User launches the application. NoCap
creates a new Parser
instance through the constructor and Parser
creates ListParser
.
Step 2: The application waits for User input. User enters list task sortbydate
. NoCap
passes the input to Parser
through Parser#chooseTask()
.
Step 3: splitInput
is called for the first time and splits the user input into list
and task sortbydate
.
TaskType is set to
list
, and TaskDescription is set totask sortbydate
.
TaskType matches a possible command String.
Step 4: splitInput
is called for the second time and splits the user input into task
and sortbydate
.
TaskType is set to
task
, and TaskDescription is set tosortbydate
.
TaskType and TaskDescription are passed to ListParser
through ListParser#overallListParser
.
Step 5: overallListParser
creates an OverallTaskList
. Through nested switch cases, TaskType and TaskDescription are matched, and the corresponding method OverallTaskList#sortByDateAndPrint()
is called. As the
name implies, this method sorts all tasks by date and prints them.
If TaskType does not match, then an error message is displayed.
If TaskDescription does not match, all tasks are printed by default.
Step 6: The full command is carried out and the application returns to NoCap and waits for new User Input.
The diagram below illustrates the splitString
process:
API : command.storage
The Storage component saves data of NoCap into JSON format, and reads them back into corresponding objects when needed using a 3rd party library Jackson Databind.
It consists of 2 utility classes StorageDecoder and StorageEncoder. StorageEncoder is used to encode the parent object
SemesterList
into a JSON file. StorageDecoder decodes a JSON file into a SemesterList
object
How the StorageEncoder
class works:
- The static method
encodeAndSaveSemesterListToJson()
fromStorageEncoder
is called when NoCap data needs to be saved - If the save file directory has not been created yet, it is first created in order to store the save file
- Similarly, an empty file is created to store the data if it has not been created yet
- Then, the object
SemesterList
which holds all NoCap information is converted into a JSON file with anObjectMapper
object from thejackson-databind
library - Upon completion, the data file is saved in a default data directory.
How the StorageDecoder
class works:
- The static method
decodeJsonToSemesterList()
fromStorageDecoder
is called when NoCap data needs to be loaded from the save file - If there is no save file available in the default data directory, a new
SemesterList
object is created and returned to the caller - Otherwise, an
ObjectMapper
object from thejackson-databind
library is used to deserialize the JSON save file into aSemesterList
object to be returned to the caller
API : semester
The Semester
component stores all NoCap data i.e., all Semester
objects and their components and cumulative average
point (CAP) (which are contained in a SemesterList object)
- It consists of 2 classes
SemesterList
andSemester
SemesterList
is used to compute and store the cumulative CAP of all semesters and also stores 10Semester
objects- Each
Semester
object stores and computes the individual CAP for the semester, while also storing aModuleList
of theModule
objects taken during the semester - The computation of the CAP for both
SemesterList
andSemester
is automatically done when a grade/credit as added to aModule
object within any semester
This is how CAP is computed:
- When
commandAddGrade()
orcommandAddCredit()
is called in Parser,addGrade(description)
oraddCredit(description)
respectively are called inModule
, setting the module’sgrade
,points
andcredits
to their corresponding values. - Then,
updateCap()
is called inSemester
with the newly setgrade
/credits
values inModule
, followed byupdateCap()
inSemesterList
with the newly setpoints
/credits
values inSemester
.
API : module
All data related to module is stored in the module class. An Arraylist of Module is used to store and manage the modules. ModuleList is also responsible for constructing and printing out the Timetable.
The modules are stored in an ArrayList and ModuleList uses the Module.get(int index) method to access the target Module.
- ModuleList is responsible for printing the Time Table.
- ModuleList contains the getter method find(String input) which returns a module by the same name as the input.
- Module contains getter and setter methods to change or access its contents.
- When Module is constructed, an empty gradableTaskList, taskList and scheduleList wll be instantiated and stored in Module.
Data stored in Module includes:
- moduleName
- letterGrade
- credits
- points
- TaskList
- GradableTaskList
- ScheduleList
The modules are stored in an ArrayList and ModuleList uses the Module.get(int index) method to access the target Module.
- ModuleList is responsible for printing the Time Table. It accesses different schedules of different mods before constructing a Time Table.
- ModuleList contains getter method find(String input) which returns a module by the same name as the input.
How printing a timetable works:
- When Timetable is called, ModuleList goes into a loop to print out the timetable. ModuleList iterates through the 207 character long length and the 33 lines which makes up the entire timetable.
- Each iteration of the loop can result in 1 of 3 cases:
- It is at a border. When this happens a "#" character is printed to the console which denotes a border.
- It is empty. When this happens a " "(blank) character is printed to the console.
- It contains module information. When this happens, getMoudleName() , getModuleLocation() and getModuleComment() is
called. The information is then printed onto the console.
API : schedule
ScheduleList consists of all data for the schedule for the module.
This includes:
day
location
startTime
comments
How ScheduleList works:
- An empty
ScheduleList
is created when a module is constructed. - When
addClass
is called inmodule
,ScheduleList
parses the input from the user and splits the information into the relevant information. The information is then used to generate a new instance ofSchedule
which is then added to the list.
Notes about ScheduleList
- ScheduleList checks that the input for the day of the week is only from the list of possible days:
MON
,TUE
,WED
,THU
,FRI
,SAT
,SUN
. All other inputs will result in an exception being thrown. - When a new
Schedule
class is called,ScheduleList
ensures that the length of venue and comments are less than 16 characters in length. This is to ensure that it fits within its time slot within the Timetable when printed.
Adding Schedule to scheduleList
- When addclass() is called, schedule first checks if there is a duplicate schedule currently in the list. This is done by going through the whole list and checking if a schedule has the same time slot. If there exists a schedule in the same time slot, an error message is printed.
- If it is an empty timeslot, schedule list parses the input and checks for formatting errors within the input.
- A new instance of Schedule is generated and added to the schedule list.
API : task.tasklist
How the TaskList
component works:
TaskList
stores all tasks in anArrayList<Task>
.- When the
addTask()
method is called, the methodgetDate()
will return thedate
string from the user input - The method
removeDate()
will return thedescription
string from the user input by removing the date component in the user input. - Then store it as a local variable of a
String
type. - The
String
variables will then be passed to instantialize a newTask
object. - This
Task
object will then be stored in theArrayList
in theTaskList
object. - The methods
weeklyTaskList()
,monthlyTaskList()
andyearlyTaskList()
returns anArrayList
which contains theTask
objects of deadline within a week, a month and a year respectively. - The methods
sortTaskListByDate()
andsortTaskListByStatus()
will sort the currentTaskList
object by ascending order ofDeadline
and completion status respectively - The
ArrayList
returned by the above methods can then be passed toprintTasks()
which will calltoString()
in eachTask
object and print to theOutput Stream
.
API : task.task
Task
object stores the following for each task:
description
date
isDone
isLate
deadline
How the Task
component works:
- Whenever the
Task
object is instantiated, theattributes
listed above will be initialized by thesetter
methods:setDescription()
,setDate()
,setDone()
,setLate()
andsetDeadline()
. - When calling
printAllTask()
,printWeeklyTask()
,printMonthlyTask()
inOverallTaskList
the methodupdateOverdue()
will be called which checks for the truth value of theboolean
attributeisDone
and also whether the current date and time of the system clock is after thedeadline
of theTask
object. - If
isDone
isFALSE
and thedeadline
is later than the current date and time,updateOverdue()
will set the attributeisLate
of the currentTask
object toTRUE
. - Calling the toString converts the task information in the Task object to printable String.
Note:
- The printTask() call in the sequence diagram is a generalised method from:
OverallTaskList#addAllNormalTasks()
,OverallTaskList#addAllGradableTasks()
andTaskList#printTasks()
- Any call from the methods above will result in the following sequence in the sequence diagram.
API : task.OverallTasklist
Class diagram for OverallTask and OverallTaskList
Note: Some methods are omitted from the class diagram to improve clarity
The OverallTaskList
class is instantiated from ListParser
only when the end user needs to list available tasks in
a Semester
.
How the OverallTaskList
class works:
-
OverallTask
objects (explained further underOverallTask
) are stored in an ArrayListoverallTaskList.
-
Both
Task
andGradableTask
objects are converted toOverallTask
objects first before being inserted intoOverallTaskList
. -
When the
OverallTaskList
object is instantiated, aModuleList
object from a semester is passed to its constructor. -
The constructor calls the method
addAllModuleListTasks(module list)
which converts and adds all the tasks in the module list intoOverallTaskList
. -
Once the object is instantiated, the following methods can be called to sort and print the tasks in the ArrayList
overallTaskList
. All sorting and filtering is done viaJava Streams
, and method details are omitted.sortByDateAndPrint() - Print all tasks sorted by deadline
sortByStatusAndPrint() - Print all tasks sorted by status(done)
printWeeklyTasks() - Print tasks due in a week
printMonthlyTasks() - Print tasks due in a month
printYearlyTasks() - Print tasks due in a year
printAllTasks() - Print all tasks without sorting
printGradableTasks() - Print all gradable tasks
printNormalTasks() - Print all non-gradable tasks
Notes about OverallTaskList
- Once
ListParser
is done using the object, it is deleted and the task list is not stored anywhere. The reason for this is to reduce coupling between objects and remove the need to update separate task lists whenever tasks are added toModules
.
API : task.OverallTask
OverallTask
objects are stored in a OverallTaskList
object when the end user needs to list available tasks in
a Semester
. It stores information from GradableTask/Task
objects together with their module name.
OverallTask
object stores the following for each task:
description
date
isDone
isLate
deadline
isGradable
weightage
moduleName
How the OverallTask
component works:
-
It inherits from
Task
, with additional attributesisGradable
,weightage
andmoduleName
. -
The attributes
isGradable
,weightage
are added to provide more information for gradable tasks, whilemoduleName
is added to display module information. -
It can be instantiated with 2 different constructors:
-
During instantiation, information from
Task/GradableTask
objects are added to theOverallTask
object together with theirmoduleName
. -
Calling the
toString()
method generates a string containing task information together with itsmoduleName
.
Target User Profile:
- NUS student
- is reasonably comfortable using CLI apps
- can type fast
- prefers typing to mouse interactions
- prefer desktop apps over other types
Value Proposition:
A centralized platform which allows NUS Students to carry out their learning management without needing to frequently
switch between multiple tools or applications such as NUSMods, Luminus, Sticky Notes etc.
Version | As a ... | I want to ... | So that I can ... |
---|---|---|---|
v1.0 | Forgetful student | have an app to automatically list out my deadlines for each week | prioritise my work. |
v1.0 | Busy student | be reminded of my tasks | remember all my tasks. |
v1.0 | Student | see which assignments are completed and which are not | know my progress in this module. |
v1.0 | User | visualize my timetable | reference it easily. |
v1.0 | User of a to-do app | see the deadline of each task | prioritise my work. |
v2.0 | Student | be able to update module details | update outdated information. |
v2.0 | Student | easily track my CAP progression | gauge how well I am doing. |
v2.0 | Student | have quick access to upcoming gradable assignments | be sure everything is prepared for. |
v2.0 | Student | be able to know what classes i have up next | prepare for them in time. |
v2.1 | University student | see the weightage of the modules | place emphasis/focus on certain work when there is a lack of time. |
- Should work on any mainstream OS as long as it has Java 11 or above installed.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be
able to accomplish most of the tasks faster using commands than using the mouse.
- Command Line Interface(CLI) - A command-line interface (CLI) processes commands to a computer program in the form of lines of text(From Wikipedia).
- Mainstream Operating Systems(OS) - Windows, Linux, Unix, OS-X
- Visualise - Snapshot of the graded components which the module is made up of and their individual percentages.
Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on, testers are expected to do more exploratory testing.
- Initial launch
- Download the JAR file and copy it into an empty folder
- Open up your terminal, and navigate to the folder containing the JAR file
- Type the following command:
Note: It is important that you navigate to the directory containing the JAR file first before running the application, as it may affect the location of the save file.java -jar NoCap.jar
- Automatic saving
- Carry out any command that adds/modifies data in the application, e.g
add CS2102
, or simply exit the application using the commandbye
. - Expected: A JSON file is created/updated automatically in the data folder located in folder containing the JAR
file, provided the instructions in
Launch
is followed correctly.
- Carry out any command that adds/modifies data in the application, e.g
- No save file exists
- Prerequisites: Make sure the data folder does not exist/is deleted from the folder containing the JAR file.
- Run the application as stated in
Launch
- Expected: Application starts with an empty template and shows the following message:
No save file found, starting with an empty template Welcome to NoCap
- Save file exists
- Prerequisites: Make sure that a save file already exists in the data folder that is located in the folder
containing the JAR file. If not, simply carry out any command that adds/modifies data in the application,
e.g
add CS2102
(see 1. Automatic Saving), and the save file will be created automatically. - Run the application as stated in
Launch
- Expected: Application loads the save file when starting the application and shows the following message:
Data loaded successfully Welcome to NoCap
- Prerequisites: Make sure that a save file already exists in the data folder that is located in the folder
containing the JAR file. If not, simply carry out any command that adds/modifies data in the application,
e.g
- Corrupted save file
- Prerequisites: Make sure that a save file already exists in the data folder that is located in the folder
containing the JAR file If not, simply carry out any command that adds/modifies data in the application,
e.g
add CS2102
(see 1. Automatic Saving), and the save file will be created automatically. - To simulate data corruption, remove lines to cause syntax errors in the JSON file, such as lines containing
{
and}
. - Run the application
- Expected: An error message is shown and application starts with an empty template, showing the message below:
Error reading save file, creating new template Welcome to NoCap
- Prerequisites: Make sure that a save file already exists in the data folder that is located in the folder
containing the JAR file If not, simply carry out any command that adds/modifies data in the application,
e.g
- Run the command
list semesters
- Expected: 10 pre-loaded semesters from Y1S1 to Y5S2 presented in the following message:
1 : Y1S1 2 : Y1S2 3 : Y2S1 4 : Y2S2 5 : Y3S1 6 : Y3S2 7 : Y4S1 8 : Y4S2 9 : Y5S1 10 : Y5S2
- On first use, NoCap defaults to Y1S1 semester
- On subsequent launches, NoCap defaults to the last accessed semester
- Switching between semesters
- Choose a semester index from 1-10 with reference to
list semesters
- Run the command
switch <index>
to switch to the new semester - For example, if '3' is chosen, running
switch 3
gives the following expected message:Semester successfully switched You are now accessing semester: Y2S1
- Choose a semester index from 1-10 with reference to
-
Prerequisite: Module should already exist.
-
Adding a module that does not exist.
- Run the command:
add CS2040C
- Expected:
Module successfully added: 1 Module name: CS2040C CREDITS: 0 --------------------------- SCHEDULE: --------------------------- GRADE: NIL TASKS: [] BREAKDOWN:
- Run the command:
-
Adding a module that already exists.
- Prerequisite: module with the same name exists in current semester list. e.g. CS2040C
- Run the command
add CS2040C
- Expected:
This module already exists!
-
Adding a module that is longer than 16 Characters.
Expected:
Module name must be less than 17 characters
- Prerequisite: Module index should already exist in the ModuleList
- Deleting a module with a valid index.
- Run the command:
delete 1
- Expected:
CS2040C has been successfully deleted Remaining Modules are:
- Run the command:
- Deleting a module with an invalid index
- Run the command:
delete 999
- Expected
Invalid number value
- Run the command:
- Prerequisite: Semester should exist.
- Run the command:
list module
- Expected:
1 Module name: CS2113T CREDITS: 4 --------------------------- SCHEDULE: --------------------------- GRADE: B+ TASKS: [] BREAKDOWN: 2 Module name: CS1010 CREDITS: 0 --------------------------- SCHEDULE: --------------------------- GRADE: NIL TASKS: [] BREAKDOWN:
- List tasks when there are no available tasks
- Prerequisites: There should be no tasks added to modules in the current semester yet.
- Run the command
list task
- Expected: No tasks are shown and the following message is shown:
All tasks: You have no tasks
- List tasks with optional arguments
- Prerequisites: There should be tasks added to modules in the semester beforehand. Can be checked by
running
list task
. If there are no tasks in the semester, add in tasks first(including both gradable and non-gradable tasks) - Run list task command with optional arguments, as specified in the user guide, e.g.
list task gradable
- Expected: Tasks are shown accordingly, depending on the optional argument
- Prerequisites: There should be tasks added to modules in the semester beforehand. Can be checked by
running
- Prerequisite: Module CS1010 already exists.
- Adding a valid Task to CS1010.
- Run the command:
/m cs1010 addtask as01 /by 11/12/2021 2359
- Expected:
Added new task to CS1010 [ ] as01 by: 11 Dec 2021 11:59 PM
- Run the command:
- Adding a Task with an invalid syntax.
- Run the command :
/m cs1010 addtask as01 /by 11-12-21 2359
- Expected:
Wrong date format input! Format: dd/MM/yyyy hhmm
- Run the command:
/m cs1010 addtask /by 11/12/2021 2359
- Expected:
You are missing a description!
- Run the command :
-
Prerequisite: Module CS2040C should already exist.
-
Adding a valid GradableTask to module.
- Run the command:
/m cs2040c addgradable finals /by 11/11/2021 1000 /w 50
- Expected:
Added new task to CS2040C finals by: 11 Nov 2021 10:00 AM Weightage 50% [ ] BREAKDOWN: <======================50%=======================> ################################################## |-----------------------1------------------------| 1: finals 1 finals by: 11 Nov 2021 10:00 AM Weightage 50% [ ]
- Run the command:
-
Adding a GradableTask with an invalid syntax.
- Run the command :
/m cs2040c addgradable finals /by 00/00/00 /w 50
- Expected:
Wrong date format input! Format: dd/MM/yyyy hhmm BREAKDOWN:
- Run the command :
- Prerequisite: module CS2040C should already exist.
- Run the command:
/m cs2040c addgradable finals /by 11/11/2021 1000 /w 50
- Run the command:
/m cs2040c addgradable midterms /by 11/09/2021 1300 /w 50
- Run the command:
/m CS2040C list gradable
- Expected:
BREAKDOWN: <======================50%=======================><======================50%=======================> ##################################################@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |-----------------------1------------------------||-----------------------2------------------------| 1: finals 2: midterms 1 finals by: 11 Nov 2021 10:00 AM Weightage 50% [ ] 2 midterms by: 11 Sep 2021 01:00 PM Weightage 50% [ ]
- Prerequisites: module CS2040C exists without any existing task.
- Add a new task:
/m cs2040c addtask testcase 1 /by 11/11/2021 0000
. - Editing description:
- Run the command:
/m cs2040c editdesc 1 testcase 2
. - Run the command:
/m cs2040c list
. - Expected:
Task List for CS2040C: There are 1 tasks 1.[ ] testcase 2 by: 11 Nov 2021 12:00 AM
- Run the command:
- Editing deadline:
- Run the command:
/m cs2040c editdate 1 12/12/2022 1212
. - Run the command:
/m cs2040c list
. - Expected:
Task List for CS2040C: There are 1 tasks 1.[ ] testcase 2 by: 12 Dec 2022 12:12 PM
- Run the command:
- Prerequisites: module CS2040C exists without any existing task.
- Add a new task:
/m cs2040c addtask testcase 1 /by 11/11/2021 0000
. - Deleting a task without matching keyword:
- Run the command:
/m cs2040c deletetask apple
. - Expected:
Task with the specified keyword not found!
- Run the command:
- Deleting a task with the matching keyword:
- Run the command:
/m cs2040c deletetask test
. - Expected:
The following task(s) are found: 1: testcase 2 Please choose a task to perform the action, or press x to cancel:
- Enter input:
1
. - Expected:
testcase 1 has been deleted
.
- Run the command:
- Prerequisites: module CS2040C exists without any existing task.
- Add a new task:
/m cs2040c addtask testcase 1 /by 11/11/2021 0000
. - Run the command:
/m cs2040c done 1
. - Expected:
Task is completed: [X] testcase 1 by: 11 Nov 2021 12:00 AM
- Prerequisites: module CS2040C exists without any existing task.
- Add a new task:
/m cs2040c addtask testcase 1 /by 11/11/2021 0000
. - Add a new task:
/m cs2040c addtask testcase 2 /by 12/12/2022 1212
. - Run the command:
/m cs2040c list
. - Expected:
Task List for CS2040C: There are 2 tasks 1.[ ] testcase 1 by: 11 Nov 2021 12:00 AM 2.[ ] testcase 2 by: 12 Dec 2022 12:12 PM
- Prerequisites: module CS2040C exists without any task/class/credit.
- Run the command:
/m cs2040c addgrade A
- Expected:
Module grade successfully added: Module name: CS2040C CREDITS: 0 --------------------------- SCHEDULE: --------------------------- GRADE: A TASKS: [] BREAKDOWN:
- Prerequisites: module CS2040C exists and has an assigned grade.
- Run the command:
/m cs2040c deletegrade
. - Expected:
Module grade has been successfully deleted
.
- Prerequisites: module CS2040C exists without any task/class/grade.
- Run the command:
/m cs2040c addcredit 4
- Expected:
Module credits successfully added: Module name: CS2040C CREDITS: 4 --------------------------- SCHEDULE: --------------------------- GRADE: NIL TASKS: [] BREAKDOWN:
- Prerequisite: module CS2040C exists.
- Adding a class with valid syntax.
- Run the command:
/m CS2040C addclass MON/1000/ZOOM/LECT
- Expected:
Module Class successfully added: 1. Day: MON Start Time: 1000 Location: ZOOM Comments: LECT
- Run the command:
- Adding a class that occupies the same timeslot.
- Run the command:
/m CS2040C addclass MON/1000/ZOOM/TUT
- Expected:
A class already exists in this timeslot!
- Run the command:
- Select an existing class index with reference to the command
/m <module> info
. - Run the command
/m <module> deleteclass <index>
. - Expected: Corresponding class is deleted from module schedule.
- Run the command
timetable
- Expected: Prints out a timetable of all classes from 0800 to 1700 periods
- Run the command
cap
- If no credit is added for any module in the semester, expected:
Unable to calculate cap as no credit assigned to any existing module
- Else, the cap is calculated accordingly and printed.
- Run the command
allcap
- Expected: prints out the aggregate cumulative CAP and respective CAP of each semester
- Semesters with no credit assigned for any module will default to 0.00 CAP