diff --git a/.gitignore b/.gitignore index f69985ef1f..b9d68580fa 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,8 @@ src/main/resources/docs/ *.iml bin/ +# Data files +data/* + /text-ui-test/ACTUAL.txt text-ui-test/EXPECTED-UNIX.TXT diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3dc7aeff56 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: command.NoCap + diff --git a/README.md b/README.md index 4eef34421f..b3dc277757 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Duke project template +# NoCap -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. +This project is based on Duke, 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. ## Setting up in Intellij @@ -9,21 +9,16 @@ Prerequisites: JDK 11 (use the exact version), update Intellij to the most recen 1. **Ensure Intellij JDK 11 is defined as an SDK**, as described [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk) -- this step is not needed if you have used JDK 11 in a previous Intellij project. * In the same dialog, you _may_ have to set the Project language level field to the SDK default option. 1. **Import the project _as a Gradle project_**, as described [here](https://se-education.org/guides/tutorials/intellijImportGradleProject.html). -1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/duke/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below: +1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/nocap/NoCap.java` file, right-click it, and choose `Run NoCap.main()`. If the setup is correct, you should see something like the below: ``` > Task :compileJava > Task :processResources NO-SOURCE > Task :classes - - > Task :Duke.main() - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - - What is your name? + + > Task :NoCap.main() + Data loaded successfully + Welcome to NoCap + You are now accessing semester: Y1S1 ``` Type some word and press enter to let the execution proceed to the end. @@ -40,7 +35,7 @@ Prerequisites: JDK 11 (use the exact version), update Intellij to the most recen ### JUnit tests -* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template. +* A skeleton JUnit test (`src/test/java/seedu/duke/NoCapTest.java`) is provided with this project template. * If you are new to JUnit, refer to the [JUnit Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/junit.html). ## Checkstyle @@ -54,12 +49,7 @@ The project uses [GitHub actions](https://github.com/features/actions) for CI. W ## Documentation -`/docs` folder contains a skeleton version of the project documentation. - -Steps for publishing documentation to the public: -1. If you are using this project template for an individual project, go your fork on GitHub.
- If you are using this project template for a team project, go to the team fork on GitHub. -1. Click on the `settings` tab. -1. Scroll down to the `GitHub Pages` section. -1. Set the `source` as `master branch /docs folder`. -1. Optionally, use the `choose a theme` button to choose a theme for your documentation. +`/docs` folder contains the following documentation for `NoCap`: +* [About Us](/docs/AboutUs.md) +* [Developer Guide](/docs/DeveloperGuide.md) +* [User Guide](/docs/UserGuide.md) diff --git a/build.gradle b/build.gradle index b0c5528fb5..31b16c207a 100644 --- a/build.gradle +++ b/build.gradle @@ -10,8 +10,14 @@ repositories { } 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' + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.8.1' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.8.1' + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.0' + implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.13.0' + // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.13.0' + + } test { @@ -29,11 +35,11 @@ test { } application { - mainClassName = "seedu.duke.Duke" + mainClassName = "command.NoCap" } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "NoCap" archiveClassifier = null } @@ -43,4 +49,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..110a7fab8e 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -2,8 +2,8 @@ Display | Name | Github Profile | Portfolio --------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Yeat Nai Jie | [Github](https://github.com/naijie2108) | [Portfolio](team/naijie2108.md) +![](https://via.placeholder.com/100.png?text=Photo) | Yap Joon Siong | [Github](https://github.com/yapjoonsiong) | [Portfolio](team/yapjoonsiong.md) +![](https://via.placeholder.com/100.png?text=Photo) | Yam Jin Ee Dmitri | [Github](https://github.com/DmitriYam) | [Portfolio](team/dmitriyam.md) +![](media/edwin-profile.jpg) | Yeo Zi Hao Edwin | [Github](https://github.com/yzhedwin) | [Portfolio](team/yzhedwin.md) +![](https://via.placeholder.com/100.png?text=Photo) | Zeng Jiexiong | [Github](https://github.com/jiexiong-zeng) | [Portfolio](team/jiexiong-zeng.md) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 64e1f0ed2b..603f11f651 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,38 +1,821 @@ # Developer Guide +## Navigation + +* [Acknowledgements](#acknowledgements) +* [Design and Implementation](#design--implementation) + * [Parser](#parser) + * [Storage](#storage) + * [Semester](#semester) + * [Module](#module) + * [Schedule List](#schedulelist) + * [Task list](#tasklist) + * [Task](#task) + * [Overall Task List](#overalltasklist) + * [Overall Task](#overalltask) +* [Product Scope](#appendix-a-product-scope) +* [User Stories](#appendix-b-user-stories) +* [Non-Functional Requirements](#appendix-c-non-functional-requirements) +* [Glossary](#appendix-d-glossary) +* [Instructions for Manual Testing](#appendix-e-instructions-for-manual-testing) + ## Acknowledgements -{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} +Third party libraries: + +- [Jackson Databind](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind) +- [Jackson Datatype-jsr310](https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310) +- [Jackson Annotations](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations) + +# Design & Implementation + +## Parser + +**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. + +![alt_text](media/ParserClassDiagram.JPG) + +How the parsing works: + +* `NoCap` passes the user input to `Parser` 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 filtered `OverallTaskList` and `TaskList` accordingly. +* Otherwise, the taskDescription is passed to `Command` which calls the corresponding commands in `SemesterList`, + `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 as + `ParserSearch#getTaskFromIndex()` and `ParserSearch#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 + by `Task`. Additional date formats can be added in `DateParser#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 +![alt_text](media/ParserSequenceDiagram.png) +**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 to `task 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 to `sortbydate`. + +**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: + +![alt_text](media/splitStringDiagram.JPG) +

+ +## Storage + +**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: + +![alt_text](media/StorageEncoderSequenceDiagram.png "image_tooltip") + +1. The static method `encodeAndSaveSemesterListToJson()` from `StorageEncoder` is called when NoCap data needs to be + saved +2. If the save file directory has not been created yet, it is first created in order to store the save file +3. Similarly, an empty file is created to store the data if it has not been created yet +4. Then, the object `SemesterList` which holds all NoCap information is converted into a JSON file with an `ObjectMapper` + object from the `jackson-databind` library +5. Upon completion, the data file is saved in a default data directory. + +How the `StorageDecoder` class works: + +![alt_text](media/StorageDecoderSequenceDiagram.png "image_tooltip") + +1. The static method `decodeJsonToSemesterList()` from `StorageDecoder` is called when NoCap data needs to be loaded + from the save file +2. If there is no save file available in the default data directory, a new `SemesterList `object is created and returned + to the caller +3. Otherwise, an `ObjectMapper` object from the `jackson-databind` library is used to deserialize the JSON save file + into a `SemesterList` object to be returned to the caller +

+ +## Semester + +**API** : `semester` + +![alt_text](media/SemesterListDiagram.jpg) + +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` and `Semester` +* `SemesterList` is used to compute and store the cumulative CAP of all semesters and also stores 10 `Semester` objects +* Each `Semester` object stores and computes the individual CAP for the semester, while also storing a `ModuleList` of + the `Module` objects taken during the semester +* The computation of the CAP for both `SemesterList` and `Semester` is automatically done when a grade/credit as added + to a `Module` object within any semester + +This is how CAP is computed: + +![alt_text](media/capComputationSequenceDiagram.png) + +* When `commandAddGrade()` or `commandAddCredit()` is called in Parser, `addGrade(description)` + or `addCredit(description)` respectively are called in `Module`, setting the module’s `grade`, `points` and `credits` + to their corresponding values. +* Then, `updateCap()` is called in `Semester` with the newly set `grade`/`credits` values in `Module`, followed + by `updateCap()` in `SemesterList` with the newly set `points`/`credits` values in `Semester`. +

+ +## Module + +**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. + +![moduleListClassDiagram](media/moduleListClassDiagram.png) + +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: + +1. moduleName +2. letterGrade +3. credits +4. points +5. TaskList +6. GradableTaskList +7. 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. + +# ![modulePrintTimetableSeq](media/ModuleListseq.png) + +How printing a timetable works: + +1. 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. +2. Each iteration of the loop can result in 1 of 3 cases: +1. It is at a border. When this happens a "#" character is printed to the console which denotes a border. +2. It is empty. When this happens a " "(blank) character is printed to the console. +3. It contains module information. When this happens, getMoudleName() , getModuleLocation() and getModuleComment() is + called. The information is then printed onto the console. +

+ +## ScheduleList + +**API** : `schedule` + +ScheduleList consists of all data for the schedule for the module. + +This includes: + +1. `day` +2. `location` +3. `startTime` +4. `comments` + +How ScheduleList works: + +1. An empty `ScheduleList` is created when a module is constructed. +2. When `addClass` is called in `module` , `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 of `Schedule` 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. + +![scheduleseq](media/scheduleseq.png) + +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. +

+ +## TaskList + +**API** : `task.tasklist` + +![alt_text](media/TaskClassDiagram.png) + +How the `TaskList` component works: + +![](media/TaskListSequenceDiagram.png) + +1. `TaskList` stores all tasks in an `ArrayList`. +2. When the `addTask()` method is called, the method `getDate()` will return the `date` string from the user input +3. The method `removeDate()` will return the `description` string from the user input by removing the date component in + the user input. +4. Then store it as a local variable of a `String` type. +5. The `String` variables will then be passed to instantialize a new `Task` object. +6. This `Task` object will then be stored in the `ArrayList` in the `TaskList` object. +7. The methods `weeklyTaskList()`, `monthlyTaskList()` and `yearlyTaskList()` returns an `ArrayList` which contains + the `Task` objects of deadline within a week, a month and a year respectively. +8. The methods `sortTaskListByDate()` and `sortTaskListByStatus()` will sort the current `TaskList` object by ascending + order of `Deadline` and completion status respectively +9. The `ArrayList` returned by the above methods can then be passed to `printTasks()` which will call `toString()` in + each `Task` object and print to the `Output Stream`. +

+ +## Task + +**API** : `task.task` + +`Task` object stores the following for each task: -## Design & implementation +1. `description` +2. `date` +3. `isDone` +4. `isLate` +5. `deadline` -{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +How the `Task` component works: +![](media/TaskSequenceDiagram.png) -## Product scope -### Target user profile +1. Whenever the `Task` object is instantiated, the `attributes` listed above will be initialized by the `setter` + methods: `setDescription()`, `setDate()`, `setDone()`, `setLate()` and `setDeadline()`. +2. When calling `printAllTask()`, `printWeeklyTask()`, `printMonthlyTask()` in `OverallTaskList` the + method `updateOverdue()`will be called which checks for the truth value of the `boolean` attribute `isDone` and also + whether the current date and time of the system clock is after the `deadline` of the `Task` object. +3. If `isDone` is `FALSE` and the `deadline` is later than the current date and time, `updateOverdue()` will set the + attribute `isLate` of the current `Task` object to `TRUE`. +4. Calling the toString converts the task information in the Task object to printable String. -{Describe the target user profile} +Note: -### Value proposition +* The printTask() call in the sequence diagram is a generalised method from: `OverallTaskList#addAllNormalTasks()` + , `OverallTaskList#addAllGradableTasks()` and `TaskList#printTasks()` +* Any call from the methods above will result in the following sequence in the sequence diagram. +

-{Describe the value proposition: what problem does it solve?} +## OverallTaskList -## User Stories +**API** : `task.OverallTasklist` + +![alt_text](media/OverallTaskClassDiagram.png) + +_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: + +1. `OverallTask` objects (explained further under `OverallTask`) are stored in an ArrayList `overallTaskList.` +2. Both `Task` and `GradableTask` objects are converted to `OverallTask` objects first before being inserted into + `OverallTaskList`. +3. When the `OverallTaskList` object is instantiated, a `ModuleList` object from a semester is passed to its + constructor. + + + ![alt_text](media/OverallTaskListConstructorSequenceDiagram.png "image_tooltip") +4. The constructor calls the method `addAllModuleListTasks(module list)` which converts and adds all the tasks in the + module list into `OverallTaskList`. +5. 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 via `Java 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 + to `Modules`. +

+ +## OverallTask + +**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: + +1. `description` +2. `date` +3. `isDone` +4. `isLate` +5. `deadline` +6. `isGradable` +7. `weightage` +8. `moduleName` + +How the `OverallTask` component works: + +1. It inherits from `Task`, with additional attributes `isGradable`, `weightage` and `moduleName`. +2. The attributes `isGradable`, `weightage` are added to provide more information for gradable tasks, while `moduleName` + is added to display module information. +3. It can be instantiated with 2 different constructors: + * `OverallTask(task: Task, moduleName: String)` - Instantiates using a `Task` object
+ ![alt_text](media/OverallTaskConstructorTaskSequenceDiagram.png "image_tooltip") + * `OverallTask(gradableTask:GradableTask, moduleName: String)` - Instantiates using a `GradableTask `object
+ ![alt_text](media/OverallTaskConstructorGradableTaskSequenceDiagram.png "image_tooltip") + +4. During instantiation, information from `Task/GradableTask` objects are added to the `OverallTask` object together + with their `moduleName` . +5. Calling the `toString()` method generates a string containing task information together with its `moduleName`. +

+ +# Appendix A: Product Scope + +**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. +

+ +# Appendix B: User Stories |Version| As a ... | I want to ... | So that I can ...| |--------|----------|---------------|------------------| -|v1.0|new user|see usage instructions|refer to them when I forget how to use the application| -|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| +|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.| + +

+ +# Appendix C: Non Functional Requirements + +1. Should work on any mainstream OS as long as it has Java 11 or above installed. +2. 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. +

+ +# Appendix D: Glossary + +* **Command Line Interface(CLI)** - A command-line interface (CLI) processes commands to a computer program in the form + of lines of text(From [Wikipedia](https://en.wikipedia.org/wiki/Command-line_interface)). +* **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. +

+ +# Appendix E: Instructions for Manual Testing + +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. + +## Launch + +1. Initial launch + 1. Download the JAR file and copy it into an empty folder + 2. Open up your terminal, and navigate to the folder containing the JAR file + 3. Type the following command: + ``` + java -jar NoCap.jar + ``` + **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. + +## Saving/Loading data + +1. Automatic saving + 1. Carry out any command that adds/modifies data in the application, e.g `add CS2102`, or simply exit the + application using the command `bye`. + 2. 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. +2. No save file exists + 1. Prerequisites: Make sure the data folder does not exist/is deleted from the folder containing the JAR file. + 2. Run the application as stated in `Launch` + 3. Expected: Application starts with an empty template and shows the following message: + ``` + No save file found, starting with an empty template + Welcome to NoCap + ``` +3. Save file exists + 1. 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. + 2. Run the application as stated in `Launch` + 3. Expected: Application loads the save file when starting the application and shows the following message: + ``` + Data loaded successfully + Welcome to NoCap + ``` +4. Corrupted save file + 1. 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. + 2. To simulate data corruption, remove lines to cause syntax errors in the JSON file, such as lines containing `{` and `}`. + 3. Run the application + 4. 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 + ``` + +## Listing semesters + +1. Run the command `list semesters` +2. 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 + ``` + +## Switching semesters + +1. On first use, NoCap defaults to Y1S1 semester +2. On subsequent launches, NoCap defaults to the last accessed semester +3. Switching between semesters + 1. Choose a semester index from 1-10 with reference to `list semesters` + 2. Run the command `switch ` to switch to the new semester + 3. For example, if '3' is chosen, running `switch 3` gives the following expected message: + ``` + Semester successfully switched + You are now accessing semester: Y2S1 + ``` + +## Adding a module to a semester + +1. Prerequisite: Module should already exist. +2. Adding a module that does not exist. + 1. Run the command: `add CS2040C` + 2. Expected: + ``` + Module successfully added: + 1 + Module name: CS2040C + CREDITS: 0 + --------------------------- + SCHEDULE: + --------------------------- + GRADE: NIL + TASKS: [] + BREAKDOWN: + ``` +3. Adding a module that already exists. + 1. Prerequisite: module with the same name exists in current semester list. e.g. CS2040C + 2. Run the command `add CS2040C` + 3. Expected:`This module already exists!` + +4. Adding a module that is longer than 16 Characters. + + Expected: `Module name must be less than 17 characters` + +## Deleting a module from a semester + +1. Prerequisite: Module index should already exist in the ModuleList +2. Deleting a module with a valid index. + 1. Run the command: `delete 1` + 2. Expected: + ``` + CS2040C has been successfully deleted + Remaining Modules are: + ``` +3. Deleting a module with an invalid index + 1. Run the command: `delete 999` + 2. Expected + ``` + Invalid number value + ``` + +## Listing all modules in a semester + +1. Prerequisite: Semester should exist. +2. Run the command: `list module` +3. 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 in a semester + +1. List tasks when there are no available tasks + 1. Prerequisites: There should be no tasks added to modules in the current semester yet. + 2. Run the command `list task` + 3. Expected: No tasks are shown and the following message is shown: + ``` + All tasks: + You have no tasks + ``` +2. List tasks with optional arguments + 1. 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) + 2. Run list task command with optional arguments, as specified in the user guide, e.g. `list task gradable` + 3. Expected: Tasks are shown accordingly, depending on the optional argument + +## Adding a task to a module + +1. Prerequisite: Module CS1010 already exists. +2. Adding a valid Task to CS1010. + 1. Run the command: `/m cs1010 addtask as01 /by 11/12/2021 2359` + 2. Expected: + ``` + Added new task to CS1010 + [ ] as01 by: 11 Dec 2021 11:59 PM + ``` +3. Adding a Task with an invalid syntax. + 1. Run the command : `/m cs1010 addtask as01 /by 11-12-21 2359` + 2. Expected: + ``` + Wrong date format input! + Format: dd/MM/yyyy hhmm + ``` + 3. Run the command: `/m cs1010 addtask /by 11/12/2021 2359` + 4. Expected: + ``` + You are missing a description! + ``` + +## Adding a GradableTask to module + +1. Prerequisite: Module CS2040C should already exist. +2. Adding a valid GradableTask to module. + 1. Run the command: `/m cs2040c addgradable finals /by 11/11/2021 1000 /w 50` + 2. 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% [ ] + ``` + +3. Adding a GradableTask with an invalid syntax. + 1. Run the command : `/m cs2040c addgradable finals /by 00/00/00 /w 50` + 2. Expected: + ``` + Wrong date format input! + Format: dd/MM/yyyy hhmm + BREAKDOWN: + ``` + +## Listing all gradable tasks + +1. Prerequisite: module CS2040C should already exist. +2. Run the command: `/m cs2040c addgradable finals /by 11/11/2021 1000 /w 50` +3. Run the command: `/m cs2040c addgradable midterms /by 11/09/2021 1300 /w 50` +4. Run the command: `/m CS2040C list gradable` +5. 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% [ ] + + ``` + +## Editing a task + +1. Prerequisites: module CS2040C exists without any existing task. +2. Add a new task: `/m cs2040c addtask testcase 1 /by 11/11/2021 0000`. +3. Editing description: + 1. Run the command: `/m cs2040c editdesc 1 testcase 2`. + 2. Run the command: `/m cs2040c list`. + 3. Expected: + ``` + Task List for CS2040C: + There are 1 tasks + 1.[ ] testcase 2 by: 11 Nov 2021 12:00 AM + ``` +4. Editing deadline: + 1. Run the command: `/m cs2040c editdate 1 12/12/2022 1212`. + 2. Run the command: `/m cs2040c list`. + 3. Expected: + ``` + Task List for CS2040C: + There are 1 tasks + 1.[ ] testcase 2 by: 12 Dec 2022 12:12 PM + ``` + +## Deleting a task + +1. Prerequisites: module CS2040C exists without any existing task. +2. Add a new task: `/m cs2040c addtask testcase 1 /by 11/11/2021 0000`. +3. Deleting a task without matching keyword: + 1. Run the command: `/m cs2040c deletetask apple`. + 2. Expected: `Task with the specified keyword not found!` +4. Deleting a task with the matching keyword: + 1. Run the command: `/m cs2040c deletetask test`. + 2. Expected: + ``` + The following task(s) are found: + 1: testcase 2 + Please choose a task to perform the action, or press x to cancel: + ``` + 3. Enter input: `1`. + 4. Expected: `testcase 1 has been deleted`. + +## Marking a task as complete + +1. Prerequisites: module CS2040C exists without any existing task. +2. Add a new task: `/m cs2040c addtask testcase 1 /by 11/11/2021 0000`. +3. Run the command: `/m cs2040c done 1`. +4. Expected: + ``` + Task is completed: + [X] testcase 1 by: 11 Nov 2021 12:00 AM + ``` + +## Listing all tasks in a module + +1. Prerequisites: module CS2040C exists without any existing task. +2. Add a new task: `/m cs2040c addtask testcase 1 /by 11/11/2021 0000`. +3. Add a new task: `/m cs2040c addtask testcase 2 /by 12/12/2022 1212`. +4. Run the command: `/m cs2040c list`. +5. 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 + ``` + +## Adding a grade to a module + +1. Prerequisites: module CS2040C exists without any task/class/credit. +2. Run the command: `/m cs2040c addgrade A` +3. Expected: + ``` + Module grade successfully added: + Module name: CS2040C + CREDITS: 0 + --------------------------- + SCHEDULE: + --------------------------- + GRADE: A + TASKS: [] + BREAKDOWN: + ``` + +## Deleting a grade from a module + +1. Prerequisites: module CS2040C exists and has an assigned grade. +2. Run the command: `/m cs2040c deletegrade`. +3. Expected: `Module grade has been successfully deleted`. + +## Adding a credit to module + +1. Prerequisites: module CS2040C exists without any task/class/grade. +2. Run the command: `/m cs2040c addcredit 4` +3. Expected: + ``` + Module credits successfully added: + Module name: CS2040C + CREDITS: 4 + --------------------------- + SCHEDULE: + --------------------------- + GRADE: NIL + TASKS: [] + BREAKDOWN: + ``` + +## Adding a class to module + +1. Prerequisite: module CS2040C exists. +2. Adding a class with valid syntax. + 1. Run the command: `/m CS2040C addclass MON/1000/ZOOM/LECT` + 2. Expected: + ``` + Module Class successfully added: + 1. + Day: MON + Start Time: 1000 + Location: ZOOM + Comments: LECT + ``` +5. Adding a class that occupies the same timeslot. + 1. Run the command: `/m CS2040C addclass MON/1000/ZOOM/TUT` + 2. Expected: `A class already exists in this timeslot!` + +## Delete class from a module + +1. Select an existing class index with reference to the command `/m info`. +2. Run the command `/m deleteclass `. +3. Expected: Corresponding class is deleted from module schedule. -## Non-Functional Requirements +## Show timetable -{Give non-functional requirements} +1. Run the command `timetable` +2. Expected: Prints out a timetable of all classes from 0800 to 1700 periods -## Glossary +## Show semester cap -* *glossary item* - Definition +1. Run the command `cap` +2. If no credit is added for any module in the semester, expected: + ``` + Unable to calculate cap as no credit assigned to any existing module + ``` +3. Else, the cap is calculated accordingly and printed. -## Instructions for manual testing +## Show all cap -{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing} +1. Run the command `allcap` +2. Expected: prints out the aggregate cumulative CAP and respective CAP of each semester +3. Semesters with no credit assigned for any module will default to 0.00 CAP diff --git a/docs/README.md b/docs/README.md index bbcc99c1e7..d38bbbe686 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,25 @@ -# Duke +# NoCap -{Give product intro here} +## Introduction +NoCap (NC) is a **desktop app for managing modules taken in NUS, optimized for use via a Command Line Interface** (CLI). +If you can type fast, NC can get your module management tasks done faster than traditional GUI apps. It is the perfect +app for NUS students! -Useful links: -* [User Guide](UserGuide.md) -* [Developer Guide](DeveloperGuide.md) +## Useful links * [About Us](AboutUs.md) +* [User Guide](UserGuide.md) +* [DeveloperGuide](DeveloperGuide.md) + +## Downloads +Download the latest version of **NoCap** [here](https://github.com/AY2122S1-CS2113T-F11-1/tp/releases) + +## Acknowledgements +Third party libraries used: + +- [Jackson Databind](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind) +- [Jackson Datatype-jsr310](https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310) +- [Jackson Annotations](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations) + + + + diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..d638df1211 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,41 +2,630 @@ ## Introduction -{Give a product intro} +NoCap (NC) is a **desktop app for managing modules taken in NUS, optimized for use via a Command Line Interface** (CLI). +If you can type fast, NC can get your module management tasks done faster than traditional GUI apps. It is the perfect +app for NUS students! ## Quick Start -{Give steps to get started quickly} - 1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). +2. Download the latest version of `NoCap` from [here](https://github.com/AY2122S1-CS2113T-F11-1/tp/releases). +3. Move the downloaded NoCap.jar to an empty directory. +4. Navigate to this directory on the Command Prompt. +5. Run NoCap.jar using the command `java -jar NoCap.jar`. + +## Features + +### **Command format:** + +* Words in `<>` are the parameters to be supplied by the user. \ + e.g. `add ` `` is the name of the module supplied by the user. +* Parameters must be in the exact order as seen in the user guide. \ + e.g. if the command specifies `/m CG1111 addclass MON/0800/E1-03/tutorial` + , `/m CG1111 addclass 0800/E1-03/tutorial/MON/` + is not acceptable. +* Commands that require <> parameters must be supplied, if not an error will be thrown. e.g. if the command + specifies `/m addclass ` , `/m CG1111 addclass MON/0800/E1-03/` is not acceptable. +* Commands that require () parameters are optional. e.g. for `/m list (optional argument)`, `/m cs1010 list` is acceptable. +* All specifier commands are case-sensitive. e.g. `HELP`, `/M CG1111 ADDCLASS MON/0800/E1-03/tutorial` and `ADD CS2113T` + are invalid commands. + +### Viewing help : `help` + +Shows a message explaining how to use NoCap. + +### Listing semesters : `list semesters` + +Lists all preloaded semesters and their corresponding indexes. + +Example output: + +``` + 1 : Y1S1 + 2 : Y1S2 + 3 : Y2S1 + 4 : Y2S2 + 5 : Y3S1 + 6 : Y3S2 + 7 : Y4S1 + 8 : Y4S2 + 9 : Y5S1 + 10 : Y5S2 +``` + +### Switching semesters : `switch ` + +Switches the currently accessed semester to the corresponding input index. (refer to `list semesters` for the index). +The currently accessed semester on start up is your last accessed semester from any previous use. + +Examples: + +* `Switch 1` +* `Switch 2` + +### Adding module: `add ` + +Adds a module + +Examples: + +* `add CS2113T` +* `add MA1508` + +Note: + +* Module code can only contain up to 16 characters + +### Delete module: `delete ` + +Deletes a module corresponding to the input index. (refer to `list module` for indexes ) + +Examples: + +* `delete 1` +* `delete 2` + +Example output: + +``` +CS2113T has been successfully deleted +Remaining Modules are: +1 +Module name: CS2040C +CREDITS: 4 +--------------------------- +SCHEDULE: +--------------------------- +GRADE: A +TASKS: [] +BREAKDOWN: +``` + +### List module : `list module` + +Lists all added modules and their corresponding indexes. + +### Add task to module : `/m addtask /by (time)` + +* The `date` is in the format of dd/MM/yyyy, dd MM yyyy. +* The `time` is in the format of hhmm. +* The `description` can contain white spaces. + +Note: + +* If time is omitted, time will default to 0000 hrs. +* If duplicate task exist and has a different deadline, the existing task's deadline will be updated with the new + deadline. +* If duplicate task has same deadline, new task will be rejected by the program. +* The task description cannot contain any `/by` blocks. + +Example of usage: + +* `/m cs1010 addtask Remember to S/U /by 20/11/2020` + +Example of expected output: + +![alt_text](media/AddTaskOutput.jpg) + +**Warning** : + +* For every month, the program will take in 01 - 31 as an input for the day of the month. +* In the case when the month does not have 31 days, the program will treat any input after the last day of the month + until 31 as the last day. + +Example: + +* Date input as `31/02/2021` will be parsed as `28/02/2021` because there are only 28 days in the month of February. +* Date input as `31/04/2021` will be parsed as `30/04/2021` because there are only 30 days in the month of April + +### Add gradable task to module : `/m addgradable /by (time) /w ` + +Adds a Gradable Task to the module. + +* Refer to Add Task for deadline format. + +Note: + +* The weightage needs to be an Integer between 5 - 100. +* The total value of all gradable tasks within the module needs to be less than or equals to 100, else a error message + will be shown. +* The GradableTask description cannot contain any `/by` or `/w` blocks. + +Examples: + +* `/m CS2113 addgradable Finals /by 10/10/2010 1000 /w 30` +* `/m CS2113 addgradable assignments /by 10/10/2010 1000 /w 40` + +Expected output: + +![](media/GradableTaskOutput.jpg) + +Note: + +* The suffix of the Gradable Task `[]` shows if the task is completed. +* If it is completed, the suffix will show `[X]`. + +### Edit description of task : `/m editdesc ` + +Edit the description of a task at the specified index in the given module. + +Note: + +* An error message will be shown if the user input a duplicate description of an existing task. + +### Edit deadline of task : `/m editdate ` + +Edit the deadline of a task at the specified index in the given module. + +### Delete task from module : `/m deletetask ` + +Finds and list down tasks with the substring. Type corresponding index to delete the task. + +### Marks module task as done : `/m done ` + +Mark task as done. + +Other similar commands include: +Mark task as not done: `/m notdone ` +Mark gradable task as done:`/m gradabledone ` +Mark gradable task as not done:`/m gradablenotdone ` + +### Listing module tasks : `/m list (optional argument)` + +Shows a list of task of specified module. + +By default, all tasks in the module specified in the current semester are listed, but this can be customised by adding +optional arguments. + +(optional argument) includes: + +* gradable - Shows a list of gradable tasks in the module. +* sortbydate - Sort tasks by due date, the closest deadline have the higher priority in the list. does not print the + task list. +* sortbystatus - Sort tasks by status, finished tasks of lower priority. Does not print task list. +* w - list tasks due within the next week. +* m - list tasks due within the next month. +* y - list tasks due within the next year. + +Task Prefixes: + +* There are 2 prefixes in each Task defined as `[ ]` +* The first prefix is a `LATE` tag. If the task is overdue, the tag will show `[LATE]` +* The second prefix is a `DONE` tag. If the task is marked completed, the tag will show `[X]` +* Format will be as follows `[LATE][DONE]