diff --git a/README.md b/README.md
index 13f5c77403f..4b86357be6e 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,19 @@
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
+[![CI Status](https://github.com/AY2122S2-CS2103T-W15-3/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S2-CS2103T-W15-3/tp/actions)
![Ui](docs/images/Ui.png)
-* This is **a sample project for Software Engineering (SE) students**.
- Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+## Teaching Assistant Contact Helper (TACH)
+
+* This is a team project for a desktop application (called **TACH**) used by Computer Science (**CS**)
+Teaching Assistants (**TA**s) in NUS to manage and keep track of their students in
+the TAs tutorial groups.
+* **TACH** aims to solve problems of CS TAs regarding management and alleviate their workload by:
+ * Managing their students in an organised manner
+ * Easily access a student's contact details like their email or Telegram
+ * Find students either by their name or by their tutorial group
+* It is named `Teaching Assistant Contact Helper` (`TACH` for short) because it helps TAs with their students' contacts.
+* For detailed documentation of this project, see the
+**[TACH Product Website](https://ay2122s2-cs2103t-w15-3.github.io/tp/)**
+* This project is based on the AddressBook-Level3 project created by the
+[SE-EDU initiative](https://se-education.org).
+
diff --git a/build.gradle b/build.gradle
index be2d2905dde..a6587c12bf5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,6 +14,7 @@ targetCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
+ maven {url "https://sandec.jfrog.io/artifactory/repo"}
}
checkstyle {
@@ -25,6 +26,10 @@ test {
finalizedBy jacocoTestReport
}
+run {
+ enableAssertions = true
+}
+
task coverage(type: JacocoReport) {
sourceDirectories.from files(sourceSets.main.allSource.srcDirs)
classDirectories.from files(sourceSets.main.output)
@@ -44,6 +49,9 @@ dependencies {
String jUnitVersion = '5.4.0'
String javaFxVersion = '11'
+ compile 'org.apache.directory.studio:org.apache.commons.io:2.4'
+ compile "com.sandec:mdfx:0.2.4"
+
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..d9143e5719d 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -5,55 +5,48 @@ title: About Us
We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
-You can reach us at the email `seer[at]comp.nus.edu.sg`
+You can reach us at the email `vanessakhor19@gmail.com`
## Project team
-### John Doe
+### Low Jia Hao
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/LowJiaHao99)]
+[[portfolio](team/lowjiahao99.md)]
-* Role: Project Advisor
+* Role: Team lead
+* Responsibilities: Model and API testing
-### Jane Doe
+### Lim Jan Jay
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
-
-* Role: Team Lead
-* Responsibilities: UI
-
-### Johnny Doe
-
-
-
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](https://github.com/jaysmyname)]
+[[portfolio](team/jaysmyname.md)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: UI and GUI testing
-### Jean Doe
+### Huang Qing
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/hqhqhq1)]
+[[portfolio](team/hqhqhq1.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: Storage, code quality, deliverables, deadlines, Scheduling and tracking
+
-### James Doe
+### Khor Vanessa
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/vanessaxuuan)]
+[[portfolio](team/vanessaxuuan.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Integration, logic and documentation
+
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..78b9142b0a3 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,14 +2,47 @@
layout: page
title: Developer Guide
---
+
+## **Introduction**
+
+Teaching Assistant Contact Helper (TACH) is a desktop application for Computer Science (CS) Teaching Assistants (TAs) in National University of Singapore (NUS) to manage their students. The
+application is highly optimised for users who can type fast as it is based on the Command Line Interface (CLI). Thus,
+the main interaction with TACH will be done through user text-based commands.
+
+This developer’s guide assumes its readers to have a basic understanding of programming.
+
+The purpose of this Developer Guide is to help readers understand the design and implementation of TACH, so that
+any reader who is interested can become a contributor to this project as well.
+
+--------------------------------------------------------------------------------------------------------------------
+## **Acknowledgements**
+
+- This project is based on the AddressBook-Level3(AB3) project created by the [SE-EDU initiative](https://se-education.org).
+- Libraries used:
+ - [JavaFX](https://openjfx.io/)
+ - [Jackson](https://github.com/FasterXML/jackson)
+ - [JUnit5](https://github.com/junit-team/junit5)
+ - [Markdown-javafx-renderer](https://github.com/JPro-one/markdown-javafx-renderer)
+
+--------------------------------------------------------------------------------------------------------------------
+
+## Table of Contents
+
* Table of Contents
{:toc}
--------------------------------------------------------------------------------------------------------------------
-## **Acknowledgements**
+## Navigation
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+Following are a few syntaxes to take note of before proceeding with the rest of the developer guide:
+
+| Syntax | Description |
+|-------------------------------------------------------------------------|---------------------------------------------------------------|
+| `Markdown` | Denotes file path, distinct classes, their usage or examples. |
+|
:information_source: Note | Important information to take note of. |
+| Words in `UPPER_CASE` | Parameters to be supplied by the user. |
+| parameter end with `…` | This parameter can be added multiple times. |
--------------------------------------------------------------------------------------------------------------------
@@ -23,12 +56,12 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md).
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
+:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
### Architecture
-
+
The ***Architecture Diagram*** given above explains the high-level design of the App.
@@ -36,7 +69,7 @@ Given below is a quick overview of main components and how they interact with ea
**Main components of the architecture**
-**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for,
+**`Main`** has two classes called [`Main`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for,
* At app launch: Initializes the components in the correct sequence, and connects them up with each other.
* At shut down: Shuts down the components and invokes cleanup methods where necessary.
@@ -69,24 +102,24 @@ The sections below give more details of each component.
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified in [`Ui.java`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/ui/Ui.java)
![Structure of the UI Component](images/UiClassDiagram.png)
-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `StudentListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
-The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
* executes user commands using the `Logic` component.
* listens for changes to `Model` data so that the UI can be updated with the modified data.
* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands.
-* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`.
+* depends on some classes in the `Model` component, as it displays `Student` object residing in the `Model`.
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
@@ -95,7 +128,7 @@ Here's a (partial) class diagram of the `Logic` component:
How the `Logic` component works:
1. When `Logic` is called upon to execute a command, it uses the `AddressBookParser` class to parse the user command.
1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to add a person).
+1. The command can communicate with the `Model` when it is executed (e.g. to add a student).
1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call.
@@ -113,20 +146,22 @@ How the parsing works:
* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+Go back to **[Table of Contents](#table-of-contents)**
+
### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+**API** : [`Model.java`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/model/Model.java)
The `Model` component,
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
+* stores the address book data i.e., all `Student` objects (which are contained in a `UniqueStudentList` object).
+* stores the currently 'selected' `Student` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
-
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `TutorialGroup` list in the `AddressBook`, which `Student` references. This allows `AddressBook` to only require one `TutorialGroup` object per unique tutorial group, instead of each `Student` needing their own `TutorialGroup` objects.
@@ -135,7 +170,7 @@ The `Model` component,
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+**API** : [`Storage.java`](https://github.com/AY2122S2-CS2103T-W15-3/tp/tree/master/src/main/java/seedu/address/storage/Storage.java)
@@ -148,96 +183,241 @@ The `Storage` component,
Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Go back to **[Table of Contents](#table-of-contents)**
+
--------------------------------------------------------------------------------------------------------------------
## **Implementation**
+* [Telegram and GitHub attribute implementations](#telegram-and-github-attribute-implementations)
+ * [How it works](#how-it-works)
+ * [Why it works](#why-it-works)
+ * [Design considerations regarding how empty GitHub and Telegram should be stored](#design-considerations-regarding-how-empty-github-and-telegram-should-be-stored)
+* [`addtg` feature](#addtg-feature)
+ * [How `addtg` command is parsed and executed](#how-addtg-command-is-parsed-and-executed)
+ * [Example usage scenario and how the `addtg` mechanism behaves](#example-usage-scenario-and-how-the-addtg-mechanism-behaves)
+* [`deletetg` feature](#deletetg-feature)
+ * [How `deletetg` command is parsed and executed](#how-deletetg-command-is-parsed-and-executed)
+ * [A few interesting details regarding how `deletetg` command works](#a-few-interesting-details-regarding-how-deletetg-command-works)
+* [`findtg` feature](#findtg-feature)
+ * [How `findtg` command is parsed and executed](#how-findtg-command-is-parsed-and-executed)
+ * [Example usage scenario and how the `findtg` mechanism behaves](#example-usage-scenario-and-how-the-findtg-mechanism-behaves)
+
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### Telegram and GitHub attribute implementations
-#### Proposed Implementation
+The diagram below shows that a `Student` may or may not have a `Telegram` and a `Github`.
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+
-* `VersionedAddressBook#commit()` — Saves the current address book state in its history.
-* `VersionedAddressBook#undo()` — Restores the previous address book state from its history.
-* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history.
+Students with empty
+`GitHub` and `Telegram` are stored using `GitHub` and `Telegram` instantiated with empty strings as shown below.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+#### How it works
-Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.
+Below is a sequence diagram for `addStudentCommand`. The command was implemented such that all inputs have to be parsed by the respective methods of `ParserUtil`.
-![UndoRedoState0](images/UndoRedoState0.png)
+
-Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
+>**Note:** parseGitHub and parseTelegram methods now accommodate null as inputs.
+> Here is a snippet for parseGitHub. parseTelegram has a similar format as well.
+> ```
+> public static GitHub parseGitHub(String gitHub) throws ParseException {
+> if (gitHub == null) {
+> return new GitHub(null);
+> }
+> String trimmedGitHub = gitHub.trim();
+> if (!GitHub.isValidGitHub(trimmedGitHub)) {
+> throw new ParseException(GitHub.MESSAGE_CONSTRAINTS);
+> }
+> return new GitHub(trimmedGitHub);
+> }
+> ```
-![UndoRedoState1](images/UndoRedoState1.png)
+GitHub and Telegram objects instantiated with null inputs have a value of ""
+Here is a snippet for the constructor of Telegram. GitHub also have a similar format.
+```
+public Telegram(String telegram) {
+ if (telegram == null) { //if telegram is empty it will exist as an empty string
+ value = "";
+ } else {
+ checkArgument(isValidTelegram(telegram), MESSAGE_CONSTRAINTS);
+ value = telegram;
+ }
+}
+```
-Step 3. The user executes `add n/David …` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`.
+This means that an empty `GitHub` object will have a "" value and a `GitHub` object with a value of "" means that it is an empty `GitHub` object. The same logic applies to `Telegram` objects as well.
-![UndoRedoState2](images/UndoRedoState2.png)
+#### Why it works
-
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.
+As shown in the previous sequence diagram, `ParserUtil` parses all the inputs for the add command. Thus, an empty string (i.e. "") will be parsed though the method isValidXX, where XX is an attribute i.e. isValidName. All empty string will throw an error in any of parse methods in `ParserUtil`. Thus, an empty string will never be able to be accepted through the user input. Therefore, an empty string was used as a means to identify and instantiate attributes that can be empty (e.g. GitHub and Telegram).
-
+#### Design considerations regarding how empty GitHub and Telegram should be stored
-Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.
+* Alternative 1: Stored as null
+ * Pros: Easy to implement
+ * Cons: NullPointerException can occur if `.toString()`of null is called
-![UndoRedoState3](images/UndoRedoState3.png)
+* Alternative 2: Stored as a reserved valid string e.g. "null"
+ * Pros: Avoid NullPointerExceptions
+ * Cons: Possibility of a student whose telegram or github be the string "null".
-
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
-than attempting to perform the undo.
+* Alternative 3 (Current Choice): Stored as an invalid string i.e. ""
+ * Pros: Avoid NullPointerExceptions
+ * Cons: We must ensure that the conversion from Object to Json and vice-versa must be correct.
-
+### `addtg` feature
-The following sequence diagram shows how the undo operation works:
+The `addtg` command adds tutorial group(s) to a student
-![UndoSequenceDiagram](images/UndoSequenceDiagram.png)
+The *add tutorial group(s) to a student* mechanism is facilitated by the `LogicManager` and the `AddressBookParser`. It is implemented by adding the parser class `AddTutorialGroupParser` and the command class `AddTutorialGroupCommand`.
-
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+```
+command format: addtg INDEX tg/TUTORIAL_GROUP...
+```
+#### How `addtg` command is parsed and executed
-
+Assuming the command is valid and execution is successful,
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state.
+1. `LogicManager` is called to execute the command, using the `AddressBookParser` class to parse the
+ command.
+2. `AddressBookParser` sees that the command has the valid starting command word `addtg` and creates a
+ new `AddTutorialGroupParser` that parses the command.
+3. `AddTutorialGroupParser` confirms the command is valid and returns a `AddTutorialGroupCommand` to
+ be executed by the `LogicManager`
+4. `LogicManager` executes `AddTutorialGroupCommand`, which gets the relevant information from the
+ `Model` component, getting the filtered student list and acquiring the student at the specified `Index`.
+5. `AddTutorialGroupCommand` creates a new `Student` combining the existing and newly specified `TUTORIAL_GROUP(s)` and returns the relevant `CommandResult` to `LogicManager`
-
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
+Rationale:
+- A new `Student` is created with the new combined information instead of adding the new tutorial group(s) to the existing `Student` because a `Student` object is immutable.
+- An `Index` based on the current list shown is used to specify which `Student` will be updated. An alternative would be to use the name of the student instead of an index. However, an index makes it easier and faster for users to key in the command as it is way shorter (length) as compared to a student's name.
+ - Hence, to increase efficiency of TACH, we have chosen `index` to be our indicator.
-
+#### Example usage scenario and how the `addtg` mechanism behaves
+
+When the user executes `addtg 2 tg/CS2103T W15-3 tg/CS2101 G08` command to add a tutorial group to the 2nd student listed in the address book.
+
+The following sequence diagram shows how the `addtg` operation works:
+
+
+
+The following diagram shows a brief overview of the AddTutorialGroupDescriptor created shown in the `addtg` sequence diagram above
+
+
+
+Go back to **[Table of Contents](#table-of-contents)**
+
+### `deletetg` feature
+
+The `deletetg` command deletes a tutorial group from a student.
+
+The *deleting a tutorial group from student* mechanism is facilitated by the `LogicManger` and the
+`AddressBookParser`. It is implemented by adding the parser class `DeleteTutorialGroupParser` and the
+command class `DeleteTutorialGroupCommand`.
+
+```
+command format: deletetg INDEX tg/TUTORIAL_GROUP
+```
+
+#### How `deletetg` command is parsed and executed
+
+Assuming the command is valid and execution is successful,
-Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged.
+1. `LogicManager` is called to execute the command, using the `AddressBookParser` class to parse the
+command.
+2. `AddressBookParser` sees that the command has the valid starting command word `deletetg` and creates a
+new `DeleteTutorialGroupParser` that parses the command.
+3. `DeleteTutorialGroupParser` confirms the command is valid and returns a `DeleteTutorialGroupCommand` to
+be executed by the `LogicManager`
+4. `LogicManager` executes `DeleteTutorialGroupCommand`, which gets the relevant information from the
+`Model` component, getting the filtered student list and acquiring the student at the specified `Index`.
+5. `DeleteTutorialGroupCommand` deletes the specified `TUTORIAL_GROUP` of the student and returns the relevant `CommandResult` to `LogicManager`
-![UndoRedoState4](images/UndoRedoState4.png)
+Sequence Diagram:
-Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
+
-![UndoRedoState5](images/UndoRedoState5.png)
+
-The following activity diagram summarizes what happens when a user executes a new command:
+This feature was implemented to follow this sequence to keep it consistent with the rest of the `Command`s
+and `Parser`s.
-
+#### A few interesting details regarding how `deletetg` command works
-#### Design considerations:
+- The command takes in an `Index` instead of a student's name because we felt that it was much easier to
+type in a number than the entirety of someone's name. It is also distinct and much less vague.
-**Aspect: How undo & redo executes:**
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+- Only one tutorial group can be deleted at a time. If a student has some tutorial groups but not all
+tutorial groups to be deleted, what should the command do? Making it such that only one tutorial group can
+be deleted at a time prevents ambiguity in contrast to if several tutorial groups can be deleted at a time.
-* **Alternative 2:** Individual command knows how to undo/redo by
- itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
-_{more aspects and alternatives to be added}_
+- If the tutorial group to be deleted is the only one that the student has, the command will not work. A
+student must have at least one tutorial group. If this were not the case, it could result in some serious
+buggy behaviours regarding other commands involving tutorial groups.
-### \[Proposed\] Data archiving
-_{Explain here how the data archiving feature will be implemented}_
+- The tutorial group must be typed exactly, but is case-insensitive. An alternative would be to
+indicate an `Index` instead of the exact tutorial group, but that would mean we would either have to
+display an overall index of all the modules, or display an index of all the modules for each student.
+Either way it would make the UI more complex and cluttered. This is why we decided to make it such
+that it must be typed exactly, but is case-insensitive, since two tutorial groups should be the same if
+only their cases are different.
+### `findtg` feature
+
+The `findtg` command will list all students in a particular tutorial group.
+
+The *find a tutorial group* mechanism is facilitated by the `LogicManger` and the
+`AddressBookParser`. It is implemented by adding the parser class `FindTutorialGroupParser`, the
+command class `FindTutorialGroupCommand` and the model class `TutorialGroupKeywordsPredicate`.
+
+```
+command format: findtg TUTORIAL_GROUP
+```
+
+#### How `findtg` command is parsed and executed
+
+Assuming the command is valid and execution is successful,
+
+1. `LogicManager` is called to execute the command, using the `AddressBookParser` class to parse the
+ command.
+2. `AddressBookParser` sees that the command has the valid starting command word `findtg` and creates a
+ new `FindTutorialGroupParser` that parses the command.
+3. `FindTutorialGroupParser` confirms the command is valid and returns a `FindTutorialGroupCommand` to
+ be executed by the `LogicManager`
+4. `FindTutorialGroupCommand` passes the specified `TUTORIAL_GROUP` name to `TutorialGroupKeywordsPredicate` to
+filter out all students with the specified `TUTORIAL_GROUP` name
+5. `LogicManager` executes `FindTutorialGroupCommand`, which gets the relevant information from the
+ `Model` component, getting the filtered student list.
+6. `FindTutorialGroupCommand` filter out all students in the specified `TUTORIAL_GROUP` and returns the relevant
+`CommandResult` to `LogicManager`
+
+#### Example usage scenario and how the *findtg* mechanism behaves
+
+When the user executes `findtg CS2100 T05` command to find a tutorial group.
+
+The following sequence diagram shows how the `findtg` operation works:
+
+
+
+There are a few interesting details as to how the command works:
+
+- The tutorial group must be typed exactly, but is case-insensitive. Since it is more convenience for user to type and
+ two tutorial groups should be the same if only their cases are different.
+
+- If there are no matching tutorial group found in the students, the command will return an empty student list
+
+- `findtg` do not support find partial keyword to prevent ambiguity and TAs usually teach a single module with multiple
+tutorial group. This operation is provided for users to sort students by their specified tutorial group
+
+Go back to **[Table of Contents](#table-of-contents)**
--------------------------------------------------------------------------------------------------------------------
@@ -257,71 +437,291 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
-* has a need to manage a significant number of contacts
+* is a Computer Science (CS) Teaching Assistant (TA) in NUS
+* is teaching multiple Computer Science modules/tutorial groups
+* has a need to manage a significant number of students
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**: TACH helps CS Teaching Assistants teaching multiple tutorial groups to manage
+their students in an organized manner. Our sorting feature will allow TAs to view, categorize
+and get information of all their students at one glance.
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
-
-*{More to be added}*
+| Priority | As a … | I want to … | So that I can … |
+|----------|------------------------------------------|---------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------|
+| `* * *` | CS TA | add a student | keep track of them and their contacts |
+| `* * *` | CS TA | add a tutorial group to a student | identify which tutorial groups a student is taking |
+| `* * *` | CS TA | delete a student | make sure I have the correct student in the list |
+| `* * *` | CS TA | delete a tutorial group from a student | make sure a student has the correct tutorial groups |
+| `* * *` | CS TA | delete a tutorial group from all students | remove non-existing tutorial groups at the end of a semester easily |
+| `* * *` | CS TA | find students by name | contact the appropriate student |
+| `* * *` | Forgetful CS TA | find students by parts of their names | contact the appropriate student even if I don't remember their full names |
+| `* * *` | CS TA using the application | see all the students' contact information that I stored | |
+| `* * *` | CS TA with small desktop screen | see all the students' contact information that I stored | |
+| `* * *` | CS TA | get my students' private contact details like their email, Telegram and GitHub easily | save time from the convenience of having all the contact details in one place |
+| `* * *` | CS TA who is experienced in CLI programs | type everything in one command at one go | manage things in the application more quickly |
+| `* * *` | CS TA new to the application | be able to find a user guide for the application | refer to it when needed |
+| `* * *` | CS TA using the application | be able to exit the application | |
+| `* * *` | CS TA | be able to edit the details of the student I added | correct my mistakes or add information without having to add a new Student |
+| `* * ` | CS TA | sort my students by tutorial groups | find the appropriate students for my tutorial groups easily |
+| `* * ` | CS TA | sort my students by name | easily find someone if I forgot part of their name |
+| `* * ` | CS TA | find students by a tutorial group | see which students are in that tutorial group |
+| `* * ` | CS TA | undo my mistakes | |
+| `* *` | CS TA | redo my mistakes | |
+| `* *` | CS TA | store zoom link and venue of tutorial session | find them easily when it is time for tutorial |
+| `* *` | CS TA that finished a semester | clear my student contact list | easily start afresh for the next semester |
+| `* *` | Forgetful TA | store timing of the tutorial session | find them easily when I lose track of time |
+| `* *` | CS TA | keep track of the assignments submitted by students | mark accordingly |
+| `* ` | CS TA | send group messages to a specific group of students | make announcements effectively |
+| `* ` | CS TA | see the announcements that I have sent to the students in a tutorial group | |
+| `* ` | Busy TA | set an alarm before the tutorial starts | be on time for tutorial session |
+
+
+Go back to **[Table of Contents](#table-of-contents)**
### Use cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+(For all use cases below, the **System** is the `Teaching Assistant Contact Helper (TACH)` and the **Actor** is the `Teaching Assistant (TA)`, unless specified otherwise)
-**Use case: Delete a person**
+**Use case: UC01 - Add a student**
-**MSS**
+**MSS:**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. TA adds a new student to the contact list by giving their name, their email and their tutorial group
+2. Student successfully added to the list
Use case ends.
**Extensions**
-* 2a. The list is empty.
+* 1a. The command has an invalid name, email and/or tutorial group.
+ * 1a1. TACH prompts the TA to type in the valid parameters.
+ Step 1a1 is repeated until the data entered is correct.
+
+ Use case resumes from step 2.
+
+
+* 1b. The command does not have a name, email and/or tutorial group.
+ * 1b1. TACH prompts the TA to add in the valid parameters.
+ Step 1b1 is repeated until the data entered is correct.
+
+ Use case resumes from step 2.
+
+
+**Use case: UC02 - Add a tutorial group to a student**
+
+**MSS:**
+
+1. TA adds a new tutorial group to a student by giving the relevant tutorial group.
+2. The new tutorial group is successfully added to the student.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The command has an invalid tutorial group.
+ * 1a1. TACH prompts the TA to type in a valid tutorial group.
+ Step 1a1 is repeated until a valid tutorial group is entered.
+
+ Use case resumes from step 2.
+
+* 1b. The command has an invalid student or a student that does not exist in the contact list.
+ * 1b1. TACH prompts the TA to type in a valid student.
+ Step 1b1 is repeated until a valid student is entered.
+
+ Use case resumes from step 2.
+
+
+**Use case: UC03 - Delete a student**
+
+**MSS:**
+
+1. TA requests to view all students.
+2. TACH shows a list of students.
+3. TA requests to delete a specific student in the list by their index on the list.
+4. TACH deletes the student from the tutorial group.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The student list is empty. There are no students that can be deleted.
Use case ends.
+* 1b. TA chooses instead to find students from a specific tutorial group.
+
+ Use case resumes at step 2.
+
* 3a. The given index is invalid.
+ * 3a1. TACH prompts the TA to type in a valid index.
+ Step 3a1 is repeated until a valid index is entered.
- * 3a1. AddressBook shows an error message.
+ Use case resumes at step 4.
+
- Use case resumes at step 2.
+**Use case: UC04 - Delete a tutorial group from a student**
-*{More to be added}*
+**MSS:**
-### Non-Functional Requirements
+1. TA requests to delete a tutorial group from a student.
+2. The tutorial group is successfully deleted from the student.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The tutorial group requested is an invalid tutorial group or the student is not under that tutorial group.
+ * 1a1. TACH prompts the TA to type a valid tutorial group.
+ Step 1a1 is repeated until a valid tutorial group is entered.
+
+* 1b. The tutorial group requested to be deleted is the only tutorial group the student has.
+ * 1b1. TACH notifies the TA that the tutorial group cannot be deleted.
+
+ Use case ends.
+
+
+**Use case: UC05 - Find students from a tutorial group**
+
+**MSS:**
+
+1. TA requests to find a tutorial group.
+2. TACH list out all the students from the tutorial group.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The tutorial group entered is not found in any student.
+ * 1a1. TACH prompts that there is 0 student in the list.
+
+ Use case ends.
+
+
+**Use case: UC06 - Clearing all students**
+
+**MSS:**
+
+1. TA chooses to clear all students from their contact list.
+2. TACH completely clears its list.
+
+ Use case ends.
+
+
+**Use case: UC07 - Delete a tutorial group from all students**
+
+**MSS:**
+
+Similar to UC04 except that it applies to all students under that tutorial group instead.
-1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-3. 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.
+**Extensions**
+
+* 1a. The tutorial group requested is an invalid tutorial group.
+ * 1a1. TACH prompts the TA to type a valid tutorial group.
+Step 1a1 is repeated until a valid tutorial group is entered.
+
+* 1b. The tutorial group requested to be deleted is the only tutorial group the student has.
+ * 1b1. TACH deletes the tutorial group from the student.
+ * 1b2. The student with no tutorial groups remaining afterwards will be deleted.
+Steps 1b1 - 1b2 are repeated until the requested tutorial group is removed from all the students under it.
+
+
+**Use case: UC08 - Get user guide**
+
+**MSS:**
+
+1. TA requests for the user guide.
+2. TACH provides the link to the user guide.
+
+ Use case ends.
+
+
+**Use case: UC09 - Exit TACH**
+
+**MSS:**
+
+1. TA requests to exit TACH.
+2. TACH closes.
+
+ Use case ends.
+
+
+**Use case: UC10 - See list of all students**
+
+**MSS:**
+
+1. TA request to see list of all students in TACH.
+2. TACH displays the list of all students that are stored.
+
+ Use case ends.
+
+
+**Use case: UC11 - Find a student**
+
+**MSS:**
-*{More to be added}*
+1. TA requests to find a student.
+2. TACH list out all the students that was requested.
+
+ Use case ends.
+
+
+**Use case: UC12 - Edit a student**
+
+**MSS:**
+
+1. TA requests to edit information of a specific student in the list by their index on the list.
+2. TACH updates the student specified by the index with the information provided by TA
+
+ Use case ends.
+
+**Extensions**
+* 1a. The given index is invalid.
+ * 1a1. TACH prompts the TA to type in a valid index.
+ Step 1a1 is repeated until a valid index is entered.
+
+* 1b. The email/telegram/github/name, that is provided, is invalid.
+ * 1b1. TACH prompts the TA to type in a valid attribute for the attribute that is invalid.
+ Step 1b1 is repeated until the provided attributes are valid.
+
+* 1c. The tutorial group ,if provided, is empty or invalid
+ * 1c1. TACH prompts the TA to type in a non-empty and valid tutorial group.
+ Step 1c1 is repeated until the tutorial group is valid and non-empty.
+ Use case resumes at step 2.
+
+
+Go back to **[Table of Contents](#table-of-contents)**
+
+### Non-Functional Requirements
+
+1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
+2. Should be able to hold up to `1000` persons without a noticeable sluggishness in performance for typical usage.
+3. The system should respond within two seconds.
+4. 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.
+5. The user interface should be easy to understand for beginner users.
+6. The commands should feel intuitive and easy to pick up and remember to a beginner user.
+7. The source code should be open source.
+8. The product is free and ready-to-use as soon as one downloads it.
+9. The product should work offline, without an Internet connection.
### Glossary
+* **Tutorial Group**: Tutorial Group is synonymous with "(Tutorial) Class", we use the term Tutorial Group in our code
+and documentation to prevent it from being confused with "Java Classes".
* **Mainstream OS**: Windows, Linux, Unix, OS-X
* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **API**: An application programming interface (API) is the medium by which different software interact
+* **Interface**: An abstract type that is used to specify a behavior of certain tutorial groups
+* **System admin commands**: Terminal commands such as `pwd`, `ls`, `tar`
+* **Open source**: Open source code is publicly accessible to everyone to read, modify and distribute
--------------------------------------------------------------------------------------------------------------------
@@ -349,29 +749,74 @@ testers are expected to do more *exploratory* testing.
1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
+### Deleting a student
-### Deleting a person
+1. Deleting a student while all students are being shown
-1. Deleting a person while all persons are being shown
-
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+ 1. Prerequisites: List all students using the `list` command. Multiple students in the list.
1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
+ Expected: First student is deleted from the list. Details of the deleted student shown in the status message. Timestamp in the status bar is updated.
1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+ Expected: No student is deleted. Error details shown in the status message. Status bar remains the same.
1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
Expected: Similar to previous.
-1. _{ more test cases … }_
-
-### Saving data
+### Finding a tutorial group
+
+1. Finding students from a particular tutorial group while all students are being shown
+ 1. Prerequisites: Multiple students are added to a tutorial group eg:`CS2103T W15`.
+
+ 2. Test case: `findtg CS2103T W15`
+ Expected: all students added to the tutorial group `CS2103T W15` are listed out. Number of students listed out are shown in the status message.
+
+ 3. Test case: `findtg CS2103T`
+ Expected: No student listed. Since user only input module code without tutorial group details. All invalid entry of tutorial group or no matching tutorial group will result in no student listed.
+
+### Dealing with corrupted data files
+
+* Troubleshooting with corrupted files:
+ 1. Prerequisite: Corrupted data file.
+ * To simulate a corrupted data file:
+ * Open the data folder in the folder where TACH is in. Edit addressbook.json and change one of the fields to an invalid one
+ e.g. Add a `!` at the end of Irfan's email.
+ i.e. change from
+ > "name" : "Irfan Ibrahim",
+ "telegram" : "@irfan201",
+ "email" : "irfan@hotmail.com",
+ "gitHub" : "",
+ "inTutorialGroups" : [ "CS2106 T01" ]
+
+ to
+ > "name" : "Irfan Ibrahim",
+ "telegram" : "@irfan201",
+ "email" : "irfan@hotmail.com!",
+ "gitHub" : "",
+ "inTutorialGroups" : [ "CS2106 T01" ]
+
+ > **NOTE:** If there is no data file, open TACH and enter the command `list`. The data file should appear in the folder where TACH is in.
+ 2. Test case: Corrupted data file
+ Open the data folder in the folder where TACH is in. Edit all the data such that it meets the requirement stated here.[Input Requirements](https://ay2122s2-cs2103t-w15-3.github.io/tp/UserGuide.html#input-requirements)
+ Expected: TACH will now load the data file and not an empty one.
+ * Example: To resolve the issue in step i, change Irfan's email from an invalid one (`irfan@hotmail.com!`)
+ to a valid one (`irfan@hotmail.com`) by removing the `!` at the end. i.e.
+ change from :
+ > "name" : "Irfan Ibrahim",
+ "telegram" : "@irfan201",
+ "email" : "irfan@hotmail.com!",
+ "gitHub" : "",
+ "inTutorialGroups" : [ "CS2106 T01" ]
+
+ to
+ > "name" : "Irfan Ibrahim",
+ "telegram" : "@irfan201",
+ "email" : "irfan@hotmail.com",
+ "gitHub" : "",
+ "inTutorialGroups" : [ "CS2106 T01" ]
+
+Go back to **[Table of Contents](#table-of-contents)**
-1. Dealing with missing/corrupted data files
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
-1. _{ more test cases … }_
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 3716f3ca8a4..4c88501ad5d 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,190 +3,497 @@ layout: page
title: User Guide
---
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps.
+## Introduction
+
+Teaching Assistant Contact Helper (TACH) is a desktop application that helps Computer Science (CS) Teaching Assistants (TAs) (like you!)
+from National University of Singapore (NUS), especially those that tutor
+multiple tutorial groups, by **managing their students in an organised manner**.
+
+You can **add, edit and delete** students and their tutorial groups from the list easily.
+You can also **find** students by their name or by their tutorial group.
+
+TACH automatically sorts students in alphabetical order, and all the students' contact details are right next to
+their names, so that you can get their details in a glance, and easily know which contacts belong to whom.
+
+TACH works by typing what you want to do as commands. It is optimized for keyboard users, so if you can type fast,
+TACH can work even faster.
+
+## How to use this guide
+
+**The goal of this guide is to help you**, the reader, to **understand how to use our app better**, regardless of
+whether you are a new user or an experienced user.
+
+If you are a **new user** and want to learn how to download and set up the app, go to **[Quick Start](#quick-start)**.
+ If you have already installed the app and want to learn the basics, go to **[Quick Tutorial](#quick-tutorial)**.
+
+If you are an **experienced user** who wants to use the app to its full potential, or just want a quick
+refresher on the commands, you can look at all the commands for TACH via **[Commands](#commands)**.
+
+--------------------------------------------------------------------------------------------------------------------
+
+## Table of Contents
* Table of Contents
{:toc}
-
+
--------------------------------------------------------------------------------------------------------------------
-## Quick start
+## Quick Start
+
+1. Ensure you have **[Java 11](https://www.oracle.com/java/technologies/downloads/#java11-windows)** or above installed in your Computer.
+
+2. Download the latest release of `TACH.jar` **[here](https://github.com/AY2122S2-CS2103T-W15-3/tp/releases/latest)**.
-1. Ensure you have Java `11` or above installed in your Computer.
+3. Copy the file to the folder you want to use as the _home folder_ for your TACH.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+4. Double-click the file to start the app. The app should appear in a few seconds and look similar to the image below. Note how the app contains some sample data.
+ ![Quick Start](images/QuickStart.png)
+
+
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+**:exclamation: For macOS users:**
-1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png)
+If the app does not open by double-clicking, follow these steps instead:
-1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
- Some example commands you can try:
+1. Move the downloaded `TACH.jar` to a new folder (e.g. TACHfolder) in your `Desktop`.
+2. Open up your **terminal** application.
+3. Enter `cd Desktop` in your terminal to go into your desktop directory.
+4. Then, enter `java -jar TACHfolder/TACH.jar` to open the app.
- * **`list`** : Lists all contacts.
+
+
+
- * **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book.
+**:information_source: Note:**
- * **`delete`**`3` : Deletes the 3rd contact shown in the current list.
+* You can **resize** the app by clicking and dragging the edges of the window to see more users at a time.
+You can also **maximise** the window.
- * **`clear`** : Deletes all contacts.
+
- * **`exit`** : Exits the app.
+You're ready to start using TACH! You can continue learning how to use TACH through the
+**[Quick Tutorial](#quick-tutorial)**.
-1. Refer to the [Features](#features) below for details of each command.
+On the other hand, if you're feeling confident, you can dive straight into all the **[Commands](#commands)**.
--------------------------------------------------------------------------------------------------------------------
-## Features
+## Quick Tutorial
+
+This quick tutorial will teach you how to navigate through the app and its components, along with some basic commands
+that you can use right now!
+
+### App Components
+
+Here is a quick summary of all the components of the app:
+ (Remember that you can **resize the window**!)
+
+![Quick Tutorial Components](images/QuickTutorialComponents.png)
+
+- ![Options](images/IconColourOrange.png) **Options**: Various options that you can use for the app.
+
+- ![Command Box](images/IconColourRed.png) **Command Box**: **The place where you type your commands.**
+Once you have finished typing your command, press the **⏎Enter** key on your keyboard to submit your command.
+
+- ![Student Box](images/IconColourCyan.png) **Student Box**: Represents a student and all their details. It has
+an index, the student's name, their contact details, and their tutorial group(s).
+
+- ![Index](images/IconColourPink.png) **Index**: A number showing where the student is positioned in the current list.
+
+- ![Name](images/IconColourYellow.png) **Name**: The student's name.
+
+- ![Contact Details](images/IconColourGreen.png) **Contact Details**: The student's contact details.
+ - The student must have an ![Email](images/LogoEmail.png) **Email**,
+but their ![Telegram](images/LogoTelegram.png) **Telegram** and ![GitHub](images/LogoGithub.png) **GitHub** usernames
+can be optional.
+
+- ![Tutorial Groups](images/IconColourBlue.png) **Tutorial Group(s)**: The student's tutorial group(s). The student
+must have at least one tutorial group.
+
+- ![Results Display](images/IconColourPurple.png) **Results Display**: Displays the results of a successful command,
+or an appropriate error message if the command is invalid.
+
+### Quick Command Tutorial
+
+Now that you know what each of the components are, it's time to learn a few commands! Commands will look like
+**`this`**. Type the following commands exactly into the command box and press the **⏎Enter** key to submit
+your command. The effect of each command is described after the command itself.
+
+1. **`list`** : Lists all the students in TACH.
+
+2. **`add n/Carl Sagan e/carlsagan42@gmail.com tg/cs2100 g01`** : Adds the student "Carl Sagan" with their email
+and tutorial group to TACH. They should appear as the 3rd person (Index 3) on the list.
+
+3. **`delete 2`**: Deletes the 2nd person in the displayed list. Here, "Bernice Yu" should be deleted
+from the list.
+
+4. **`find david`**: Finds all students that have "David" in their name. Only "David Li" should
+be visible to you now.
+
+5. **`edit 1 n/David Lee t/DavidLee777 g/david-lee`** : Edits the 1st person in the visible list by changing
+their name, their Telegram and their GitHub. This should edit "David Li" to "David Lee" and add their
+Telegram and GitHub usernames.
+
+6. **`findtg cs2106 t05`** : Finds all students that have "CS2106 T05" as a tutorial group. In this tutorial,
+you should see 3 students that have "CS2106 T05" as their tutorial group.
+
+7. **`list`** : Lists all the students in TACH again.
+
+8. **`deletetgall tg/cs2106 t05`** : Deletes the tutorial group "CS2106 T05" from every student. Students that
+have no tutorial groups afterwards will be deleted as well. In this tutorial, you should see that "CS2106 T05"
+is nowhere to be found, and the student "Charlotte Oliveiro" is deleted since they no longer have any
+tutorial groups.
+
+9. Experiment with some commands! Try out the same commands but with different formats, or you can take a look at
+**[Commands](#commands)** for a few more commands that are not covered in this tutorial. When you're ready,
+you can move on to the next two easy commands to complete the tutorial.
+
+10. **`clear`** : Clears TACH of all students.
+
+11. **`exit`** : Exits the app.
+
+This completes the command tutorial! You're now ready to start adding your own students!
-**:information_source: Notes about the command format:**
+**:information_source: Note about reloading sample students:**
+
+If you ever get stuck or want to try out the tutorial again, follow these instructions to reload the
+sample students into the app.
-* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
+1. Exit the app.
+2. Go to the folder that TACH is in.
+3. Delete the `data` folder.
+4. Reopen the app again.
-* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
+The app should give back the original sample students for you to try out commands again!
-* Items with `…` after them can be used multiple times including zero times.
- e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
+
-* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
+Congratulations! You've learned what each component in the app is, and some basic commands that you can use right now
+to get started! If you want more details on what each command does, you can refer to **[Commands](#commands)** for
+a better understanding.
-* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
- e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+Go back to **[Table of Contents](#table-of-contents)**.
+
+--------------------------------------------------------------------------------------------------------------------
+
+## Commands
+
+List of commands:
+* [Viewing help](#viewing-help--help)
+* [Listing students](#listing-all-students-list)
+* [Adding](#adding)
+ - [Adding a student](#adding-a-student-add)
+ - [Adding a tutorial group](#adding-a-tutorial-group-for-a-student-addtg)
+* [Editing a student](#editing-a-student--edit)
+* [Finding](#finding)
+ - [Finding students by name](#finding-students-by-name-find)
+ - [Findind students by tutorial group](#finding-students-by-tutorial-group-findtg)
+* [Deleting](#deleting)
+ - [Deleting a student](#deleting-a-student-delete)
+ - [Deleting a tutorial group from a student](#deleting-a-tutorial-group-from-a-student-deletetg)
+ - [Deleting a tutorial group from all students](#deleting-tutorial-groups-from-all-students-deletetgall)
+* [Clearing all entries](#clearing-all-entries--clear)
+* [Exiting the program](#exiting-the-program--exit)
+
+
+
+**:information_source: Notes about the command format:**
+
+* Words in `UPPER_CASE` are the parameters to be supplied by you.
+ e.g. in `add n/NAME`, `NAME` is a parameter which can be used like `add n/John Doe` for example.
+
+
+* Items in square brackets are optional.
+ e.g. `e/EMAIL [t/TELEGRAM]` can be used as `e/e0123456@u.nus.edu t/JohnSmith` or as `e/e0123456@u.nus.edu`
+
+* Items with `…` after them can be added multiple times.
+ e.g. `tg/TUTORIAL_GROUP…` can be used as `tg/CS2103 W15-3`, `tg/CS2103 W15-3 tg/CS2100 G08` etc.
+
+* Parameters can be in any order.
+ e.g. if the command specifies `n/NAME e/EMAIL`, `e/EMAIL n/NAME` is also acceptable.
+
+* Extraneous parameters for commands that do not take in parameters (such as `help`) will be ignored.
+ e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+ - `help123` will not be interpreted as `help`.
+
+* For information on the requirements of the different inputs, refer to [Input Requirements](#input-requirements).
### Viewing help : `help`
-Shows a message explaning how to access the help page.
-
-![help message](images/helpMessage.png)
+Opens a window showing the **[Command Summary](#command-summary)** and the **[Input Requirements](#input-requirements)**,
+and also gives a reference to the full user guide, which is this page.
Format: `help`
+![Help Window](images/HelpWindow.png)
-### Adding a person: `add`
+### Listing all students: `list`
-Adds a person to the address book.
+Shows a list of all students in TACH.
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+Format: `list`
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+![Results Display](images/ListCommandResult.png)
+
+The students will be sorted in alphabetical order by their names.
+
+### Adding
+
+#### Adding a student: `add`
+
+Adds a student into TACH.
+
+Format: `add n/NAME e/EMAIL [t/TELEGRAM] [g/GITHUB] tg/TUTORIAL_GROUP…`
+
+Note:
+* Adding a student with the exact same name as another student in TACH is **not allowed**.
+ - e.g. If `Sam` exists in TACH, another `Sam` **cannot be added again** even if their contact details are different.
+ - You can manually differentiate them by saving them as `Sam 1` and `Sam 2` for example, or use your own way
+ of identifying them.
+* Names in TACH are used to uniquely identify students. If two students who have the same name are in the same
+tutorial group, it would be difficult to differentiate the two students.
Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+* `add n/John Doe tg/CS2100 G08 e/e0123456@u.nus.edu`
+* `add n/Michael Tay e/michaelT@gmail.com t/MichaelTay g/michael777 tg/CS2103T W15-3 tg/CS2100 G08`
-### Listing all persons : `list`
+The following image shows the output for the following command:
+`add n/Chloe Lee e/chloexlee@gmail.com t/chloe201 g/jchloechloe tg/CS2101 G08`
-Shows a list of all persons in the address book.
+![Results Display](images/AddStudentResult.png)
-Format: `list`
+#### Adding tutorial group(s) for a student: `addtg`
+
+Adds tutorial group(s) for a student in TACH.
+
+Format: `addtg INDEX tg/TUTORIAL_GROUP…`
+
+* Adds one or more tutorial groups for the student at the specified `INDEX`.
+* Adding of tutorial groups is cumulative. (Existing tutorial groups of the specified student will
+remain unchanged.)
+
+Example:
+* `list` followed by `addtg 2 tg/CS2040S T03` adds the tutorial group `CS2040S T03` for the 2nd student listed in TACH.
+* `find Dave` followed by `addtg 1 tg/CS2040S T03 tg/CS3230 T01` adds the tutorial groups `CS2040S T03` and
+`CS3230 T01` for the 1st student in the results of the `find` command.
+
+### Editing a student : `edit`
-### Editing a person : `edit`
+Edits an existing student in TACH.
-Edits an existing person in the address book.
+Format: `edit INDEX [n/NAME] [e/EMAIL] [t/TELEGRAM] [g/GITHUB] [tg/TUTORIAL_GROUPS]…`
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+* Edits the student at the specified `INDEX`
+* At least one of the optional details (Name/NUS email/Telegram/GitHub/Tutorial Groups) must be provided.
+* Any details entered in the `edit` command will replace the original details of the student.
+* Details not entered in the `edit` command will stay the same and not be replaced.
-* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …
-* At least one of the optional fields must be provided.
-* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
- specifying any tags after it.
+>*Note*:
+> * Tutorial groups **CANNOT** be empty.
+`edit 1 tg/` is **NOT** allowed.
+> * GitHub and Telegram **CAN** be empty.
+`edit 1 g/ t/` is allowed and will set the student to have no GitHub and Telegram.
Examples:
-* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+* `list` followed by `edit 2 t/DaveHunter g/` edits the 2nd student listed in TACH. Their Telegram will be
+edited to `DaveHunter` and they will not have any GitHub username.
+* `find Robert` followed by `edit 1 n/Bobby Smiles` edits the 1st student in the results of the `find` command. Their
+name will be edited to `Bobby Smiles`.
-### Locating persons by name: `find`
+The following diagram shows the output for `edit 5 t/chloe201 g/chloechloe`
+from the previous `Add student` [command](#adding-a-student-add)
-Finds persons whose names contain any of the given keywords.
+![Results Display](images/EditingResult.png)
-Format: `find KEYWORD [MORE_KEYWORDS]`
+### Finding
+
+#### Finding students by name: `find`
+
+Finds students whose names contain all the given keywords.
+
+Format `find KEYWORD [ADDTIONAL_KEYWORDS]`
-* The search is case-insensitive. e.g `hans` will match `Hans`
-* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
-* Persons matching at least one keyword will be returned (i.e. `OR` search).
- e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
+* The search ignores cases. e.g. `charles` will match `Charles`
+* The order of the keywords matters. e.g. `Charles Boyle` will not match `Boyle Charles`
+* Keywords can match the name partially e.g. `Char` **WILL** match `Charles`
+ - e.g. `Charles Bo` and `les Boyle` will match `Charles Boyle`, but `Charle Boyle` will not match `Charles Boyle`
+* The positions of the spaces matter. e.g. `Alex Lee En` **will not** match `Alex Leeen`
+* Students whose names contain the keyword fully or partially will be returned
+ - e.g. `find char` will return `Charles Alex Lee`, `Charles Boyle`, and `Racharl Tan` if they are in the list of students
-Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+#### Finding students by tutorial group: `findtg`
+
+Finds all students in a particular tutorial group.
-### Deleting a person : `delete`
+Format `findtg TUTORIAL_GROUP`
-Deletes the specified person from the address book.
+* The search ignores cases. e.g. `cs2101 g08` will match `CS2101 G08`
+* The search ignores extra spaces between the module name and the tutorial group name. e.g. `cs2101<><><>g08` will match `cs2101<>g08`
+ - In this example, `<>` means a space.
+ - However, e.g. `cs2101<>g<>08` **will not** match `cs2101<>g08`
+* Only the tutorial group is searched.
+* Only the exact tutorial group will be matched e.g. `CS2101 G` **WILL NOT** match `CS2101 G08`
+* Students with matching tutorial group will be returned. e.g. `findtg CS2101 G08` will return
+`Charles Martinet` and `Susan Boyle` only if both of them are in the tutorial group `CS2101 G08`
+* If there are no students with matching tutorial group, no student will be returned and an empty list is displayed.
+
+The following diagram shows the result for `findtg CS2100 T05`
+
+![Results Display](images/FindTgResult.png)
+
+### Deleting
+
+#### Deleting a student: `delete`
+
+Deletes the specified student from TACH.
Format: `delete INDEX`
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
-* The index **must be a positive integer** 1, 2, 3, …
+* Deletes the student at the specified `INDEX`.
Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+* `list` followed by `delete 2` deletes the 2nd student listed in TACH.
+* `find Waldo` followed by `delete 1` deletes the 1st student in the results of the `find` command.
+
+
+#### Deleting a tutorial group from a student: `deletetg`
+
+Deletes the specified tutorial group from the specified student.
+
+Format: `deletetg INDEX tg/TUTORIAL_GROUP`
+
+* Deletes the specified tutorial group of the student at the specified `INDEX`.
+* The tutorial group must be written **EXACTLY**, but *ignores cases*. e.g. `deletetg 1 tg/cs2040s t03` will
+delete `CS2040S T03` if that person has that tutorial group, but `deletetg 1 tg/cs2040s` or `deletetg 1 tg/cs2040st03`
+**WILL NOT** successfully delete it.
+* The tutorial group **cannot be deleted** if it is the **only** tutorial group a student has. e.g. A student with only
+the tutorial group `CS2040S T03` cannot have that tutorial group deleted.
+
+Examples:
+* `list` followed by `deletetg 2 tg/CS2103T W15-3` deletes the tutorial group `CS2103T W15-3` of the 2nd student listed
+in TACH (only if the 2nd student has more than one tutorial group).
+* `find Carmen` followed by `deletetg 1 tg/cs2100 g01` deletes the tutorial group `CS2100 G01` of the 1st student in the
+results of the `find` command (only if the 1st student has more than one tutorial group).
+
+#### Deleting tutorial groups from all students: `deletetgall`
+
+Deletes the specified tutorial group from **ALL** students in TACH.
+
+Format: `deletetgall tg/TUTORIAL_GROUP…`
+
+* Deletes the specified tutorial group from **ALL** students stored in TACH.
+* The tutorial group must be written **EXACTLY**, but *ignores cases*. e.g. `deletetgall tg/cs2040s t03` will
+ delete `CS2040S T03` from tutorial groups of all Students, but `deletetgall tg/cs2040s` or `deletetgall tg/cs2040st03` **WILL NOT** successfully delete `CS2040S T03` from students in TACH.
+> **NOTE**: After the deletion, you will see all the updated remaining students in TACH.
+
+>**WARNING:**
+> 1. Students with 0 tutorial groups after the deletion will automatically be deleted.
+> 2. **ALL** students in TACH will be affected. Even those not visible as a result of the `find` command.
+
+Example:
+* `find Eve` followed by `deletetgall tg/CS2103T W15-3` deletes the tutorial group `CS2103T W15-3` from all students in TACH, including those not visible after the `find Eve` command (i.e. students whose name does not contain `Eve`)
+* `deletetgall tg/CS2106 T08 tg/CS2103T W13-3` will remove tutorial groups `CS2106 T08` and `CS2103T W13-3` from all students in TACH. Students with 0 tutorial groups after the tutorial groups' deletion will be deleted from TACH.
+
+The following diagram shows the output of `deletetgall tg/CS2100 T05`
+from the previous `findtg` [command](#finding-students-by-tutorial-group-findtg)
+
+![Results Display](images/DeleteTgAllResult.png)
+
+Note:
+- 3 students, `Gwak Seo Hyeon`, `John Smith` and `Pranith Loganathan` are deleted because they have 0 tutorial groups left after `CS2100 T05` is deleted.
### Clearing all entries : `clear`
-Clears all entries from the address book.
+Clears all entries from TACH. This means every student and all their details.
Format: `clear`
+>**WARNING:**
+> This action erases all the student data stored in your computer and CANNOT be undone! Consider carefully before calling the command as you will have to re-enter the students' details if clear is executed accidentally.
+
### Exiting the program : `exit`
Exits the program.
Format: `exit`
-### Saving the data
+## Input Requirements
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+There are **parameters** (like Names, NUS Emails, and GitHub usernames for example) that must follow certain
+requirements so that TACH recognises them as valid parameters. Here is a list of requirements of every parameter to
+easier understand which parameters are invalid when typing a command.
-### Editing the data file
+In the list, a **word** is defined as a bunch of *characters* (letters, numbers, punctuation, etc.) separated by spaces.
+e.g. `There A_RE 4 w0-rd_s.` has 4 words.
-AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+| Parameter | Requirements |
+|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **INDEX** | Must be a positive number that can be a maximum of 2,147,483,647 (1, 2, 3, … , 2147483647). e.g. `100` |
+| **NAME** | Must contain letters. Can contain spaces, apostrophes and hyphens as long as they are in between letters. Consecutive spaces, apostrophes or hyphens are not allowed. Name must start with a letter. Numbers are allowed, but they must strictly be at the end of the name separated by a space. Cannot be empty, and must not be more than 100 characters long, including spaces. e.g. `John Smith 2` or `Johnson-Johnson Maxine d'Arby` |
+| **TUTORIAL_GROUP** | Must **STRICTLY** consist of a module code, followed by a space, then the tutorial name. It should not be blank. The tutorial name must have a non-zero digit and cannot start or end with a hyphen. The name can consist of a combination of letters, hyphens, digits or underscores. Tutorial groups can only have a maximum of 100 characters including spaces. e.g. `CS2103T W15-3_A`
**ALL** letters in tutorial group inputs will be converted into uppercase letters e.g. `addtg 2 tg/cs2101 t01` will add `CS2101 T01` into the list of tutorial groups of student 2, assuming there are at least 2 students in the list that you see. |
+| **EMAIL** | An email consists of three parts in the following order, the local part, the `@` sign, and the domain part. The local part should only contain letters, numbers, and these special symbols: `+` `_` `.` `-`. It cannot start or end with the special symbols. It must be at most 64 characters long. There must be an @ sign afterwards, followed by the domain name. The domain name must be one of the following: `u.nus.edu` `nus.edu.sg` `gmail.com` `yahoo.com` `outlook.com` `hotmail.com` e.g. `e0123456@u.nus.edu` or `jasminelim@gmail.com` (Our original intention is for you to put in your students' NUS emails which are given to you on LumiNUS, but we also provide the freedom to use some of the more popular email providers listed above, should they be more convenient.) |
+| **TELEGRAM** | May include `@` at the start. Must be exactly one word that can contain letters, numbers and underscores. It must be between 5 to 32 characters long (inclusive). This does not count the `@` symbol. e.g. `Dave3` or `@Lorem_ipsum_dolor_sit_amet_12345` |
+| **GITHUB** | Must be exactly one word that can contain letters, numbers and hyphens. It must be between 2 to 39 characters long (inclusive). e.g. `12345678` or `cake-is-a-lie77` |
-
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run.
-
+## Saving the data
+
+TACH data is saved in your computer's [hard disk](#glossary) automatically after any command that changes the data is entered. There is no need to save manually.
+
+## Editing the data file
+
+TACH data is saved as a [JSON file](#glossary) under `[TACH file location]/data/addressbook.json`.
+**You should not edit the data file directly unless you are absolutely sure of what you are doing!**
+Only advanced users who are absolutely familiar with the data format should try updating the data directly by editing the data file.
-### Archiving data files `[coming in v2.0]`
+>
:exclamation: Caution:
+>If your changes to the data file make its format invalid, TACH will consider the data corrupted and discard ALL data, starting with an empty data file in the next run.
+>This action CANNOT be undone! Please consider making a copy of the data first before attempting to edit the data file.
+>
-_Details coming soon ..._
+Go back to **[Table of Contents](#table-of-contents)**.
--------------------------------------------------------------------------------------------------------------------
## FAQ
**Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder.
+**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains
+the data of your previous TACH home folder.
+
+**Q**: Does TACH works on both MacOS and Microsoft Windows?
+**A**: Yes. It is supported on both systems.
+
+**Q**: TACH doesn't seem to work on my computer, how may I get help?
+**A**: You may drop us an email here with the relevant questions: **[Link](mailto:vanessakhor19@gmail.com)**.
+
+--------------------------------------------------------------------------------------------------------------------
+## Glossary
+
+| Terms | Definition |
+|---------------|-----------------------------------------------------------------------------------------------------------------|
+| **Hard disk** | A storage device for data in your computer. |
+| **JSON file** | A file that uses human-readable text to store and transmit data objects such as `Students` in the case of TACH. |
--------------------------------------------------------------------------------------------------------------------
-## Command summary
-
-Action | Format, Examples
---------|------------------
-**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…` e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
-**Clear** | `clear`
-**Delete** | `delete INDEX` e.g., `delete 3`
-**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
-**Find** | `find KEYWORD [MORE_KEYWORDS]` e.g., `find James Jake`
-**List** | `list`
-**Help** | `help`
+## Command Summary
+
+| Action | Format, Examples |
+|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Add Student** | `add n/NAME e/EMAIL [t/TELEGRAM] [g/GITHUB] tg/TUTORIAL_GROUP…` e.g. `add n/John Smith tg/CS2103T W15-3 e/e0123456@u.nus.edu t/johnsmyname g/johnsmyname` |
+| **Add Tutorial Group for Student** | `addtg INDEX tg/TUTORIAL_GROUP…` e.g. `addtg 5 tg/CS2100 G08` |
+| **Edit Student** | `edit INDEX [n/NAME] [e/EMAIL] [t/TELEGRAM] [g/GITHUB] [tg/TUTORIAL_GROUP]…` e.g. `edit 3 n/Mary Sue t/PresentPerfect` |
+| **Find Students by name** | `find KEYWORD [ADDTIONAL_KEYWORDS]` e.g. `find Jack Ho` |
+| **Find Students by Tutorial Group** | `findtg TUTORIAL_GROUP` e.g. `findtg CS2101 G08` |
+| **Delete Student** | `delete INDEX` e.g. `delete 4` |
+| **Deleting Tutorial Group from Student** | `deletetg INDEX tg/TUTORIAL_GROUP` e.g. `deletetg 4 tg/cs2030s t11` |
+| **Deleting Tutorial Group from all Students** | `deletetgall tg/TUTORIAL_GROUP…` e.g. `deletetgall tg/CS2106 T08` |
+| **List** | `list` |
+| **Clear** | `clear` |
+| **Help** | `help` |
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..9f61f04e59c 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "TACH"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2122S2-CS2103T-W15-3/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..8e5e75a7d89 100644
--- a/docs/_sass/minima/_base.scss
+++ b/docs/_sass/minima/_base.scss
@@ -288,7 +288,7 @@ table {
text-align: center;
}
.site-header:before {
- content: "AB-3";
+ content: "TACH";
font-size: 32px;
}
}
diff --git a/docs/diagrams/AddStudentSequenceDiagram.puml b/docs/diagrams/AddStudentSequenceDiagram.puml
new file mode 100644
index 00000000000..aa303868dce
--- /dev/null
+++ b/docs/diagrams/AddStudentSequenceDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+!include style.puml
+
+box add LOGIC_COLOR_T1
+participant ":AddStudentCommandParser" as AddStudentCommandParser LOGIC_COLOR
+participant ":ParserUtil" as ParserUtil LOGIC_COLOR
+participant "s:Student" as Student LOGIC_COLOR
+participant ":AddStudentCommand" as AddStudentCommand LOGIC_COLOR
+end box
+
+-> AddStudentCommandParser : parse("n/john smith e/johnsmith@gmail.com t/john1 tg/CS2106 T04")
+activate AddStudentCommandParser
+
+AddStudentCommandParser -> ParserUtil : parseName("john smith")
+activate ParserUtil
+
+ParserUtil --> AddStudentCommandParser : n
+deactivate ParserUtil
+
+AddStudentCommandParser -> ParserUtil : parseEmail("johnsmith@gmail.com")
+activate ParserUtil
+
+ParserUtil --> AddStudentCommandParser : e
+deactivate ParserUtil
+
+AddStudentCommandParser -> ParserUtil : parseTelegram("john1")
+activate ParserUtil
+
+ParserUtil --> AddStudentCommandParser : t
+deactivate ParserUtil
+
+AddStudentCommandParser -> ParserUtil : parseGitHub(null)
+activate ParserUtil
+
+ParserUtil --> AddStudentCommandParser : g
+deactivate ParserUtil
+
+AddStudentCommandParser -> ParserUtil : parseTutorialGroup("CS2106 T04")
+activate ParserUtil
+
+ParserUtil --> AddStudentCommandParser : tg
+deactivate ParserUtil
+
+create Student
+AddStudentCommandParser -> Student : new Student(n, e, t, g, tg)
+activate Student
+
+Student --> AddStudentCommandParser : s
+deactivate Student
+
+create AddStudentCommand
+AddStudentCommandParser -> AddStudentCommand : new AddStudentCommand(s)
+activate AddStudentCommand
+
+AddStudentCommand --> AddStudentCommandParser
+deactivate AddStudentCommand
+
+[<--AddStudentCommandParser
+deactivate AddStudentCommandParser
+destroy AddStudentCommandParser
+@enduml
diff --git a/docs/diagrams/AddTutorialGroupDescriptorDiagram.puml b/docs/diagrams/AddTutorialGroupDescriptorDiagram.puml
new file mode 100644
index 00000000000..b211653aa0e
--- /dev/null
+++ b/docs/diagrams/AddTutorialGroupDescriptorDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+'https://plantuml.com/object-diagram'
+
+object "__:AddTutorialGroupDescriptor__" as addTutorialGroupDescriptor
+object "__:TutorialGroup__" as tutorialGroup_1
+object "__:TutorialGroup__" as tutorialGroup_2
+
+tutorialGroup_1 : tutorialGroupName = "CS2103T W15-3"
+tutorialGroup_2 : tutorialGroupName = "CS2101 G08"
+
+addTutorialGroupDescriptor --> tutorialGroup_1
+addTutorialGroupDescriptor --> tutorialGroup_2
+@enduml
diff --git a/docs/diagrams/AddTutorialGroupSequenceDiagram.puml b/docs/diagrams/AddTutorialGroupSequenceDiagram.puml
new file mode 100644
index 00000000000..3f44aae90b9
--- /dev/null
+++ b/docs/diagrams/AddTutorialGroupSequenceDiagram.puml
@@ -0,0 +1,87 @@
+@startuml
+!include Style.puml
+
+box addtg LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":AddTutorialGroupParser" as AddTutorialGroupParser LOGIC_COLOR
+participant ":AddTutorialGroupDescriptor" as AddTutorialGroupDescriptor LOGIC_COLOR
+participant ":AddTutorialGroupCommand" as AddTutorialGroupCommand LOGIC_COLOR
+participant ":Student" as Student LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+ -> LogicManager : execute("addtg 2 tg/CS2103T W15-3 tg/CS2101 G08")
+activate LogicManager
+LogicManager -> AddressBookParser : parseCommand("addtg 2 tg/CS2103T W15-3 tg/CS2101 G08")
+activate AddressBookParser
+
+create AddTutorialGroupParser
+AddressBookParser -> AddTutorialGroupParser
+activate AddTutorialGroupParser
+AddTutorialGroupParser --> AddressBookParser
+deactivate AddTutorialGroupParser
+
+AddressBookParser -> AddTutorialGroupParser : parse("2 tg/CS2103T W15-3 tg/CS2101 G08")
+activate AddTutorialGroupParser
+
+create AddTutorialGroupDescriptor
+AddTutorialGroupParser -> AddTutorialGroupDescriptor : new AddTutorialGroupDescriptor()
+activate AddTutorialGroupDescriptor
+
+AddTutorialGroupDescriptor --> AddTutorialGroupParser
+deactivate AddTutorialGroupDescriptor
+
+AddTutorialGroupParser -> AddTutorialGroupDescriptor : setTutorialGroups()
+activate AddTutorialGroupDescriptor
+
+AddTutorialGroupDescriptor --> AddTutorialGroupParser
+deactivate AddTutorialGroupDescriptor
+
+create AddTutorialGroupCommand
+AddTutorialGroupParser -> AddTutorialGroupCommand : new AddTutorialGroupCommand(index, addTutorialGroupDescriptor)
+activate AddTutorialGroupCommand
+
+AddTutorialGroupCommand --> AddTutorialGroupParser
+deactivate AddTutorialGroupCommand
+
+AddTutorialGroupParser --> AddressBookParser
+deactivate AddTutorialGroupParser
+
+AddressBookParser --> LogicManager
+deactivate AddressBookParser
+
+LogicManager -> AddTutorialGroupCommand : execute()
+activate AddTutorialGroupCommand
+
+create Student
+AddTutorialGroupCommand -> Student : new Student(n, t, e, g, tg)
+activate Student
+
+Student --> AddTutorialGroupCommand
+deactivate Student
+
+AddTutorialGroupCommand -> Model : setStudent(studentToEdit, updatedStudent)
+activate Model
+Model --> AddTutorialGroupCommand
+deactivate Model
+
+AddTutorialGroupCommand -> Model : getFilteredStudentList()
+activate Model
+Model --> AddTutorialGroupCommand
+deactivate Model
+
+create CommandResult
+AddTutorialGroupCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddTutorialGroupCommand
+deactivate CommandResult
+
+AddTutorialGroupCommand --> LogicManager
+deactivate AddTutorialGroupCommand
+@enduml
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..d43a4bc258c 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -13,7 +13,7 @@ activate ui UI_COLOR
ui -[UI_COLOR]> logic : execute("delete 1")
activate logic LOGIC_COLOR
-logic -[LOGIC_COLOR]> model : deletePerson(p)
+logic -[LOGIC_COLOR]> model : deleteStudent(p)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 5731f9cbaa1..6565b1f2a94 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,18 @@ skinparam arrowThickness 1.1
skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
-AddressBook *-right-> "1" UniquePersonList
-AddressBook *-right-> "1" UniqueTagList
-UniqueTagList -[hidden]down- UniquePersonList
-UniqueTagList -[hidden]down- UniquePersonList
+AddressBook *-right-> "1" UniqueStudentList
+AddressBook *-right-> "1" UniqueTutorialList
+UniqueTutorialList -[hidden]down- UniqueStudentList
+UniqueTutorialList -[hidden]down- UniqueStudentList
-UniqueTagList *-right-> "*" Tag
-UniquePersonList -right-> Person
+UniqueTutorialList *-right-> "*" TutorialGroup
+UniqueStudentList -right-> "*" Student
-Person -up-> "*" Tag
+Student -up-> "1..*" TutorialGroup
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
+Student *--> "1" Name
+Student *--> "0..1" Telegram
+Student *--> "1" Email
+Student *--> "0..1" GitHub
@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..577458fe4ee 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -48,7 +48,7 @@ deactivate AddressBookParser
LogicManager -> DeleteCommand : execute()
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : deleteStudent(1)
activate Model
Model --> DeleteCommand
diff --git a/docs/diagrams/DeleteTutorialGroupSequenceDiagram.puml b/docs/diagrams/DeleteTutorialGroupSequenceDiagram.puml
new file mode 100644
index 00000000000..4fe16faa0b9
--- /dev/null
+++ b/docs/diagrams/DeleteTutorialGroupSequenceDiagram.puml
@@ -0,0 +1,74 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":DeleteTutorialGroupParser" as DeleteTutorialGroupParser LOGIC_COLOR
+participant "d:DeleteTutorialGroupCommand" as DeleteTutorialGroupCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager: execute("deletetg 2 tg/CS2100 T01")]
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("deletetg 2 tg/CS2100 T01")
+activate AddressBookParser
+
+create DeleteTutorialGroupParser
+AddressBookParser -> DeleteTutorialGroupParser
+activate DeleteTutorialGroupParser
+
+DeleteTutorialGroupParser --> AddressBookParser
+deactivate DeleteTutorialGroupParser
+
+AddressBookParser -> DeleteTutorialGroupParser : parse("2 tg/CS2100 T01")
+activate DeleteTutorialGroupParser
+
+create DeleteTutorialGroupCommand
+DeleteTutorialGroupParser -> DeleteTutorialGroupCommand
+activate DeleteTutorialGroupCommand
+
+DeleteTutorialGroupCommand --> DeleteTutorialGroupParser : d
+deactivate DeleteTutorialGroupCommand
+
+DeleteTutorialGroupParser --> AddressBookParser : d
+deactivate DeleteTutorialGroupParser
+DeleteTutorialGroupParser -[hidden]-> AddressBookParser
+destroy DeleteTutorialGroupParser
+
+AddressBookParser --> LogicManager : d
+deactivate AddressBookParser
+
+LogicManager -> DeleteTutorialGroupCommand : execute()
+activate DeleteTutorialGroupCommand
+
+DeleteTutorialGroupCommand -> Model : getFilteredStudentList()
+activate Model
+
+Model --> DeleteTutorialGroupCommand
+deactivate Model
+
+DeleteTutorialGroupCommand -> Model : setStudent()
+activate Model
+
+Model --> DeleteTutorialGroupCommand
+deactivate Model
+
+create CommandResult
+DeleteTutorialGroupCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> DeleteTutorialGroupCommand
+deactivate CommandResult
+
+DeleteTutorialGroupCommand --> LogicManager : result
+deactivate DeleteTutorialGroupCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/FindTutorialGroupSequenceDiagram.puml b/docs/diagrams/FindTutorialGroupSequenceDiagram.puml
new file mode 100644
index 00000000000..fd254f91dc4
--- /dev/null
+++ b/docs/diagrams/FindTutorialGroupSequenceDiagram.puml
@@ -0,0 +1,78 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":FindTutorialGroupParser" as FindTutorialGroupParser LOGIC_COLOR
+participant ":FindTutorialGroupCommand" as FindTutorialGroupCommand LOGIC_COLOR
+participant ":TutorialGroupKeywordsPredicate" as TutorialGroupKeywordsPredicate LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager: execute("findtg CS2100 T05")]
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("findtg CS2100 T05"")
+activate AddressBookParser
+
+create FindTutorialGroupParser
+AddressBookParser -> FindTutorialGroupParser
+activate FindTutorialGroupParser
+
+FindTutorialGroupParser --> AddressBookParser
+deactivate FindTutorialGroupParser
+
+AddressBookParser -> FindTutorialGroupParser : parse("CS2100 T05")
+activate FindTutorialGroupParser
+
+create FindTutorialGroupCommand
+FindTutorialGroupParser -> FindTutorialGroupCommand :
+activate FindTutorialGroupCommand
+
+create TutorialGroupKeywordsPredicate
+FindTutorialGroupCommand -> TutorialGroupKeywordsPredicate : CS2100 T05
+activate TutorialGroupKeywordsPredicate
+
+TutorialGroupKeywordsPredicate --> FindTutorialGroupCommand :
+deactivate TutorialGroupKeywordsPredicate
+
+FindTutorialGroupCommand --> FindTutorialGroupParser :
+deactivate FindTutorialGroupCommand
+
+FindTutorialGroupParser --> AddressBookParser :
+deactivate FindTutorialGroupParser
+FindTutorialGroupParser -[hidden]-> AddressBookParser
+destroy FindTutorialGroupParser
+
+AddressBookParser --> LogicManager :
+deactivate AddressBookParser
+
+LogicManager -> FindTutorialGroupCommand : execute()
+activate FindTutorialGroupCommand
+
+FindTutorialGroupCommand -> Model : getFilteredStudentList()
+activate Model
+
+Model --> FindTutorialGroupCommand
+deactivate Model
+
+
+
+create CommandResult
+FindTutorialGroupCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> FindTutorialGroupCommand
+deactivate CommandResult
+
+FindTutorialGroupCommand --> LogicManager : result
+deactivate FindTutorialGroupCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 4439108973a..cb676a445de 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -12,13 +12,13 @@ Class AddressBook
Class ModelManager
Class UserPrefs
-Class UniquePersonList
-Class Person
-Class Address
+Class UniqueStudentList
+Class Student
+Class GitHub
Class Email
Class Name
-Class Phone
-Class Tag
+Class Telegram
+Class TutorialGroup
}
@@ -34,17 +34,17 @@ ModelManager -left-> "1" AddressBook
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+AddressBook *--> "1" UniqueStudentList
+UniqueStudentList --> "~* all" Student
+Student *--> "1" Name
+Student *--> "0..1" Telegram
+Student *--> "1" Email
+Student *--> "0..1" GitHub
+Student *--> "1..*" TutorialGroup
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+Name -[hidden]right-> Telegram
+Telegram -[hidden]right-> GitHub
+GitHub -[hidden]right-> Email
-ModelManager -->"~* filtered" Person
+ModelManager -->"~* filtered" Student
@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 760305e0e58..f7ccdf8c964 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -18,8 +18,8 @@ package "AddressBook Storage" #F4F6F6{
Class "<>\nAddressBookStorage" as AddressBookStorage
Class JsonAddressBookStorage
Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
-Class JsonAdaptedTag
+Class JsonAdaptedStudent
+Class JsonAdaptedTutorialGroup
}
}
@@ -37,7 +37,7 @@ Storage -right-|> AddressBookStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
JsonAddressBookStorage .up.|> AddressBookStorage
JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonSerializableAddressBook --> "*" JsonAdaptedStudent
+JsonAdaptedStudent --> "1..*" JsonAdaptedTutorialGroup
@enduml
diff --git a/docs/diagrams/StudentWithEmptyTelegramAndGitHub.puml b/docs/diagrams/StudentWithEmptyTelegramAndGitHub.puml
new file mode 100644
index 00000000000..d7f6fb84cc8
--- /dev/null
+++ b/docs/diagrams/StudentWithEmptyTelegramAndGitHub.puml
@@ -0,0 +1,22 @@
+@startuml
+'https://plantuml.com/object-diagram
+
+object "__:Student__" as student
+object "__:GitHub__" as gitHub
+object "__:Telegram__" as telegram
+object "__:Name__" as name
+object "__:Tutorial Group__" as tg
+object "__:Email__" as email
+
+gitHub : value = ""
+telegram : value = ""
+name : fullName = "john smith"
+tg : tutorialGroupName = "CS2103 WT13-2"
+email : value = example@u.nus.edu
+
+student --> tg
+student --> name
+student --> gitHub
+student --> telegram
+student --> email
+@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..927a6342276 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -11,8 +11,8 @@ Class UiManager
Class MainWindow
Class HelpWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class StudentListPanel
+Class StudentCard
Class StatusBarFooter
Class CommandBox
}
@@ -32,26 +32,26 @@ UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" StudentListPanel
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
-PersonListPanel -down-> "*" PersonCard
+StudentListPanel -down-> "*" StudentCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+StudentListPanel --|> UiPart
+StudentCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
-PersonCard ..> Model
+StudentCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+StudentListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
index 01fcb9b2b96..a0ccd45a491 100644
--- a/docs/diagrams/UndoRedoState1.puml
+++ b/docs/diagrams/UndoRedoState1.puml
@@ -16,7 +16,7 @@ State2 -[hidden]right-> State3
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFf
Pointer -up-> State2
@end
diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml
index fdcbe1c0ccc..56fc24eadcd 100644
--- a/docs/diagrams/tracing/LogicSequenceDiagram.puml
+++ b/docs/diagrams/tracing/LogicSequenceDiagram.puml
@@ -13,7 +13,7 @@ create ecp
abp -> ecp
abp -> ecp ++: parse(arguments)
create ec
-ecp -> ec ++: index, editPersonDescriptor
+ecp -> ec ++: index, editStudentDescriptor
ec --> ecp --
ecp --> abp --: command
abp --> logic --: command
diff --git a/docs/diagrams/tracing/Style.puml b/docs/diagrams/tracing/Style.puml
new file mode 100644
index 00000000000..a08bc22c026
--- /dev/null
+++ b/docs/diagrams/tracing/Style.puml
@@ -0,0 +1,5 @@
+!define LOGIC_COLOR #3333C4
+!define LOGIC_COLOR_T1 #7777DB
+!define LOGIC_COLOR_T2 #5252CE
+!define LOGIC_COLOR_T3 #1616B0
+!define LOGIC_COLOR_T4 #101086
diff --git a/docs/images/AddStudentResult.png b/docs/images/AddStudentResult.png
new file mode 100644
index 00000000000..79a82e6eeb3
Binary files /dev/null and b/docs/images/AddStudentResult.png differ
diff --git a/docs/images/AddStudentSequenceDiagram.png b/docs/images/AddStudentSequenceDiagram.png
new file mode 100644
index 00000000000..43efeaeafec
Binary files /dev/null and b/docs/images/AddStudentSequenceDiagram.png differ
diff --git a/docs/images/AddTutorialGroupDescriptorDiagram.png b/docs/images/AddTutorialGroupDescriptorDiagram.png
new file mode 100644
index 00000000000..79d39783b9a
Binary files /dev/null and b/docs/images/AddTutorialGroupDescriptorDiagram.png differ
diff --git a/docs/images/AddTutorialGroupSequenceDiagram.png b/docs/images/AddTutorialGroupSequenceDiagram.png
new file mode 100644
index 00000000000..c6fc4d6c076
Binary files /dev/null and b/docs/images/AddTutorialGroupSequenceDiagram.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..6c9361462c9 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 1ec62caa2a5..d882b6525f0 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..dfff7539424 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/DeleteTgAllResult.png b/docs/images/DeleteTgAllResult.png
new file mode 100644
index 00000000000..f67b1325fa3
Binary files /dev/null and b/docs/images/DeleteTgAllResult.png differ
diff --git a/docs/images/DeleteTutorialGroupSequenceDiagram.png b/docs/images/DeleteTutorialGroupSequenceDiagram.png
new file mode 100644
index 00000000000..940da66a5b1
Binary files /dev/null and b/docs/images/DeleteTutorialGroupSequenceDiagram.png differ
diff --git a/docs/images/EditingResult.png b/docs/images/EditingResult.png
new file mode 100644
index 00000000000..66636542a63
Binary files /dev/null and b/docs/images/EditingResult.png differ
diff --git a/docs/images/FindTgResult.png b/docs/images/FindTgResult.png
new file mode 100644
index 00000000000..189b727b5d6
Binary files /dev/null and b/docs/images/FindTgResult.png differ
diff --git a/docs/images/FindTutorialGroupSequenceDiagram.png b/docs/images/FindTutorialGroupSequenceDiagram.png
new file mode 100644
index 00000000000..a08c996bd68
Binary files /dev/null and b/docs/images/FindTutorialGroupSequenceDiagram.png differ
diff --git a/docs/images/HelpWindow.png b/docs/images/HelpWindow.png
new file mode 100644
index 00000000000..6dd9c30fed8
Binary files /dev/null and b/docs/images/HelpWindow.png differ
diff --git a/docs/images/IconColourBlue.png b/docs/images/IconColourBlue.png
new file mode 100644
index 00000000000..9711e20b8cf
Binary files /dev/null and b/docs/images/IconColourBlue.png differ
diff --git a/docs/images/IconColourCyan.png b/docs/images/IconColourCyan.png
new file mode 100644
index 00000000000..3c4ae4d609b
Binary files /dev/null and b/docs/images/IconColourCyan.png differ
diff --git a/docs/images/IconColourGreen.png b/docs/images/IconColourGreen.png
new file mode 100644
index 00000000000..7cb3b64e202
Binary files /dev/null and b/docs/images/IconColourGreen.png differ
diff --git a/docs/images/IconColourOrange.png b/docs/images/IconColourOrange.png
new file mode 100644
index 00000000000..21504de56c8
Binary files /dev/null and b/docs/images/IconColourOrange.png differ
diff --git a/docs/images/IconColourPink.png b/docs/images/IconColourPink.png
new file mode 100644
index 00000000000..3fbbd71fc95
Binary files /dev/null and b/docs/images/IconColourPink.png differ
diff --git a/docs/images/IconColourPurple.png b/docs/images/IconColourPurple.png
new file mode 100644
index 00000000000..3c2bc0163aa
Binary files /dev/null and b/docs/images/IconColourPurple.png differ
diff --git a/docs/images/IconColourRed.png b/docs/images/IconColourRed.png
new file mode 100644
index 00000000000..46ace3fd5eb
Binary files /dev/null and b/docs/images/IconColourRed.png differ
diff --git a/docs/images/IconColourYellow.png b/docs/images/IconColourYellow.png
new file mode 100644
index 00000000000..47d1dab2811
Binary files /dev/null and b/docs/images/IconColourYellow.png differ
diff --git a/docs/images/ListAfterDeleteTgAll.png b/docs/images/ListAfterDeleteTgAll.png
new file mode 100644
index 00000000000..a97c8b3bca1
Binary files /dev/null and b/docs/images/ListAfterDeleteTgAll.png differ
diff --git a/docs/images/ListCommandResult.png b/docs/images/ListCommandResult.png
new file mode 100644
index 00000000000..94ada15b8e8
Binary files /dev/null and b/docs/images/ListCommandResult.png differ
diff --git a/docs/images/LogoEmail.png b/docs/images/LogoEmail.png
new file mode 100644
index 00000000000..bc8069efc4c
Binary files /dev/null and b/docs/images/LogoEmail.png differ
diff --git a/docs/images/LogoGithub.png b/docs/images/LogoGithub.png
new file mode 100644
index 00000000000..d21675537ea
Binary files /dev/null and b/docs/images/LogoGithub.png differ
diff --git a/docs/images/LogoTelegram.png b/docs/images/LogoTelegram.png
new file mode 100644
index 00000000000..7c41a50109e
Binary files /dev/null and b/docs/images/LogoTelegram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index 04070af60d8..0a6a5e2cf67 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/QuickStart.png b/docs/images/QuickStart.png
new file mode 100644
index 00000000000..31bcb5581ad
Binary files /dev/null and b/docs/images/QuickStart.png differ
diff --git a/docs/images/QuickTutorialComponents.png b/docs/images/QuickTutorialComponents.png
new file mode 100644
index 00000000000..6ba9fae068a
Binary files /dev/null and b/docs/images/QuickTutorialComponents.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 2533a5c1af0..d78804fc6a2 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/StudentWithEmptyTelegramAndGitHub.png b/docs/images/StudentWithEmptyTelegramAndGitHub.png
new file mode 100644
index 00000000000..15eeb65e7a1
Binary files /dev/null and b/docs/images/StudentWithEmptyTelegramAndGitHub.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..0a1b664a6a8 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 785e04dbab4..34fe1798981 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/hqhqhq1.png b/docs/images/hqhqhq1.png
new file mode 100644
index 00000000000..4dd12b37cd6
Binary files /dev/null and b/docs/images/hqhqhq1.png differ
diff --git a/docs/images/jaysmyname.png b/docs/images/jaysmyname.png
new file mode 100644
index 00000000000..b42e24ae577
Binary files /dev/null and b/docs/images/jaysmyname.png differ
diff --git a/docs/images/lowjiahao99.png b/docs/images/lowjiahao99.png
new file mode 100644
index 00000000000..59d9d1d57d9
Binary files /dev/null and b/docs/images/lowjiahao99.png differ
diff --git a/docs/images/vanessaxuuan.png b/docs/images/vanessaxuuan.png
new file mode 100644
index 00000000000..6735f2f8844
Binary files /dev/null and b/docs/images/vanessaxuuan.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..a93359767ad 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,24 @@
---
layout: page
-title: AddressBook Level-3
+title: Teaching Assistant Contact Helper (TACH)
---
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
-[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3)
+[![CI Status](https://github.com/AY2122S2-CS2103T-W15-3/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S2-CS2103T-W15-3/tp/actions)
+[![codecov](https://codecov.io/gh/AY2122S2-CS2103T-W15-3/tp/branch/master/graph/badge.svg?token=UXIYT9OQUD)](https://codecov.io/gh/AY2122S2-CS2103T-W15-3/tp)
![Ui](images/Ui.png)
-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+The Teaching Assistant Contact Helper (TACH) is a desktop app that helps Computer Science (CS) Teaching Assistants (TAs)
+from National University of Singapore (NUS), especially those that tutor
+multiple tutorial groups, by **managing their students in an organised manner**.
+The sorting feature allows TAs to **view, categorize and get information** of all their students in a glance.
+It is optimized for Command Line Interface (CLI) users so that frequent tasks can be done faster by
+typing in commands. While it has a GUI (Graphical User Interface), most of the user interactions happen using the CLI.
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+* If you are interested in using TACH, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing TACH, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5), [Markdown-javafx-renderer](https://github.com/JPro-one/markdown-javafx-renderer)
diff --git a/docs/team/hqhqhq1.md b/docs/team/hqhqhq1.md
new file mode 100644
index 00000000000..0f45be69dc7
--- /dev/null
+++ b/docs/team/hqhqhq1.md
@@ -0,0 +1,44 @@
+---
+layout: page
+title: Huang Qing's Project Portfolio Page
+---
+
+## Project: Teaching Assistant Contact Helper (TACH)
+
+TACH helps CS Teaching Assistants tutoring multiple modules & classes by keeping
+track of their students and monitoring their progress on their tutorials.
+It is optimized for CLI users so that frequent tasks can be done faster by typing
+in commands.
+
+The following sections below summarise my contributions to this project.
+
+* **Code contributed**: **[RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=hqhqhq1&breakdown=true)**
+* **New Feature**: Added find tutorial group feature
+ * What it does: allows the user to view all students in a particular tutorial group
+ * Justification: this feature improves the product significantly because users will need to sort students by tutorial
+ group to have a clear overview of a particular tutorial group, and it also allows users to manage their students by tutorial
+ groups
+* **Project management**:
+ * set up, keep track and assigning of issues
+ * update milestones with respective issues and set deadline
+* **Enhancements to existing features**:
+ * Changed add feature to add student feature to suit our product purpose (Pull request [#58](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/58))
+ * Added automatically sort student by alphabetical order feature (Pull request [#67](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/67))
+ * Updated ui for help window (Pull request [#162](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/162))
+ * Wrote additional tests for existing features (Pull request [#58](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/58))
+ * Enhanced `edit`, `addtg`, `deletetg` features to keep at current list instead of go back to main list (Pull request [#167](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/167))
+* **Documentation**:
+ * *User Guide*:
+ * Added documentation for the features `add` and `findtg`
+ * Updated command summary
+ * *Developer Guide*:
+ * Added use cases and user stories (Pull request [#30](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/30))
+ * Added and updated the following sections: Introduction, Acknowledgement and Navigation
+ * Added implementation details of the `findtg` feature. [#67](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/67))
+* **Contributions to team-based tasks**:
+ * PRs reviewed (with non-trivial review comments): [#56](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/56),
+ [#72](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/72), [#83](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/83).
+
+* **Tools:**
+ * Integrated a third party library ([markdown-javafx-renderer](https://github.com/JPro-one/markdown-javafx-renderer)) to the project
+(Pull request [#162](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/162))
diff --git a/docs/team/jaysmyname.md b/docs/team/jaysmyname.md
new file mode 100644
index 00000000000..5cf97bf77ca
--- /dev/null
+++ b/docs/team/jaysmyname.md
@@ -0,0 +1,35 @@
+---
+layout: page
+title: Lim Jan Jay's Project Portfolio Page
+---
+
+## Project: Teaching Assistant Contact Helper (TACH)
+
+TACH helps CS Teaching Assistants tutoring multiple modules & classes by keeping
+track of their students and monitoring their progress on their tutorials.
+It is optimized for CLI users so that frequent tasks can be done faster by typing
+in commands.
+
+The following sections below summarise my contributions to this project.
+
+* **Code contributed**: **[RepoSense Link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=jaysmyname&breakdown=true)**
+* **New Feature**: Added the ability to delete tutorial groups of specific students.
+ * What it does: Allows the user to delete tutorial groups one at a time for a specified student.
+ * Justification: This feature improves the product significantly because it allows a user to undo an erroneous tutorial group, or delete irrelevant tutorial groups once a semester ends.
+* **Project management**:
+ * Managed releases `v1.2` - `v1.4` (4 releases) on GitHub
+ * Set deadlines for milestones and made sure they were met.
+ * Set up the [team repo](https://github.com/AY2122S2-CS2103T-W15-3)
+* **Enhancements to existing features**:
+ * Updated the GUI to fit our product (Pull request [#68](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/68))
+ * Improved email and name regexes to be more useful (Pull requests [#150](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/150), [#153](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/153))
+* **Documentation**:
+ * *User Guide*:
+ * Added the following sections: Introduction, How to use the guide, Quick Start and Quick Tutorial [#89](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/89)
+ * Added documentation for the features `addtg` and `deletetg` [#57](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/57)
+ * Added the Input Requirements section [#57](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/57)
+ * *Developer Guide*:
+ * Added implementation details of the `deletetg` feature.
+ * Added Non-Functional Requirements.
+* **Contributions to team-based tasks**:
+ * PRs reviewed (with non-trivial review comments): [#34](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/34), [#75](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/75), [#77](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/77), [#91](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/91).
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index 773a07794e2..00000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: page
-title: John Doe's Project Portfolio Page
----
-
-### Project: AddressBook Level 3
-
-AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
-
-Given below are my contributions to the project.
-
-* **New Feature**: Added the ability to undo/redo previous commands.
- * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
- * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
- * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
- * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
-
-* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
-
-* **Code contributed**: [RepoSense link]()
-
-* **Project management**:
- * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
-
-* **Enhancements to existing features**:
- * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
- * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
-
-* **Documentation**:
- * User Guide:
- * Added documentation for the features `delete` and `find` [\#72]()
- * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
- * Developer Guide:
- * Added implementation details of the `delete` feature.
-
-* **Community**:
- * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
- * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
- * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
- * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
-
-* **Tools**:
- * Integrated a third party library (Natty) to the project ([\#42]())
- * Integrated a new Github plugin (CircleCI) to the team repo
-
-* _{you can add/remove categories in the list above}_
diff --git a/docs/team/lowjiahao99.md b/docs/team/lowjiahao99.md
new file mode 100644
index 00000000000..73ee637df49
--- /dev/null
+++ b/docs/team/lowjiahao99.md
@@ -0,0 +1,37 @@
+---
+layout: page
+title: Low Jia Hao's Project Portfolio Page
+---
+
+## Project: Teaching Assistant Contact Helper (TACH)
+
+TACH helps CS Teaching Assistants tutoring multiple modules & classes by keeping
+track of their students and monitoring their progress on their tutorials.
+It is optimized for CLI users so that frequent tasks can be done faster by typing
+in commands.
+
+The following sections below summarise my contributions to this project.
+
+* **New Feature**: Added GitHub, Telegram and Tutorial Group feature.
+ * What it does: allows users to store GitHub, Telegram and Tutorial Groups as data.
+ * Justification: This features allows the application to be more specialised to our target users (CS TAs).
+ * Highlights: GitHub and Telegram are modified to be able to be empty. Difficulty faced in storing data that can be empty because the base project does not allow any empty fields.
+* **New Feature**: Added deletetgall feature.
+ * What it does: Deletes all the provided tutorial group from all students in the list.
+ * Justification: This feature allows TAs to remove his contact list if he was reassigned to another tutorial group. Can be used at end of semester as well.
+
+* **Code contributed**: [RepoSense Link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=lowjiahao99&breakdown=true)
+* **Enhancements to existing features**:
+ * Modify edit command to be able to accept empty GitHub and Telegram. ([#66](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/66))
+* **Documentation**:
+ * *User Guide*:
+ * Added documentation for the feature `add`, `edit` and `deletetgall`. ([#34](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/34), [#66](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/66), [#72](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/72))
+ * *Developer Guide*:
+ * Modify UML diagrams to fit the program. ([#71](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/71))
+ * Added implementation details of GitHub and Telegram features. ([#75](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/75))
+ * Added value proposition and user stories. ([#28](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/28), [#40](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/40))
+* **Contributions to team-based tasks**:
+ * Ensuring issues are closed with the PRs attached.
+ * Updating user stories and value propositions in developer guide. ([#28](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/28), [#40](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/40))
+* **Review/mentoring contributions**:
+ * PRs reviewed (with non-trivial review comments) : [#36](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/36), [#57](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/57), [#58](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/58), [#60](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/60)
diff --git a/docs/team/vanessaxuuan.md b/docs/team/vanessaxuuan.md
new file mode 100644
index 00000000000..66d93cc71f5
--- /dev/null
+++ b/docs/team/vanessaxuuan.md
@@ -0,0 +1,42 @@
+---
+layout: page
+title: Khor Vanessa's Project Portfolio Page
+---
+
+### Project: Teaching Assistant Contact Helper (TACH)
+
+TACH helps CS Teaching Assistants tutoring multiple modules & classes by keeping track of their students and monitoring their progress on their tutorials. It is optimized for CLI users so that frequent tasks can be done faster by typing in commands.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense Link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=vanessaxuuan&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+* **New Feature**: added `addtg` feature [(#60)](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/60)
+ - What it does: allows users to add tutorial group(s) to an existing student.
+ - Rationale: this provides greater flexibility for the users as they will be able to add tutorial groups that they have missed out on when the student was being created initially, instead of recreating the student.
+* **Enhancements to existing features**:
+ - Extended `find` feature to allow partial word/phrase matching. [(#172)](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/172)
+ - e.g. `find ja` returns `javier` and `jan`.
+ - Changed `find` feature to search for students whose names match ALL keywords given instead of ANY keywords. [(#77)](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/77)
+ - e.g. `find Alex Ko` returns `Alex ko` and `Alex koh` but not `Alex` or `Alexius ko`.
+ - Enhanced `findtg` feature to remove extra whitespace(s). [(#169)](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/169)
+ - e.g. Both `findtg CS2101G08` and `findtg CS2101G08` returns the tutorial group `CS2101 G08`.
+ - Cosmetic updates of GUI: text wrapping and padding. ([#79](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/79), [#171](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/171))
+* **Contributions to team-based tasks**:
+ - Set up demo for v1.2.
+ - PR reviews (with non-trivial comments). [(#34](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/34), [#57](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/57), [#154](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/154))
+* **Project management**:
+ - Created our discussion group on Discord.
+ - Note takings during project meetings.
+ - Managed submissions for User Guide drafts and (CS2101) peer review forms.
+* **Documentation**:
+ * *User Guide*
+ * Updated the **Commands** section. [(#91)](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/91/files)
+ * Added documentation for `addtg`.
+ * Added diagrams for `list`, `add`, `deletetgall`, `findtg` and `edit`.
+ * Added Glossary.
+ * Updated FAQ.
+ * Added Quick Start instructions for MacOs users
+ * *Developer Guide*
+ * Added Target User Profile.
+ * Added Glossary.
+ * Added documentation and UML diagrams for the feature `addtg`. [(#76)](https://github.com/AY2122S2-CS2103T-W15-3/tp/pull/76)
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 4133aaa0151..42f7d860aa2 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -36,7 +36,7 @@
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 0, true);
+ public static final Version VERSION = new Version(1, 4, 0, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing TACH ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -79,14 +79,14 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
try {
addressBookOptional = storage.readAddressBook();
if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ logger.info("Data file not found. Will be starting with a sample TACH");
}
initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
} catch (DataConversionException e) {
- logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook");
+ logger.warning("Data file not in the correct format. Will be starting with an empty TACH");
initialData = new AddressBook();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
+ logger.warning("Problem while reading from the file. Will be starting with an empty TACH");
initialData = new AddressBook();
}
@@ -151,7 +151,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
+ "Using default user prefs");
initializedPrefs = new UserPrefs();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
+ logger.warning("Problem while reading from the file. Will be starting with an empty TACH");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +167,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting TACH " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping TACH ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
index 1deb3a1e469..93bc791abcf 100644
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ b/src/main/java/seedu/address/commons/core/Messages.java
@@ -7,7 +7,8 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
- public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
- public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
+ public static final String MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX = "The student index provided is invalid! "
+ + "\n%1$s";
+ public static final String MESSAGE_STUDENTS_LISTED_OVERVIEW = "%1$d students listed!";
}
diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/address/commons/core/index/Index.java
index 19536439c09..1b902a058cd 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/seedu/address/commons/core/index/Index.java
@@ -9,6 +9,9 @@
* convert it back to an int if the index will not be passed to a different component again.
*/
public class Index {
+ public static final String MESSAGE_CONSTRAINT = "Index is not a non-zero unsigned integer that is less than or"
+ + " equal to 2,147,483,647.";
+
private int zeroBasedIndex;
/**
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java
index 61cc8c9a1cb..2963ff6aee7 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/seedu/address/commons/util/StringUtil.java
@@ -5,7 +5,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.Arrays;
+import java.math.BigInteger;
/**
* Helper functions for handling strings.
@@ -13,29 +13,44 @@
public class StringUtil {
/**
- * Returns true if the {@code sentence} contains the {@code word}.
- * Ignores case, but a full word match is required.
+ * Returns true if the {@code sentence} contains the {@code keys}.
+ * Ignores case, but white space in {@code keys} must match {@code sentence}'s.
* examples:
- * containsWordIgnoreCase("ABc def", "abc") == true
- * containsWordIgnoreCase("ABc def", "DEF") == true
- * containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
+ * containsPartialSentenceIgnoreCase("ABc def", "abc") == true
+ * containsPartialSentenceIgnoreCase("ABc def", "abc d") == true
+ * containsPartialSentenceIgnoreCase("ABc def", "abcd") == false // whitespace does not tally
+ * containsPartialSentenceIgnoreCase("ABc def", "abc defg") == false // not a substring
*
* @param sentence cannot be null
- * @param word cannot be null, cannot be empty, must be a single word
+ * @param keys cannot be null, cannot be empty
*/
- public static boolean containsWordIgnoreCase(String sentence, String word) {
+ public static boolean containsPartialSentenceIgnoreCase(String sentence, String keys) {
requireNonNull(sentence);
- requireNonNull(word);
+ requireNonNull(keys);
- String preppedWord = word.trim();
- checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty");
- checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word");
+ checkArgument(!keys.isBlank(), "Keys cannot be empty");
+ String capitalizedName = sentence.toUpperCase().trim();
+ String capitalizedKeys = keys.toUpperCase().trim();
+ return capitalizedName.contains(capitalizedKeys);
+ }
- String preppedSentence = sentence;
- String[] wordsInPreppedSentence = preppedSentence.split("\\s+");
+ /**
+ * Returns true if the {@code sentence1} contains the {@code sentence2}.
+ * Ignores case, but a full sentence match is required.
+ * examples:
+ * containsWordIgnoreCase("ABc def", "abc def") == true
+ * containsWordIgnoreCase("ABc def", "abc DEF") == true
+ * containsWordIgnoreCase("ABc def", "ABc") == false //not a full sentence match
+ *
+ * @param sentence1 cannot be null
+ * @param sentence2 cannot be null, cannot be empty
+ */
+ public static boolean containsFullSentenceIgnoreCase(String sentence1, String sentence2) {
+ requireNonNull(sentence1);
+ requireNonNull(sentence2);
- return Arrays.stream(wordsInPreppedSentence)
- .anyMatch(preppedWord::equalsIgnoreCase);
+ checkArgument(!sentence2.isEmpty(), "sentence2 parameter cannot be empty");
+ return sentence1.equalsIgnoreCase(sentence2);
}
/**
@@ -49,16 +64,21 @@ public static String getDetails(Throwable t) {
}
/**
- * Returns true if {@code s} represents a non-zero unsigned integer
+ * Returns true if {@code s} represents a nonZero unsigned integer that is less than
+ * or equal to {@code Integer.MAX_VALUE}
* e.g. 1, 2, 3, ..., {@code Integer.MAX_VALUE}
* Will return false for any other non-null string input
* e.g. empty string, "-1", "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters)
* @throws NullPointerException if {@code s} is null.
*/
- public static boolean isNonZeroUnsignedInteger(String s) {
- requireNonNull(s);
-
+ public static boolean isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit(String s) {
try {
+ BigInteger parsedInteger = new BigInteger(s);
+ Integer maxInt = Integer.MAX_VALUE;
+ String maxIntString = maxInt.toString();
+ if (parsedInteger.compareTo(new BigInteger(maxIntString)) == 1) { //check for overflow
+ return false;
+ }
int value = Integer.parseInt(s);
return value > 0 && !s.startsWith("+"); // "+1" is successfully parsed by Integer#parseInt(String)
} catch (NumberFormatException nfe) {
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..6696e55727a 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -8,7 +8,7 @@
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* API of the Logic component
@@ -30,8 +30,8 @@ public interface Logic {
*/
ReadOnlyAddressBook getAddressBook();
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the filtered list of students */
+ ObservableList getFilteredStudentList();
/**
* Returns the user prefs' address book file path.
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 9d9c6d15bdc..d80ff2e1ded 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -14,7 +14,7 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
import seedu.address.storage.Storage;
/**
@@ -60,8 +60,8 @@ public ReadOnlyAddressBook getAddressBook() {
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredStudentList() {
+ return model.getFilteredStudentList();
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
deleted file mode 100644
index 71656d7c5c8..00000000000
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * Adds a person to the address book.
- */
-public class AddCommand extends Command {
-
- public static final String COMMAND_WORD = "add";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " "
- + PREFIX_NAME + "John Doe "
- + PREFIX_PHONE + "98765432 "
- + PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
-
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
-
- private final Person toAdd;
-
- /**
- * Creates an AddCommand to add the specified {@code Person}
- */
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
-
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.addPerson(toAdd);
- return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddCommand // instanceof handles nulls
- && toAdd.equals(((AddCommand) other).toAdd));
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/AddStudentCommand.java b/src/main/java/seedu/address/logic/commands/AddStudentCommand.java
new file mode 100644
index 00000000000..2d1cf906d26
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddStudentCommand.java
@@ -0,0 +1,67 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.student.Student;
+
+/**
+ * Adds a student to the address book.
+ */
+public class AddStudentCommand extends Command {
+
+ public static final String COMMAND_WORD = "add";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a student to the address book. "
+ + "Parameters: "
+ + PREFIX_NAME + "NAME "
+ + PREFIX_EMAIL + "EMAIL "
+ + "[" + PREFIX_TELEGRAM + "TELEGRAM] "
+ + "[" + PREFIX_GITHUB + "GITHUB] "
+ + PREFIX_TUTORIAL_GROUP + "TUTORIAL_GROUP...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_NAME + "John Doe "
+ + PREFIX_EMAIL + "e0123456@u.nus.edu "
+ + PREFIX_TELEGRAM + "johndoe201 "
+ + PREFIX_GITHUB + "john-doe "
+ + PREFIX_TUTORIAL_GROUP + "CS2103T W15-3 "
+ + PREFIX_TUTORIAL_GROUP + "CS2101 G08";
+
+ public static final String MESSAGE_SUCCESS = "New student added: %1$s";
+ public static final String MESSAGE_DUPLICATE_STUDENT = "This student already exists in the address book";
+
+ private final Student toAdd;
+
+ /**
+ * Creates an AddStudentCommand to add the specified {@code Student}
+ */
+ public AddStudentCommand(Student student) {
+ requireNonNull(student);
+ toAdd = student;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasStudent(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
+ }
+
+ model.addStudent(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddStudentCommand // instanceof handles nulls
+ && toAdd.equals(((AddStudentCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/AddTutorialGroupCommand.java b/src/main/java/seedu/address/logic/commands/AddTutorialGroupCommand.java
new file mode 100644
index 00000000000..a0d58a1f97d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddTutorialGroupCommand.java
@@ -0,0 +1,191 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.CollectionUtil;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Adds tutorial group to a student identified using it's displayed index from the address book
+ */
+public class AddTutorialGroupCommand extends Command {
+
+ public static final String COMMAND_WORD = "addtg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds tutorial groups to the student identified "
+ + "by the index number used in the displayed student list. "
+ + "Adding of tutorial groups is cumulative.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_TUTORIAL_GROUP + "TUTORIAL_GROUP...\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_TUTORIAL_GROUP + "CS2103T W15-3 "
+ + PREFIX_TUTORIAL_GROUP + "CS2101 G08";
+
+ public static final String MESSAGE_ADD_TUTORIAL_GROUP_SUCCESS = "Added tutorial group: %1$s";
+ public static final String MESSAGE_NOT_ADDED = "At least one tutorial group to add must be provided.";
+ public static final String MESSAGE_DUPLICATE_TUTORIAL_GROUP = "This tutorial group already exists.";
+ public static final String MESSAGE_INDEX_OUT_OF_RANGE = String.format(
+ Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, "Index is larger than the number of "
+ + "students in the viewed list.");
+
+ private final Index index;
+ private final AddTutorialGroupDescriptor addTutorialGroupDescriptor;
+
+ /**
+ * @param index of the student in the filtered student list to edit
+ * @param details to edit the student with
+ */
+ public AddTutorialGroupCommand(Index index, AddTutorialGroupDescriptor details) {
+ requireNonNull(index);
+ requireNonNull(details);
+
+ this.index = index;
+ this.addTutorialGroupDescriptor = new AddTutorialGroupDescriptor(details);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredStudentList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(MESSAGE_INDEX_OUT_OF_RANGE);
+ }
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+
+ // identify duplicate tutorial groups
+ if (studentToEdit.tutorialGroupExists(addTutorialGroupDescriptor.tutorialGroups)) {
+ throw new CommandException(MESSAGE_DUPLICATE_TUTORIAL_GROUP);
+ }
+
+ Student updatedStudent = createNewStudent(studentToEdit, addTutorialGroupDescriptor);
+ model.setStudent(studentToEdit, updatedStudent);
+ model.getFilteredStudentList();
+ return new CommandResult(String.format(MESSAGE_ADD_TUTORIAL_GROUP_SUCCESS,
+ addTutorialGroupDescriptor.tutorialGroups));
+ }
+
+ /**
+ * Creates and returns a {@code Student} with the details of {@code studentToEdit}
+ * edited with {@code ddTutorialGroupDescriptor}.
+ */
+ private static Student createNewStudent(Student studentToEdit, AddTutorialGroupDescriptor tgDescriptor) {
+ assert studentToEdit != null;
+ // Defensive copy of tgDescriptor
+ AddTutorialGroupDescriptor tgDescriptorCopy = new AddTutorialGroupDescriptor(tgDescriptor);
+
+ Name currName = studentToEdit.getName();
+ Email currEmail = studentToEdit.getEmail();
+
+ Telegram currTelegram = studentToEdit.getTelegram();
+ GitHub currGitHub = studentToEdit.getGitHub();
+
+ tgDescriptorCopy.addTutorialGroups(studentToEdit.getTutorialGroups());
+ Set updatedTutorialGroups = tgDescriptorCopy.getTutorialGroups().get();
+
+ return new Student(currName, currTelegram, currEmail, currGitHub, updatedTutorialGroups);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddTutorialGroupCommand)) {
+ return false;
+ }
+
+ // state check
+ AddTutorialGroupCommand e = (AddTutorialGroupCommand) other;
+ return index.equals(e.index)
+ && addTutorialGroupDescriptor.equals(e.addTutorialGroupDescriptor);
+ }
+
+ /**
+ * Stores the details to edit the student with. Each non-empty field value will replace the
+ * corresponding field value of the student.
+ */
+ public static class AddTutorialGroupDescriptor {
+ private Set tutorialGroups;
+
+ public AddTutorialGroupDescriptor() {}
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tutorialGroups} is used internally.
+ */
+ public AddTutorialGroupDescriptor(AddTutorialGroupDescriptor toCopy) {
+ setTutorialGroups(toCopy.tutorialGroups);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(tutorialGroups);
+ }
+
+ /**
+ * Sets {@code tutorialGroups} to this object's {@code tutorialGroups}.
+ * A defensive copy of {@code tutorialGroups} is used internally.
+ */
+ public void setTutorialGroups(Set tutorialGroups) {
+ this.tutorialGroups = (tutorialGroups != null) ? new HashSet<>(tutorialGroups) : null;
+ }
+
+ /**
+ * Returns an unmodifiable tutorial group set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code tutorialGroups} is null.
+ */
+ public Optional> getTutorialGroups() {
+ return (tutorialGroups != null)
+ ? Optional.of(Collections.unmodifiableSet(tutorialGroups)) : Optional.empty();
+ }
+
+ /**
+ * Adds additional tutorial groups to the current AddTutorialGroupDescriptor
+ *
+ * @param tg tutorial group(s) to be added
+ */
+ public void addTutorialGroups(Set tg) {
+ tutorialGroups.addAll(tg);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddTutorialGroupDescriptor)) {
+ return false;
+ }
+
+ // state check
+ AddTutorialGroupDescriptor a = (AddTutorialGroupDescriptor) other;
+ return getTutorialGroups().equals(a.getTutorialGroups());
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 02fd256acba..29c7795a84c 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -8,21 +8,24 @@
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
- * Deletes a person identified using it's displayed index from the address book.
+ * Deletes a student identified using it's displayed index from the address book.
*/
public class DeleteCommand extends Command {
public static final String COMMAND_WORD = "delete";
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
+ + ": Deletes the student identified by the index number used in the displayed student list.\n"
+ "Parameters: INDEX (must be a positive integer)\n"
+ "Example: " + COMMAND_WORD + " 1";
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+ public static final String MESSAGE_DELETE_STUDENT_SUCCESS = "Deleted Student: %1$s";
+ public static final String MESSAGE_INDEX_OUT_OF_RANGE = String.format(
+ Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, "Index is larger than the number of "
+ + "students in the viewed list.");
private final Index targetIndex;
@@ -33,15 +36,15 @@ public DeleteCommand(Index targetIndex) {
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredStudentList();
if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(MESSAGE_INDEX_OUT_OF_RANGE);
}
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete));
+ Student studentToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteStudent(studentToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_STUDENT_SUCCESS, studentToDelete));
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/DeleteTutorialGroupCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTutorialGroupCommand.java
new file mode 100644
index 00000000000..0d5dbcb1725
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteTutorialGroupCommand.java
@@ -0,0 +1,151 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Deletes the specified tutorial group from a student using their displayed index
+ */
+public class DeleteTutorialGroupCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletetg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes the specified tutorial group "
+ + "from a student identified by the index number used in the displayed student list.\n"
+ + "Only one tutorial group can be deleted at a time.\n"
+ + "The tutorial group must be written EXACTLY, but is case-insensitive.\n"
+ + "The tutorial group cannot be deleted if it is the ONLY tutorial group a student has.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_TUTORIAL_GROUP + "TUTORIAL_GROUP\n"
+ + "Example: " + COMMAND_WORD + " 2 "
+ + PREFIX_TUTORIAL_GROUP + "Cs2101 g08";
+
+ public static final String MESSAGE_DELETE_TUTORIAL_GROUP_SUCCESS = "Deleted Tutorial Group: %1$s";
+ public static final String MESSAGE_NOT_DELETED = "Exactly one tutorial group must be provided.";
+ public static final String MESSAGE_NO_SUCH_TUTORIAL_GROUP = "The student at this index does not "
+ + "have this tutorial group.";
+ public static final String MESSAGE_CANNOT_DELETE_ONLY_TUTORIAL_GROUP = "This tutorial group cannot be deleted "
+ + "because the student at this index only has this tutorial group.";
+ public static final String MESSAGE_INDEX_OUT_OF_RANGE = String.format(
+ Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, "Index is larger than the number of "
+ + "students in the viewed list.");
+
+ private final Index index;
+ private final TutorialGroup tutorialGroupToDelete;
+
+ /**
+ * DeleteTutorialGroupCommand constructor.
+ *
+ * @param index of the student in the filtered student list to edit
+ * @param tutorialGroupToDelete {@code String} of tutorial group to delete from student
+ */
+ public DeleteTutorialGroupCommand(Index index, String tutorialGroupToDelete) {
+ requireNonNull(index);
+ requireNonNull(tutorialGroupToDelete);
+
+ this.index = index;
+ this.tutorialGroupToDelete = new TutorialGroup(tutorialGroupToDelete);
+ }
+
+ /**
+ * Another DeleteTutorialGroupCommand constructor.
+ *
+ * @param index of the student in the filtered student list to edit
+ * @param tutorialGroupToDelete {@code TutorialGroup} to delete from student
+ */
+ public DeleteTutorialGroupCommand(Index index, TutorialGroup tutorialGroupToDelete) {
+ requireNonNull(index);
+ requireNonNull(tutorialGroupToDelete);
+
+ this.index = index;
+ this.tutorialGroupToDelete = tutorialGroupToDelete;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredStudentList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(MESSAGE_INDEX_OUT_OF_RANGE);
+ }
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+
+ // Identify if tutorial group does not exist
+ if (!studentToEdit.tutorialGroupExists(tutorialGroupToDelete)) {
+ throw new CommandException(MESSAGE_NO_SUCH_TUTORIAL_GROUP);
+ }
+
+ Student updatedStudent = createNewStudent(studentToEdit, tutorialGroupToDelete);
+ model.setStudent(studentToEdit, updatedStudent);
+ model.getFilteredStudentList();
+ return new CommandResult(String.format(MESSAGE_DELETE_TUTORIAL_GROUP_SUCCESS, updatedStudent));
+ }
+
+ /**
+ * Creates and returns a {@code Student} with the details of {@code studentToEdit}
+ * edited with {@code deleteTutorialGroupDescriptor}.
+ */
+ private static Student createNewStudent(Student studentToEdit, TutorialGroup tutorialGroupToDelete)
+ throws CommandException {
+ assert studentToEdit != null;
+
+ Name currName = studentToEdit.getName();
+ Email currEmail = studentToEdit.getEmail();
+ Telegram currTelegram = studentToEdit.getTelegram();
+ GitHub currGitHub = studentToEdit.getGitHub();
+
+ Set currTutorialGroups = studentToEdit.getTutorialGroups();
+
+ assert studentToEdit.tutorialGroupExists(tutorialGroupToDelete);
+
+ // Identify if tutorial group to delete is the only tutorial group
+ if (currTutorialGroups.size() == 1) {
+ throw new CommandException(MESSAGE_CANNOT_DELETE_ONLY_TUTORIAL_GROUP);
+ }
+
+ Set updatedTutorialGroups = new HashSet<>();
+ for (TutorialGroup tg : currTutorialGroups) {
+ if (tg.equals(tutorialGroupToDelete)) {
+ continue;
+ }
+ updatedTutorialGroups.add(tg);
+ }
+
+ return new Student(currName, currTelegram, currEmail, currGitHub, updatedTutorialGroups);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteTutorialGroupCommand)) {
+ return false;
+ }
+
+ // state check
+ DeleteTutorialGroupCommand d = (DeleteTutorialGroupCommand) other;
+ return index.equals(d.index)
+ && tutorialGroupToDelete.equals(d.tutorialGroupToDelete);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteTutorialGroupsFromStudentsCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTutorialGroupsFromStudentsCommand.java
new file mode 100644
index 00000000000..b7bd788f80c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteTutorialGroupsFromStudentsCommand.java
@@ -0,0 +1,107 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Deletes tutorial groups given from all students in TACH. If student does not have a tutorial group after deleting
+ * the student will be deleted.
+ */
+public class DeleteTutorialGroupsFromStudentsCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletetgall";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the tutorial group identified by the prefix from all students.\n"
+ + "Students without a tutorial group after the deletion will also be deleted.\n"
+ + "Parameters: "
+ + PREFIX_TUTORIAL_GROUP + "TUTORIAL_GROUPS...\n"
+ + "Example: " + COMMAND_WORD + PREFIX_TUTORIAL_GROUP + "CS2103-W15-3" + " "
+ + PREFIX_TUTORIAL_GROUP + "CS2101 G08";
+
+ public static final String MESSAGE_TUTORIAL_GROUP_DELETE_SUCCESS = "Deleted tutorial group(s): %1$s";
+
+ private final Set tutorialGroupsToDelete;
+
+ public DeleteTutorialGroupsFromStudentsCommand(Set tutorialGroupsToDelete) {
+ this.tutorialGroupsToDelete = tutorialGroupsToDelete;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List studentList = model.getSortedStudentList();
+ List studentsToRemoveTutorialGroup = new ArrayList<>();
+ for (Student student : studentList) {
+ studentsToRemoveTutorialGroup.add(student);
+ }
+
+ for (Student studentToRemoveTutorialGroup : studentsToRemoveTutorialGroup) {
+ Set updatedTutorialGroupForStudent = removeTutorialGroups(
+ studentToRemoveTutorialGroup.getTutorialGroups(), tutorialGroupsToDelete);
+ if (updatedTutorialGroupForStudent.size() == 0) {
+ model.deleteStudent(studentToRemoveTutorialGroup);
+ } else {
+ Student updatedStudent = createNewStudent(studentToRemoveTutorialGroup, updatedTutorialGroupForStudent);
+ model.setStudent(studentToRemoveTutorialGroup, updatedStudent);
+ }
+ }
+
+ model.updateFilteredStudentList(Model.PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(String.format(MESSAGE_TUTORIAL_GROUP_DELETE_SUCCESS,
+ tutorialGroupsToDelete.toString()));
+ }
+
+ private static Set removeTutorialGroups(Set targetTutorialGroups,
+ Set tutorialGroupsToRemove) {
+ Set updatedTutorialGroup = new HashSet<>();
+ updatedTutorialGroup.addAll(targetTutorialGroups);
+ for (TutorialGroup tgtr : tutorialGroupsToRemove) {
+ for (TutorialGroup ttg : targetTutorialGroups) {
+ if (ttg.equals(tgtr)) {
+ updatedTutorialGroup.remove(ttg);
+ }
+ }
+ }
+ return updatedTutorialGroup;
+ }
+
+ /**
+ * Creates and returns a {@code Student} with the details of {@code studentToEdit}
+ * edited with {@code Set}.
+ */
+ private static Student createNewStudent(Student studentToEdit, Set newTutorialGroup) {
+ assert studentToEdit != null;
+
+ Name currName = studentToEdit.getName();
+ Email currEmail = studentToEdit.getEmail();
+
+ Telegram currTelegram = studentToEdit.getTelegram();
+ GitHub currGitHub = studentToEdit.getGitHub();
+
+ return new Student(currName, currTelegram, currEmail, currGitHub, newTutorialGroup);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteTutorialGroupsFromStudentsCommand // instanceof handles nulls
+ && tutorialGroupsToDelete.equals(((DeleteTutorialGroupsFromStudentsCommand) other)
+ .tutorialGroupsToDelete)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 7e36114902f..c7406d1294a 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -1,105 +1,126 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
+import javafx.collections.transformation.FilteredList;
import seedu.address.commons.core.Messages;
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.CollectionUtil;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
- * Edits the details of an existing person in the address book.
+ * Edits the details of an existing student in the address book.
*/
public class EditCommand extends Command {
public static final String COMMAND_WORD = "edit";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the student identified "
+ + "by the index number used in the displayed student list. "
+ "Existing values will be overwritten by the input values.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "[" + PREFIX_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_TELEGRAM + "TELEGRAM] "
+ + "[" + PREFIX_GITHUB + "GITHUB] "
+ + "[" + PREFIX_TUTORIAL_GROUP + "TUTORIAL_GROUP]...\n"
+ "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
+ + PREFIX_TELEGRAM + "johndoe "
+ + PREFIX_EMAIL + "e0123456@u.nus.edu";
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
+ public static final String MESSAGE_EDIT_STUDENT_SUCCESS = "Edited Student: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
+ public static final String MESSAGE_DUPLICATE_STUDENT = "This student already exists in the address book.";
+ public static final String MESSAGE_INDEX_OUT_OF_RANGE = String.format(
+ Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, "Index is larger than the number of "
+ + "students in the viewed list.");
private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
+ private final EditStudentDescriptor editStudentDescriptor;
/**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
+ * @param index of the student in the filtered student list to edit
+ * @param editStudentDescriptor details to edit the student with
*/
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
+ public EditCommand(Index index, EditStudentDescriptor editStudentDescriptor) {
requireNonNull(index);
- requireNonNull(editPersonDescriptor);
+ requireNonNull(editStudentDescriptor);
this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
+ this.editStudentDescriptor = new EditStudentDescriptor(editStudentDescriptor);
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredStudentList();
if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(MESSAGE_INDEX_OUT_OF_RANGE);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+ Student editedStudent = createEditedStudent(studentToEdit, editStudentDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
}
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
+ model.setStudent(studentToEdit, editedStudent);
+
+ //keep the current list of filtered student and edited student
+ if (!model.getFilteredStudentList().equals(model.getSortedStudentList())) {
+ FilteredList filteredStudents = (FilteredList) model.getFilteredStudentList();
+
+ @SuppressWarnings("unchecked")
+ //test.getPredicate() must be a Predicate type
+ Predicate predicateForFilteredStudents = (Predicate) filteredStudents.getPredicate();
+
+ Predicate predicateToObtainEditedStudent = (Student s) -> s.equals(editedStudent);
+
+ model.updateFilteredStudentList(predicateForFilteredStudents.or(predicateToObtainEditedStudent));
+ } else {
+ //the list is not filtered, show all students
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ }
+ return new CommandResult(String.format(MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent));
}
/**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
+ * Creates and returns a {@code Student} with the details of {@code studentToEdit}
+ * edited with {@code editStudentDescriptor}.
*/
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
+ private static Student createEditedStudent(Student studentToEdit, EditStudentDescriptor editStudentDescriptor) {
+ assert studentToEdit != null;
- Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
- Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
- Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
- Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
+ Name updatedName = editStudentDescriptor.getName().orElse(studentToEdit.getName());
+ Email updatedEmail = editStudentDescriptor.getEmail().orElse(studentToEdit.getEmail());
+ Telegram updatedTelegram = editStudentDescriptor.getTelegram().orElse(studentToEdit.getTelegram());
+ GitHub updatedGitHub = editStudentDescriptor.getGitHub().orElse(studentToEdit.getGitHub());
+ Set updatedTutorialGroups = editStudentDescriptor.getTutorialGroups()
+ .orElse(studentToEdit.getTutorialGroups());
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ return new Student(updatedName, updatedTelegram, updatedEmail, updatedGitHub, updatedTutorialGroups);
}
@Override
@@ -117,39 +138,39 @@ public boolean equals(Object other) {
// state check
EditCommand e = (EditCommand) other;
return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
+ && editStudentDescriptor.equals(e.editStudentDescriptor);
}
/**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
+ * Stores the details to edit the student with. Each non-empty field value will replace the
+ * corresponding field value of the student.
*/
- public static class EditPersonDescriptor {
+ public static class EditStudentDescriptor {
private Name name;
- private Phone phone;
+ private Telegram telegram;
private Email email;
- private Address address;
- private Set tags;
+ private GitHub gitHub;
+ private Set tutorialGroups;
- public EditPersonDescriptor() {}
+ public EditStudentDescriptor() {}
/**
* Copy constructor.
- * A defensive copy of {@code tags} is used internally.
+ * A defensive copy of {@code tutorialGroups} is used internally.
*/
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
+ public EditStudentDescriptor(EditStudentDescriptor toCopy) {
setName(toCopy.name);
- setPhone(toCopy.phone);
+ setTelegram(toCopy.telegram);
setEmail(toCopy.email);
- setAddress(toCopy.address);
- setTags(toCopy.tags);
+ setGitHub(toCopy.gitHub);
+ setTutorialGroups(toCopy.tutorialGroups);
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(name, telegram, email, gitHub, tutorialGroups);
}
public void setName(Name name) {
@@ -160,12 +181,12 @@ public Optional getName() {
return Optional.ofNullable(name);
}
- public void setPhone(Phone phone) {
- this.phone = phone;
+ public void setTelegram(Telegram telegram) {
+ this.telegram = telegram;
}
- public Optional getPhone() {
- return Optional.ofNullable(phone);
+ public Optional getTelegram() {
+ return Optional.ofNullable(telegram);
}
public void setEmail(Email email) {
@@ -176,29 +197,30 @@ public Optional getEmail() {
return Optional.ofNullable(email);
}
- public void setAddress(Address address) {
- this.address = address;
+ public void setGitHub(GitHub gitHub) {
+ this.gitHub = gitHub;
}
- public Optional getAddress() {
- return Optional.ofNullable(address);
+ public Optional getGitHub() {
+ return Optional.ofNullable(gitHub);
}
/**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
+ * Sets {@code tutorialGroups} to this object's {@code tutorialGroups}.
+ * A defensive copy of {@code tutorialGroups} is used internally.
*/
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ public void setTutorialGroups(Set tutorialGroups) {
+ this.tutorialGroups = (tutorialGroups != null) ? new HashSet<>(tutorialGroups) : null;
}
/**
* Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
+ * Returns {@code Optional#empty()} if {@code tutorialGroups} is null.
*/
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ public Optional> getTutorialGroups() {
+ return (tutorialGroups != null)
+ ? Optional.of(Collections.unmodifiableSet(tutorialGroups)) : Optional.empty();
}
@Override
@@ -209,18 +231,18 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
+ if (!(other instanceof EditStudentDescriptor)) {
return false;
}
// state check
- EditPersonDescriptor e = (EditPersonDescriptor) other;
+ EditStudentDescriptor e = (EditStudentDescriptor) other;
return getName().equals(e.getName())
- && getPhone().equals(e.getPhone())
+ && getTelegram().equals(e.getTelegram())
&& getEmail().equals(e.getEmail())
- && getAddress().equals(e.getAddress())
- && getTags().equals(e.getTags());
+ && getGitHub().equals(e.getGitHub())
+ && getTutorialGroups().equals(e.getTutorialGroups());
}
}
}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index d6b19b0a0de..a5544180806 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -4,20 +4,20 @@
import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
+ * Finds and lists all students in address book whose name contains all the argument keywords.
* Keyword matching is case insensitive.
*/
public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all students whose names contain all of "
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
+ + "Example: " + COMMAND_WORD + " John Smith";
private final NameContainsKeywordsPredicate predicate;
@@ -28,9 +28,9 @@ public FindCommand(NameContainsKeywordsPredicate predicate) {
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(predicate);
+ model.updateFilteredStudentList(predicate);
return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ String.format(Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW, model.getFilteredStudentList().size()));
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/FindTutorialGroupCommand.java b/src/main/java/seedu/address/logic/commands/FindTutorialGroupCommand.java
new file mode 100644
index 00000000000..b986d24f373
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindTutorialGroupCommand.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.tutorialgroup.TutorialGroupKeywordsPredicate;
+
+public class FindTutorialGroupCommand extends Command {
+ public static final String COMMAND_WORD = "findtg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all students in a tutorial group "
+ + "sorted (alphabetical order) and displays them as a list with index numbers.\n"
+ + "Parameters: Module code and Tutorial name\n"
+ + "Example: " + COMMAND_WORD + " CS2103T W15-3";
+
+ private final TutorialGroupKeywordsPredicate predicate;
+
+ public FindTutorialGroupCommand(TutorialGroupKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredStudentList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW, model.getFilteredStudentList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindTutorialGroupCommand // instanceof handles nulls
+ && predicate.equals(((FindTutorialGroupCommand) other).predicate)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..77ab100be7c 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -1,24 +1,24 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
import seedu.address.model.Model;
/**
- * Lists all persons in the address book to the user.
+ * Lists all students in the address book to the user.
*/
public class ListCommand extends Command {
public static final String COMMAND_WORD = "list";
- public static final String MESSAGE_SUCCESS = "Listed all persons";
+ public static final String MESSAGE_SUCCESS = "Listed all students";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
deleted file mode 100644
index 3b8bfa035e8..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-import java.util.stream.Stream;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new AddCommand object
- */
-public class AddCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the AddCommand
- * and returns an AddCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- }
-
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
- Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
- Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
-
- return new AddCommand(person);
- }
-
- /**
- * Returns true if none of the prefixes contains empty {@code Optional} values in the given
- * {@code ArgumentMultimap}.
- */
- private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
- return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddStudentCommandParser.java b/src/main/java/seedu/address/logic/parser/AddStudentCommandParser.java
new file mode 100644
index 00000000000..8f042573eec
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddStudentCommandParser.java
@@ -0,0 +1,67 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddStudentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new AddStudentCommand object
+ */
+public class AddStudentCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddStudentCommand
+ * and returns an AddStudentCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddStudentCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TELEGRAM, PREFIX_EMAIL,
+ PREFIX_GITHUB, PREFIX_TUTORIAL_GROUP);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_EMAIL, PREFIX_TUTORIAL_GROUP)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddStudentCommand.MESSAGE_USAGE));
+ }
+
+ String telegramString = argMultimap.getValue(PREFIX_TELEGRAM).isPresent()
+ ? argMultimap.getValue(PREFIX_TELEGRAM).get() : null;
+ String gitHubString = argMultimap.getValue(PREFIX_GITHUB).isPresent()
+ ? argMultimap.getValue(PREFIX_GITHUB).get() : null;
+
+ Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
+ Telegram telegram = ParserUtil.parseTelegram(telegramString);
+ Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
+ GitHub gitHub = ParserUtil.parseGitHub(gitHubString);
+ Set tutorialGroupList = ParserUtil.parseTutorialGroups(
+ argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP));
+
+ Student student = new Student(name, telegram, email, gitHub, tutorialGroupList);
+
+ return new AddStudentCommand(student);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddTutorialGroupParser.java b/src/main/java/seedu/address/logic/parser/AddTutorialGroupParser.java
new file mode 100644
index 00000000000..7e6cf7d0866
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddTutorialGroupParser.java
@@ -0,0 +1,56 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.Set;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddTutorialGroupCommand;
+import seedu.address.logic.commands.AddTutorialGroupCommand.AddTutorialGroupDescriptor;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new AddTutorialGroupCommand object
+ */
+public class AddTutorialGroupParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddTutorialGroupCommand
+ * and returns an AddTutorialGroupCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddTutorialGroupCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_TUTORIAL_GROUP);
+
+ // Exception thrown if prefix or value missing
+ if (argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP).isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddTutorialGroupCommand.MESSAGE_USAGE));
+ }
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, pe.getMessage()));
+ }
+
+ AddTutorialGroupDescriptor addTutorialGroupDescriptor = new AddTutorialGroupDescriptor();
+ Set tutorialGroupList = ParserUtil.parseTutorialGroups(argMultimap
+ .getAllValues(PREFIX_TUTORIAL_GROUP));
+ addTutorialGroupDescriptor.setTutorialGroups(tutorialGroupList);
+
+ if (!addTutorialGroupDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(AddTutorialGroupCommand.MESSAGE_NOT_ADDED);
+ }
+
+ return new AddTutorialGroupCommand(index, addTutorialGroupDescriptor);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 1e466792b46..d544a5f1a66 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -6,13 +6,17 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddStudentCommand;
+import seedu.address.logic.commands.AddTutorialGroupCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.logic.commands.DeleteTutorialGroupCommand;
+import seedu.address.logic.commands.DeleteTutorialGroupsFromStudentsCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindTutorialGroupCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.parser.exceptions.ParseException;
@@ -44,8 +48,8 @@ public Command parseCommand(String userInput) throws ParseException {
final String arguments = matcher.group("arguments");
switch (commandWord) {
- case AddCommand.COMMAND_WORD:
- return new AddCommandParser().parse(arguments);
+ case AddStudentCommand.COMMAND_WORD:
+ return new AddStudentCommandParser().parse(arguments);
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
@@ -59,6 +63,9 @@ public Command parseCommand(String userInput) throws ParseException {
case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);
+ case FindTutorialGroupCommand.COMMAND_WORD:
+ return new FindTutorialGroupParser().parse(arguments);
+
case ListCommand.COMMAND_WORD:
return new ListCommand();
@@ -68,6 +75,15 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case AddTutorialGroupCommand.COMMAND_WORD:
+ return new AddTutorialGroupParser().parse(arguments);
+
+ case DeleteTutorialGroupsFromStudentsCommand.COMMAND_WORD:
+ return new DeleteTutorialGroupsFromStudentsParser().parse(arguments);
+
+ case DeleteTutorialGroupCommand.COMMAND_WORD:
+ return new DeleteTutorialGroupParser().parse(arguments);
+
default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..fc1ac418bcc 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -7,9 +7,9 @@ public class CliSyntax {
/* Prefix definitions */
public static final Prefix PREFIX_NAME = new Prefix("n/");
- public static final Prefix PREFIX_PHONE = new Prefix("p/");
+ public static final Prefix PREFIX_TELEGRAM = new Prefix("t/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
- public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
- public static final Prefix PREFIX_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_GITHUB = new Prefix("g/");
+ public static final Prefix PREFIX_TUTORIAL_GROUP = new Prefix("tg/");
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 522b93081cc..e553e7f363f 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -1,6 +1,6 @@
package seedu.address.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.DeleteCommand;
@@ -22,7 +22,7 @@ public DeleteCommand parse(String args) throws ParseException {
return new DeleteCommand(index);
} catch (ParseException pe) {
throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+ String.format(String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, pe.getMessage())));
}
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteTutorialGroupParser.java b/src/main/java/seedu/address/logic/parser/DeleteTutorialGroupParser.java
new file mode 100644
index 00000000000..ab31e4cb597
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteTutorialGroupParser.java
@@ -0,0 +1,55 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteTutorialGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new DeleteTutorialGroupCommand object
+ */
+public class DeleteTutorialGroupParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteTutorialGroupCommand
+ * and returns a DeleteTutorialGroupCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform with the expected format.
+ */
+ public DeleteTutorialGroupCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_TUTORIAL_GROUP);
+
+ // Exception thrown if prefix or value missing
+ if (argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP).isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTutorialGroupCommand.MESSAGE_USAGE));
+ }
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, pe.getMessage()));
+ }
+
+ // Exception thrown if more than one value
+ if (argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP).size() > 1) {
+ throw new ParseException(DeleteTutorialGroupCommand.MESSAGE_NOT_DELETED);
+ }
+
+ assert argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP).size() == 1;
+
+ TutorialGroup tutorialGroupToDelete = ParserUtil.parseTutorialGroup(argMultimap
+ .getAllValues(PREFIX_TUTORIAL_GROUP)
+ .get(0));
+
+ return new DeleteTutorialGroupCommand(index, tutorialGroupToDelete);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteTutorialGroupsFromStudentsParser.java b/src/main/java/seedu/address/logic/parser/DeleteTutorialGroupsFromStudentsParser.java
new file mode 100644
index 00000000000..00062028466
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteTutorialGroupsFromStudentsParser.java
@@ -0,0 +1,40 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.Set;
+
+import seedu.address.logic.commands.DeleteTutorialGroupsFromStudentsCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new DeleteTutorialGroupsFromStudents object
+ */
+public class DeleteTutorialGroupsFromStudentsParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteTutorialGroupsFromStudentsCommand
+ * and returns a DeleteTutorialGroupsFromStudentsCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteTutorialGroupsFromStudentsCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_TUTORIAL_GROUP);
+
+ // Exception thrown if prefix or value missing
+ if (argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP).isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTutorialGroupsFromStudentsCommand.MESSAGE_USAGE));
+ }
+
+ Set tutorialGroupListToDelete = ParserUtil.parseTutorialGroups(argMultimap
+ .getAllValues(PREFIX_TUTORIAL_GROUP));
+
+ return new DeleteTutorialGroupsFromStudentsCommand(tutorialGroupListToDelete);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 845644b7dea..f0bdbe032ad 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -1,23 +1,22 @@
package seedu.address.logic.parser;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
import java.util.Collection;
-import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditCommand.EditStudentDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
* Parses input arguments and creates a new EditCommand object
@@ -32,51 +31,64 @@ public class EditCommandParser implements Parser {
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TELEGRAM,
+ PREFIX_EMAIL, PREFIX_GITHUB, PREFIX_TUTORIAL_GROUP);
Index index;
try {
index = ParserUtil.parseIndex(argMultimap.getPreamble());
} catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
+ throw new ParseException(String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, pe.getMessage()));
}
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
+ EditStudentDescriptor editStudentDescriptor = new EditCommand.EditStudentDescriptor();
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
+ editStudentDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
}
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ if (argMultimap.getValue(PREFIX_TELEGRAM).isPresent()) {
+ if ((argMultimap.getValue(PREFIX_TELEGRAM).get().equals(""))) {
+ editStudentDescriptor.setTelegram(ParserUtil.parseTelegram(null));
+ } else {
+ editStudentDescriptor.setTelegram(ParserUtil.parseTelegram(
+ argMultimap.getValue(PREFIX_TELEGRAM).get()));
+ }
}
if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ editStudentDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
}
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ if (argMultimap.getValue(PREFIX_GITHUB).isPresent()) {
+ if ((argMultimap.getValue(PREFIX_GITHUB).get().equals(""))) {
+ editStudentDescriptor.setGitHub(ParserUtil.parseGitHub(null));
+ } else {
+ editStudentDescriptor.setGitHub(ParserUtil.parseGitHub(argMultimap.getValue(PREFIX_GITHUB).get()));
+ }
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
+ parseTutorialGroupsForEdit(argMultimap.getAllValues(PREFIX_TUTORIAL_GROUP))
+ .ifPresent(editStudentDescriptor::setTutorialGroups);
- if (!editPersonDescriptor.isAnyFieldEdited()) {
+ if (!editStudentDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
}
- return new EditCommand(index, editPersonDescriptor);
+ return new EditCommand(index, editStudentDescriptor);
}
/**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
+ * Parses {@code Collection tutorialGroups} into a {@code Set} given that
+ * {@code tutorialGroups} is non-empty.
+ *
+ * @throws ParseException if {@code tutorialGroups} contain only one element which is an empty string
*/
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
+ private Optional> parseTutorialGroupsForEdit(
+ Collection tutorialGroups) throws ParseException {
+ assert tutorialGroups != null;
- if (tags.isEmpty()) {
+ if (tutorialGroups.isEmpty()) {
return Optional.empty();
}
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
+
+ return Optional.of(ParserUtil.parseTutorialGroups(tutorialGroups));
}
}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 4fb71f23103..9e0833aca08 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -6,7 +6,7 @@
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
/**
* Parses input arguments and creates a new FindCommand object
diff --git a/src/main/java/seedu/address/logic/parser/FindTutorialGroupParser.java b/src/main/java/seedu/address/logic/parser/FindTutorialGroupParser.java
new file mode 100644
index 00000000000..872357b201b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindTutorialGroupParser.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FindTutorialGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tutorialgroup.TutorialGroupKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindTutorialGroupCommand object
+ */
+public class FindTutorialGroupParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindTutorialGroupCommand
+ * and returns a FindTutorialGroupCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindTutorialGroupCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindTutorialGroupCommand.MESSAGE_USAGE));
+ }
+
+ // Check for presence of whitespace
+ int whitespacePos = trimmedArgs.indexOf(" ");
+ if (whitespacePos == -1) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindTutorialGroupCommand.MESSAGE_USAGE));
+ }
+
+ // remove extra whitespaces
+ String moduleCode = trimmedArgs.substring(0, whitespacePos).trim();
+ String trimmedGroup = trimmedArgs.substring(whitespacePos).trim();
+ String trimmedTutorialGroup = moduleCode + " " + trimmedGroup;
+ return new FindTutorialGroupCommand(new TutorialGroupKeywordsPredicate(trimmedTutorialGroup));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..619dc5e1342 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -9,19 +9,17 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
*/
public class ParserUtil {
- public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
-
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
@@ -29,9 +27,10 @@ public class ParserUtil {
*/
public static Index parseIndex(String oneBasedIndex) throws ParseException {
String trimmedIndex = oneBasedIndex.trim();
- if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
- throw new ParseException(MESSAGE_INVALID_INDEX);
+ if (!StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit(trimmedIndex)) {
+ throw new ParseException(Index.MESSAGE_CONSTRAINT);
}
+
return Index.fromOneBased(Integer.parseInt(trimmedIndex));
}
@@ -51,33 +50,37 @@ public static Name parseName(String name) throws ParseException {
}
/**
- * Parses a {@code String phone} into a {@code Phone}.
+ * Parses a {@code String telegram} into a {@code Telegram}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code phone} is invalid.
+ * @throws ParseException if the given {@code telegram} is invalid.
*/
- public static Phone parsePhone(String phone) throws ParseException {
- requireNonNull(phone);
- String trimmedPhone = phone.trim();
- if (!Phone.isValidPhone(trimmedPhone)) {
- throw new ParseException(Phone.MESSAGE_CONSTRAINTS);
+ public static Telegram parseTelegram(String telegram) throws ParseException {
+ if (telegram == null) {
+ return new Telegram(null);
}
- return new Phone(trimmedPhone);
+ String trimmedTelegram = telegram.trim();
+ if (!Telegram.isValidTelegram(trimmedTelegram)) {
+ throw new ParseException(Telegram.MESSAGE_CONSTRAINTS);
+ }
+ return new Telegram(trimmedTelegram);
}
/**
- * Parses a {@code String address} into an {@code Address}.
+ * Parses a {@code String gitHub} into an {@code GitHub}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code address} is invalid.
+ * @throws ParseException if the given {@code gitHub} is invalid.
*/
- public static Address parseAddress(String address) throws ParseException {
- requireNonNull(address);
- String trimmedAddress = address.trim();
- if (!Address.isValidAddress(trimmedAddress)) {
- throw new ParseException(Address.MESSAGE_CONSTRAINTS);
+ public static GitHub parseGitHub(String gitHub) throws ParseException {
+ if (gitHub == null) {
+ return new GitHub(null);
+ }
+ String trimmedGitHub = gitHub.trim();
+ if (!GitHub.isValidGitHub(trimmedGitHub)) {
+ throw new ParseException(GitHub.MESSAGE_CONSTRAINTS);
}
- return new Address(trimmedAddress);
+ return new GitHub(trimmedGitHub);
}
/**
@@ -96,29 +99,29 @@ public static Email parseEmail(String email) throws ParseException {
}
/**
- * Parses a {@code String tag} into a {@code Tag}.
+ * Parses a {@code String tutorialGroup} into a {@code TutorialGroup}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code tag} is invalid.
+ * @throws ParseException if the given {@code tutorialGroup} is invalid.
*/
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ public static TutorialGroup parseTutorialGroup(String tutorialGroup) throws ParseException {
+ requireNonNull(tutorialGroup);
+ String trimmedTutorialGroup = tutorialGroup.trim();
+ if (!TutorialGroup.isValidTutorialGroupName(trimmedTutorialGroup)) {
+ throw new ParseException(TutorialGroup.MESSAGE_CONSTRAINTS);
}
- return new Tag(trimmedTag);
+ return new TutorialGroup(trimmedTutorialGroup.toUpperCase());
}
/**
- * Parses {@code Collection tags} into a {@code Set}.
+ * Parses {@code Collection tutorialGroups} into a {@code Set}.
*/
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
+ public static Set parseTutorialGroups(Collection tutorialGroups) throws ParseException {
+ requireNonNull(tutorialGroups);
+ final Set tutorialGroupSet = new HashSet<>();
+ for (String tutorialGroupName : tutorialGroups) {
+ tutorialGroupSet.add(parseTutorialGroup(tutorialGroupName));
}
- return tagSet;
+ return tutorialGroupSet;
}
}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
index 1a943a0781a..2691cd5ba10 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/seedu/address/model/AddressBook.java
@@ -5,8 +5,8 @@
import java.util.List;
import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.UniqueStudentList;
/**
* Wraps all data at the address-book level
@@ -14,7 +14,7 @@
*/
public class AddressBook implements ReadOnlyAddressBook {
- private final UniquePersonList persons;
+ private final UniqueStudentList students;
/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
@@ -24,13 +24,13 @@ public class AddressBook implements ReadOnlyAddressBook {
* among constructors.
*/
{
- persons = new UniquePersonList();
+ students = new UniqueStudentList();
}
public AddressBook() {}
/**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
+ * Creates an AddressBook using the Students in the {@code toBeCopied}
*/
public AddressBook(ReadOnlyAddressBook toBeCopied) {
this();
@@ -40,11 +40,11 @@ public AddressBook(ReadOnlyAddressBook toBeCopied) {
//// list overwrite operations
/**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
+ * Replaces the contents of the student list with {@code students}.
+ * {@code students} must not contain duplicate students.
*/
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
+ public void setStudents(List students) {
+ this.students.setStudents(students);
}
/**
@@ -53,68 +53,69 @@ public void setPersons(List persons) {
public void resetData(ReadOnlyAddressBook newData) {
requireNonNull(newData);
- setPersons(newData.getPersonList());
+ setStudents(newData.getStudentList());
}
- //// person-level operations
+ //// student-level operations
/**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
+ * Returns true if a student with the same identity as {@code student} exists in the address book.
*/
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
+ public boolean hasStudent(Student student) {
+ requireNonNull(student);
+ return students.contains(student);
}
/**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
+ * Adds a student to the address book.
+ * The student must not already exist in the address book.
*/
- public void addPerson(Person p) {
- persons.add(p);
+ public void addStudent(Student s) {
+ students.add(s);
}
/**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
+ * Replaces the given student {@code target} in the list with {@code editedStudent}.
* {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
+ * The student identity of {@code editedStudent} must not
+ * be the same as another existing student in the address book.
*/
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
+ public void setStudent(Student target, Student editedStudent) {
+ requireNonNull(editedStudent);
- persons.setPerson(target, editedPerson);
+ students.setStudent(target, editedStudent);
}
/**
* Removes {@code key} from this {@code AddressBook}.
* {@code key} must exist in the address book.
*/
- public void removePerson(Person key) {
- persons.remove(key);
+ public void removeStudent(Student key) {
+ students.remove(key);
}
//// util methods
@Override
public String toString() {
- return persons.asUnmodifiableObservableList().size() + " persons";
+ return students.asUnmodifiableObservableList().size() + " students";
// TODO: refine later
}
@Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
+ public ObservableList getStudentList() {
+ return students.asUnmodifiableObservableList();
}
@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof AddressBook // instanceof handles nulls
- && persons.equals(((AddressBook) other).persons));
+ && students.equals(((AddressBook) other).students));
}
@Override
public int hashCode() {
- return persons.hashCode();
+ return students.hashCode();
}
}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..efd2972b423 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -5,14 +5,14 @@
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* The API of the Model component.
*/
public interface Model {
/** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ Predicate PREDICATE_SHOW_ALL_STUDENTS = unused -> true;
/**
* Replaces user prefs data with the data in {@code userPrefs}.
@@ -53,35 +53,40 @@ public interface Model {
ReadOnlyAddressBook getAddressBook();
/**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
+ * Returns true if a student with the same identity as {@code student} exists in the address book.
*/
- boolean hasPerson(Person person);
+ boolean hasStudent(Student student);
/**
- * Deletes the given person.
- * The person must exist in the address book.
+ * Deletes the given student.
+ * The student must exist in the address book.
*/
- void deletePerson(Person target);
+ void deleteStudent(Student target);
/**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
+ * Adds the given student.
+ * {@code student} must not already exist in the address book.
*/
- void addPerson(Person person);
+ void addStudent(Student student);
/**
- * Replaces the given person {@code target} with {@code editedPerson}.
+ * Replaces the given student {@code target} with {@code editedStudent}.
* {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
+ * The student identity of {@code editedStudent} must not
+ * be the same as another existing student in the address book.
*/
- void setPerson(Person target, Person editedPerson);
+ void setStudent(Student target, Student editedStudent);
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the filtered student list */
+ ObservableList getFilteredStudentList();
/**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
+ * Updates the filter of the filtered student list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
- void updateFilteredPersonList(Predicate predicate);
+ void updateFilteredStudentList(Predicate predicate);
+
+ /** Returns an unmodifiable view of the student list in address book in sorted order
+ */
+ ObservableList getSortedStudentList();
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 86c1df298d7..a2250b6cb08 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -9,9 +9,10 @@
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
+import javafx.collections.transformation.SortedList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* Represents the in-memory model of the address book data.
@@ -21,7 +22,8 @@ public class ModelManager implements Model {
private final AddressBook addressBook;
private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
+ private final FilteredList filteredStudents;
+ private final SortedList sortedStudents;
/**
* Initializes a ModelManager with the given addressBook and userPrefs.
@@ -33,7 +35,8 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs
this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ sortedStudents = new SortedList(this.addressBook.getStudentList().sorted());
+ filteredStudents = new FilteredList<>(sortedStudents);
}
public ModelManager() {
@@ -88,44 +91,49 @@ public ReadOnlyAddressBook getAddressBook() {
}
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
+ public boolean hasStudent(Student student) {
+ requireNonNull(student);
+ return addressBook.hasStudent(student);
}
@Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
+ public void deleteStudent(Student target) {
+ addressBook.removeStudent(target);
}
@Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ public void addStudent(Student student) {
+ addressBook.addStudent(student);
+ updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
}
@Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
+ public void setStudent(Student target, Student editedStudent) {
+ requireAllNonNull(target, editedStudent);
- addressBook.setPerson(target, editedPerson);
+ addressBook.setStudent(target, editedStudent);
}
- //=========== Filtered Person List Accessors =============================================================
+ @Override
+ public ObservableList getSortedStudentList() {
+ return sortedStudents;
+ }
+
+ //=========== Filtered Student List Accessors =============================================================
/**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
+ * Returns an unmodifiable view of the list of {@code Student} backed by the internal list of
* {@code versionedAddressBook}
*/
@Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
+ public ObservableList getFilteredStudentList() {
+ return filteredStudents;
}
@Override
- public void updateFilteredPersonList(Predicate predicate) {
+ public void updateFilteredStudentList(Predicate predicate) {
requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
+ filteredStudents.setPredicate(predicate);
}
@Override
@@ -144,7 +152,7 @@ public boolean equals(Object obj) {
ModelManager other = (ModelManager) obj;
return addressBook.equals(other.addressBook)
&& userPrefs.equals(other.userPrefs)
- && filteredPersons.equals(other.filteredPersons);
+ && filteredStudents.equals(other.filteredStudents);
}
}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
index 6ddc2cd9a29..4fac98ec6b0 100644
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
@@ -1,7 +1,7 @@
package seedu.address.model;
import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* Unmodifiable view of an address book
@@ -9,9 +9,9 @@
public interface ReadOnlyAddressBook {
/**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
+ * Returns an unmodifiable view of the students list.
+ * This list will not contain any duplicate students.
*/
- ObservableList getPersonList();
+ ObservableList getStudentList();
}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
deleted file mode 100644
index 60472ca22a0..00000000000
--- a/src/main/java/seedu/address/model/person/Address.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's address in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
- */
-public class Address {
-
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[^\\s].*";
-
- public final String value;
-
- /**
- * Constructs an {@code Address}.
- *
- * @param address A valid address.
- */
- public Address(String address) {
- requireNonNull(address);
- checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS);
- value = address;
- }
-
- /**
- * Returns true if a given string is a valid email.
- */
- public static boolean isValidAddress(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Address // instanceof handles nulls
- && value.equals(((Address) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
deleted file mode 100644
index 8ff1d83fe89..00000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package seedu.address.model.person;
-
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.model.tag.Tag;
-
-/**
- * Represents a Person in the address book.
- * Guarantees: details are present and not null, field values are validated, immutable.
- */
-public class Person {
-
- // Identity fields
- private final Name name;
- private final Phone phone;
- private final Email email;
-
- // Data fields
- private final Address address;
- private final Set tags = new HashSet<>();
-
- /**
- * Every field must be present and not null.
- */
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- this.tags.addAll(tags);
- }
-
- public Name getName() {
- return name;
- }
-
- public Phone getPhone() {
- return phone;
- }
-
- public Email getEmail() {
- return email;
- }
-
- public Address getAddress() {
- return address;
- }
-
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
- }
-
- /**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
- */
- public boolean isSamePerson(Person otherPerson) {
- if (otherPerson == this) {
- return true;
- }
-
- return otherPerson != null
- && otherPerson.getName().equals(getName());
- }
-
- /**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Person)) {
- return false;
- }
-
- Person otherPerson = (Person) other;
- return otherPerson.getName().equals(getName())
- && otherPerson.getPhone().equals(getPhone())
- && otherPerson.getEmail().equals(getEmail())
- && otherPerson.getAddress().equals(getAddress())
- && otherPerson.getTags().equals(getTags());
- }
-
- @Override
- public int hashCode() {
- // use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(getName())
- .append("; Phone: ")
- .append(getPhone())
- .append("; Email: ")
- .append(getEmail())
- .append("; Address: ")
- .append(getAddress());
-
- Set tags = getTags();
- if (!tags.isEmpty()) {
- builder.append("; Tags: ");
- tags.forEach(builder::append);
- }
- return builder.toString();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
deleted file mode 100644
index 872c76b382f..00000000000
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's phone number in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
- */
-public class Phone {
-
-
- public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
- public final String value;
-
- /**
- * Constructs a {@code Phone}.
- *
- * @param phone A valid phone number.
- */
- public Phone(String phone) {
- requireNonNull(phone);
- checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS);
- value = phone;
- }
-
- /**
- * Returns true if a given string is a valid phone number.
- */
- public static boolean isValidPhone(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Phone // instanceof handles nulls
- && value.equals(((Phone) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
deleted file mode 100644
index 0fee4fe57e6..00000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-
-/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
- *
- * Supports a minimal set of list operations.
- *
- * @see Person#isSamePerson(Person)
- */
-public class UniquePersonList implements Iterable {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private final ObservableList internalUnmodifiableList =
- FXCollections.unmodifiableObservableList(internalList);
-
- /**
- * Returns true if the list contains an equivalent person as the given argument.
- */
- public boolean contains(Person toCheck) {
- requireNonNull(toCheck);
- return internalList.stream().anyMatch(toCheck::isSamePerson);
- }
-
- /**
- * Adds a person to the list.
- * The person must not already exist in the list.
- */
- public void add(Person toAdd) {
- requireNonNull(toAdd);
- if (contains(toAdd)) {
- throw new DuplicatePersonException();
- }
- internalList.add(toAdd);
- }
-
- /**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- int index = internalList.indexOf(target);
- if (index == -1) {
- throw new PersonNotFoundException();
- }
-
- if (!target.isSamePerson(editedPerson) && contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- internalList.set(index, editedPerson);
- }
-
- /**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
- */
- public void remove(Person toRemove) {
- requireNonNull(toRemove);
- if (!internalList.remove(toRemove)) {
- throw new PersonNotFoundException();
- }
- }
-
- public void setPersons(UniquePersonList replacement) {
- requireNonNull(replacement);
- internalList.setAll(replacement.internalList);
- }
-
- /**
- * Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- requireAllNonNull(persons);
- if (!personsAreUnique(persons)) {
- throw new DuplicatePersonException();
- }
-
- internalList.setAll(persons);
- }
-
- /**
- * Returns the backing list as an unmodifiable {@code ObservableList}.
- */
- public ObservableList asUnmodifiableObservableList() {
- return internalUnmodifiableList;
- }
-
- @Override
- public Iterator iterator() {
- return internalList.iterator();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof UniquePersonList // instanceof handles nulls
- && internalList.equals(((UniquePersonList) other).internalList));
- }
-
- @Override
- public int hashCode() {
- return internalList.hashCode();
- }
-
- /**
- * Returns true if {@code persons} contains only unique persons.
- */
- private boolean personsAreUnique(List persons) {
- for (int i = 0; i < persons.size() - 1; i++) {
- for (int j = i + 1; j < persons.size(); j++) {
- if (persons.get(i).isSamePerson(persons.get(j))) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
deleted file mode 100644
index d7290f59442..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
- */
-public class DuplicatePersonException extends RuntimeException {
- public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
deleted file mode 100644
index fa764426ca7..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation is unable to find the specified person.
- */
-public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/student/Email.java
similarity index 68%
rename from src/main/java/seedu/address/model/person/Email.java
rename to src/main/java/seedu/address/model/student/Email.java
index f866e7133de..850facf6207 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/seedu/address/model/student/Email.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's email in the address book.
+ * Represents a Student's email in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
*/
public class Email {
@@ -14,21 +14,15 @@ public class Email {
+ "and adhere to the following constraints:\n"
+ "1. The local-part should only contain alphanumeric characters and these special characters, excluding "
+ "the parentheses, (" + SPECIAL_CHARACTERS + "). The local-part may not start or end with any special "
- + "characters.\n"
- + "2. This is followed by a '@' and then a domain name. The domain name is made up of domain labels "
- + "separated by periods.\n"
- + "The domain name must:\n"
- + " - end with a domain label at least 2 characters long\n"
- + " - have each domain label start and end with alphanumeric characters\n"
- + " - have each domain label consist of alphanumeric characters, separated only by hyphens, if any.";
+ + "characters. The local-part cannot be longer than 64 characters.\n"
+ + "2. This is followed by a '@' and then a domain name. The domain name must be one of the following:\n"
+ + "u.nus.edu nus.edu.sg gmail.com yahoo.com outlook.com hotmail.com";
// alphanumeric and special characters
private static final String ALPHANUMERIC_NO_UNDERSCORE = "[^\\W_]+"; // alphanumeric characters except underscore
private static final String LOCAL_PART_REGEX = "^" + ALPHANUMERIC_NO_UNDERSCORE + "([" + SPECIAL_CHARACTERS + "]"
+ ALPHANUMERIC_NO_UNDERSCORE + ")*";
- private static final String DOMAIN_PART_REGEX = ALPHANUMERIC_NO_UNDERSCORE
- + "(-" + ALPHANUMERIC_NO_UNDERSCORE + ")*";
- private static final String DOMAIN_LAST_PART_REGEX = "(" + DOMAIN_PART_REGEX + "){2,}$"; // At least two chars
- private static final String DOMAIN_REGEX = "(" + DOMAIN_PART_REGEX + "\\.)*" + DOMAIN_LAST_PART_REGEX;
+ private static final String DOMAIN_REGEX = "(u\\.nus\\.edu|nus\\.edu\\.sg|gmail\\.com"
+ + "|yahoo\\.com|outlook\\.com|hotmail\\.com)";
public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" + DOMAIN_REGEX;
public final String value;
@@ -48,7 +42,12 @@ public Email(String email) {
* Returns if a given string is a valid email.
*/
public static boolean isValidEmail(String test) {
- return test.matches(VALIDATION_REGEX);
+ if (test.matches(VALIDATION_REGEX)) {
+ String[] localAndDomain = test.split("@");
+ return localAndDomain[0].length() <= 64;
+ } else {
+ return false;
+ }
}
@Override
diff --git a/src/main/java/seedu/address/model/student/GitHub.java b/src/main/java/seedu/address/model/student/GitHub.java
new file mode 100644
index 00000000000..2dd0698914a
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/GitHub.java
@@ -0,0 +1,69 @@
+package seedu.address.model.student;
+
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Student's GitHub in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidGitHub(String)}
+ */
+public class GitHub {
+
+ public static final String MESSAGE_CONSTRAINTS = "Github username must only contain alphanumeric "
+ + "characters or hyphens.\n Github username cannot have multiple consecutive hyphens.\n"
+ + " Github username cannot begin or end with a hyphen.\n"
+ + " Maximum is 39 characters and minimum of 2 characters.\n GitHub can be blank.";
+
+ /*
+ * The first character of the gitHub must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[A-Za-z0-9][A-Za-z0-9-]{0,37}[A-Za-z0-9]";
+
+ public final String value;
+
+ /**
+ * Constructs an {@code GitHub}.
+ *
+ * @param gitHub A valid gitHub.
+ */
+ public GitHub(String gitHub) {
+ if (gitHub == null) { //if gitHub is empty it will exist as an empty string
+ value = "";
+ } else {
+ checkArgument(isValidGitHub(gitHub), MESSAGE_CONSTRAINTS);
+ value = gitHub;
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid gitHub.
+ */
+ public static boolean isValidGitHub(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns true if the gitHub is null.
+ */
+ public boolean isNull() {
+ return value.equals("");
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof GitHub // instanceof handles nulls
+ && value.equals(((GitHub) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/student/Name.java
similarity index 58%
rename from src/main/java/seedu/address/model/person/Name.java
rename to src/main/java/seedu/address/model/student/Name.java
index 79244d71cf7..250fdcb14ed 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/student/Name.java
@@ -1,22 +1,26 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's name in the address book.
+ * Represents a Student's name in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
*/
public class Name {
public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+ "Names must contain letters. Can contain spaces, apostrophes and hyphens as long as they are in between "
+ + "letters. Consecutive spaces, apostrophes or hyphens are not allowed. "
+ + "Names must start with a letter. "
+ + "Numbers are allowed, but they must strictly be at the end of the name. "
+ + "Names cannot be blank and cannot be more than 100 characters long, including spaces.";
/*
* The first character of the address must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+ public static final String VALIDATION_REGEX = "[A-Za-z]([ '-]?[A-Za-z])*( \\d+)?";
public final String fullName;
@@ -27,15 +31,15 @@ public class Name {
*/
public Name(String name) {
requireNonNull(name);
- checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
+ checkArgument(isValidName(name.trim()), MESSAGE_CONSTRAINTS);
+ fullName = name.trim();
}
/**
* Returns true if a given string is a valid name.
*/
public static boolean isValidName(String test) {
- return test.matches(VALIDATION_REGEX);
+ return test.matches(VALIDATION_REGEX) && test.length() <= 100;
}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/student/NameContainsKeywordsPredicate.java
similarity index 66%
rename from src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
rename to src/main/java/seedu/address/model/student/NameContainsKeywordsPredicate.java
index c9b5868427c..848086784a4 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/student/NameContainsKeywordsPredicate.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import java.util.List;
import java.util.function.Predicate;
@@ -6,9 +6,9 @@
import seedu.address.commons.util.StringUtil;
/**
- * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ * Tests that a {@code Student}'s {@code Name} matches all the keywords given.
*/
-public class NameContainsKeywordsPredicate implements Predicate {
+public class NameContainsKeywordsPredicate implements Predicate {
private final List keywords;
public NameContainsKeywordsPredicate(List keywords) {
@@ -16,9 +16,10 @@ public NameContainsKeywordsPredicate(List keywords) {
}
@Override
- public boolean test(Person person) {
- return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ public boolean test(Student student) {
+ String keys = String.join(" ", keywords);
+ String name = student.getName().fullName;
+ return StringUtil.containsPartialSentenceIgnoreCase(name, keys);
}
@Override
diff --git a/src/main/java/seedu/address/model/student/Student.java b/src/main/java/seedu/address/model/student/Student.java
new file mode 100644
index 00000000000..cb6964f7bb7
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/Student.java
@@ -0,0 +1,183 @@
+package seedu.address.model.student;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Represents a Student in the address book.
+ * Guarantees: details except telegram and gitHub are present and not null field values are validated, immutable.
+ * Telegram and GitHub will be empty strings if the user command does not include them.
+ */
+public class Student implements Comparator {
+
+ // Identity fields
+ private final Name name;
+ private final Telegram telegram;
+ private final Email email;
+ private final GitHub gitHub;
+
+ // Data field
+ private final Set tutorialGroups = new HashSet<>();
+
+ /**
+ * Every field must be present and not null.
+ */
+ public Student(Name name, Telegram telegram, Email email, GitHub gitHub, Set tutorialGroups) {
+ requireAllNonNull(name, email, telegram, gitHub, tutorialGroups);
+ this.name = name;
+ this.telegram = telegram;
+ this.email = email;
+ this.gitHub = gitHub;
+ this.tutorialGroups.addAll(tutorialGroups);
+ }
+
+ public Name getName() {
+ return name;
+ }
+
+ public Telegram getTelegram() {
+ return telegram;
+ }
+
+ public Email getEmail() {
+ return email;
+ }
+
+ public GitHub getGitHub() {
+ return gitHub;
+ }
+
+ /**
+ * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getTutorialGroups() {
+ return Collections.unmodifiableSet(tutorialGroups);
+ }
+
+ /**
+ * Returns true if both students have the same name.
+ * This defines a weaker notion of equality between two students.
+ */
+ public boolean isSameStudent(Student otherStudent) {
+ if (otherStudent == this) {
+ return true;
+ }
+
+ return otherStudent != null
+ && otherStudent.getName().equals(getName());
+ }
+
+ /**
+ * Checks if the tutorial group already exists
+ *
+ * @param toCheck is a set of tutorial Group(s)
+ * @return if any tutorial group exists under this Student
+ */
+ public boolean tutorialGroupExists(Set toCheck) {
+ if (toCheck == null) {
+ return false;
+ }
+ for (TutorialGroup tgtc : toCheck) {
+ for (TutorialGroup tg : tutorialGroups) {
+ if (tgtc.equals(tg)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the tutorial group already exists. Is case-insensitive
+ *
+ * @param toCheck is the tutorial group to check with
+ * @return if any tutorial group exists under this student
+ */
+ public boolean tutorialGroupExists(TutorialGroup toCheck) {
+ if (toCheck == null) {
+ return false;
+ }
+ for (TutorialGroup tg : tutorialGroups) {
+ if (tg.equals(toCheck)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if both students have the same identity and data fields.
+ * This defines a stronger notion of equality between two students.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Student)) {
+ return false;
+ }
+
+ Student otherStudent = (Student) other;
+ return otherStudent.getName().equals(getName())
+ && otherStudent.getTelegram().equals(getTelegram())
+ && otherStudent.getEmail().equals(getEmail())
+ && otherStudent.getGitHub().equals(getGitHub())
+ && otherStudent.getTutorialGroups().equals(getTutorialGroups());
+ }
+
+ /**
+ * Compares its two arguments for order. Provide a way to sort the students by their name
+ *
+ * @param s1 the first student to be compared
+ * @param s2 the second student to be compared
+ * @return a negative integer, zero, or a positive integer corresponding to less than, equal to, or greater than
+ */
+ @Override
+ public int compare(Student s1, Student s2) {
+ return s1.getName().toString().compareTo(s2.getName().toString());
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(name, telegram, email, gitHub, tutorialGroups);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append(getName())
+ .append("; Email: ")
+ .append(getEmail());
+
+ if (!getTelegram().isNull()) {
+ builder.append("; Telegram: ")
+ .append(getTelegram());
+ }
+
+ if (!getGitHub().isNull()) {
+ builder.append("; GitHub: ")
+ .append(getGitHub());
+ }
+
+ Set tutorialGroups = getTutorialGroups();
+ assert !tutorialGroups.isEmpty();
+
+ builder.append("; Tutorial Groups: ");
+ tutorialGroups.forEach(builder::append);
+
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/student/Telegram.java b/src/main/java/seedu/address/model/student/Telegram.java
new file mode 100644
index 00000000000..477d118eef4
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/Telegram.java
@@ -0,0 +1,62 @@
+package seedu.address.model.student;
+
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Student's telegram in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidTelegram(String)}
+ */
+public class Telegram {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Telegram may begin with a \"{@}\" character, followed by between 5 to 32 alphanumerical "
+ + "characters, can be blank";
+ public static final String VALIDATION_REGEX = "@?\\w{5,32}";
+ public final String value;
+
+ /**
+ * Constructs a {@code Telegram}.
+ *
+ * @param telegram A valid telegram.
+ */
+ public Telegram(String telegram) {
+ if (telegram == null) { //if telegram is empty it will exist as an empty string
+ value = "";
+ } else {
+ checkArgument(isValidTelegram(telegram), MESSAGE_CONSTRAINTS);
+ value = telegram;
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid telegram.
+ */
+ public static boolean isValidTelegram(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns true if the telegram is null.
+ */
+ public boolean isNull() {
+ return value.equals("");
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Telegram // instanceof handles nulls
+ && value.equals(((Telegram) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/student/UniqueStudentList.java b/src/main/java/seedu/address/model/student/UniqueStudentList.java
new file mode 100644
index 00000000000..7325620d1b6
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/UniqueStudentList.java
@@ -0,0 +1,138 @@
+package seedu.address.model.student;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.student.exceptions.DuplicateStudentException;
+import seedu.address.model.student.exceptions.StudentNotFoundException;
+
+/**
+ * A list of students that enforces uniqueness between its elements and does not allow nulls.
+ * A student is considered unique by comparing using {@code Student#isSameStudent(Student)}.
+ * As such, adding and updating of persons uses Student#isSameStudent(Student) for equality
+ * so as to ensure that the student being added or updated is unique in terms of identity in the UniqueStudentList.
+ * However, the removal of a student uses Student#equals(Object) so
+ * as to ensure that the student with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Student#isSameStudent(Student)
+ */
+public class UniqueStudentList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent student as the given argument.
+ */
+ public boolean contains(Student toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameStudent);
+ }
+
+ /**
+ * Adds a student to the list.
+ * The student must not already exist in the list.
+ */
+ public void add(Student toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateStudentException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the student {@code target} in the list with {@code editedStudent}.
+ * {@code target} must exist in the list.
+ * The student identity of {@code editedStudent} must not be the same as another existing student in the list.
+ */
+ public void setStudent(Student target, Student editedStudent) {
+ requireAllNonNull(target, editedStudent);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new StudentNotFoundException();
+ }
+
+ if (!target.isSameStudent(editedStudent) && contains(editedStudent)) {
+ throw new DuplicateStudentException();
+ }
+
+ internalList.set(index, editedStudent);
+ }
+
+ /**
+ * Removes the equivalent student from the list.
+ * The student must exist in the list.
+ */
+ public void remove(Student toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new StudentNotFoundException();
+ }
+ }
+
+ public void setStudents(UniqueStudentList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code students}.
+ * {@code students} must not contain duplicate students.
+ */
+ public void setStudents(List students) {
+ requireAllNonNull(students);
+ if (!studentsAreUnique(students)) {
+ throw new DuplicateStudentException();
+ }
+
+ internalList.setAll(students);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof UniqueStudentList // instanceof handles nulls
+ && internalList.equals(((UniqueStudentList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code students} contains only unique students.
+ */
+ private boolean studentsAreUnique(List students) {
+ for (int i = 0; i < students.size() - 1; i++) {
+ for (int j = i + 1; j < students.size(); j++) {
+ if (students.get(i).isSameStudent(students.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/address/model/student/exceptions/DuplicateStudentException.java b/src/main/java/seedu/address/model/student/exceptions/DuplicateStudentException.java
new file mode 100644
index 00000000000..d1a8f9ce635
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/exceptions/DuplicateStudentException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.student.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Students (Students are considered duplicates if they have the
+ * same identity).
+ */
+public class DuplicateStudentException extends RuntimeException {
+ public DuplicateStudentException() {
+ super("Operation would result in duplicate students");
+ }
+}
diff --git a/src/main/java/seedu/address/model/student/exceptions/StudentNotFoundException.java b/src/main/java/seedu/address/model/student/exceptions/StudentNotFoundException.java
new file mode 100644
index 00000000000..2b41e9e0296
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/exceptions/StudentNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.address.model.student.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified student.
+ */
+public class StudentNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
deleted file mode 100644
index b0ea7e7dad7..00000000000
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package seedu.address.model.tag;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
- */
-public class Tag {
-
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
- public static final String VALIDATION_REGEX = "\\p{Alnum}+";
-
- public final String tagName;
-
- /**
- * Constructs a {@code Tag}.
- *
- * @param tagName A valid tag name.
- */
- public Tag(String tagName) {
- requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
- this.tagName = tagName;
- }
-
- /**
- * Returns true if a given string is a valid tag name.
- */
- public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Tag // instanceof handles nulls
- && tagName.equals(((Tag) other).tagName)); // state check
- }
-
- @Override
- public int hashCode() {
- return tagName.hashCode();
- }
-
- /**
- * Format state as text for viewing.
- */
- public String toString() {
- return '[' + tagName + ']';
- }
-
-}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/TutorialGroup.java b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroup.java
new file mode 100644
index 00000000000..633cdd5323c
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroup.java
@@ -0,0 +1,84 @@
+package seedu.address.model.tutorialgroup;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a TutorialGroup in the address book.
+ * Guarantees: immutable; name is valid as declared in {@link #isValidTutorialGroupName(String)}
+ */
+public class TutorialGroup {
+
+ public static final String MESSAGE_CONSTRAINTS = "Must STRICTLY consist of a module code, followed by a "
+ + "space, then the tutorial name. It should not be blank. The tutorial name must have a non-zero digit and "
+ + "cannot start or end with a hyphen. The name consist of letters or hyphens or digits or underscores."
+ + "Tutorial Group may only have a maximum of 100 characters including whitespace."
+ + "ALL letters in tutorial group inputs will be converted into uppercase letters.";
+ public static final String VALIDATION_REGEX = "[A-Za-z]{2,3}[1-8]\\d{3}[A-Za-z]{0,2} "
+ + "[\\w-]+"; // ensures correct module code and tutorial name contain letters or digits or underscores or
+ // hyphens
+
+ public final String tutorialGroupName;
+
+ /**
+ * Constructs a {@code TutorialGroup}.
+ *
+ * @param tutorialGroupName A valid tutorial group name.
+ */
+ public TutorialGroup(String tutorialGroupName) {
+ requireNonNull(tutorialGroupName);
+ assert tutorialGroupName == tutorialGroupName.toUpperCase() : "tutorial group should be in uppercase";
+ checkArgument(isValidTutorialGroupName(tutorialGroupName), MESSAGE_CONSTRAINTS);
+ this.tutorialGroupName = tutorialGroupName;
+ }
+
+ /**
+ * Returns true if a given string is a valid tutorial group name.
+ */
+ public static boolean isValidTutorialGroupName(String test) {
+ if (test.length() > 100 || !test.contains(" ")) {
+ return false;
+ }
+ String[] tutorialGroupSplitByOneWhitespace = test.split(" ", 2);
+ String tutorialName = tutorialGroupSplitByOneWhitespace[1];
+ for (int i = 1; i <= 10; i++) {
+ if (tutorialName.contains(String.format("%d", i))) {
+ break;
+ }
+ if (i == 10) {
+ return false;
+ }
+ }
+ String lastCharacterOfTutorialName = tutorialName.substring(tutorialName.length() - 1);
+ String firstCharacterOfTutorialName = tutorialName.substring(0, 1);
+ if (!lastCharacterOfTutorialName.matches("[\\w]")
+ || !firstCharacterOfTutorialName.matches("[\\w]")) {
+ //ensures tutorial name does not start and end with hyphens
+ return false;
+ }
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * {@code TutorialGroup}s are equal if they have the same tutorial group name ignoring cases.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof TutorialGroup // instanceof handles nulls
+ && tutorialGroupName.equalsIgnoreCase(((TutorialGroup) other).tutorialGroupName)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return tutorialGroupName.hashCode();
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return '[' + tutorialGroupName + ']';
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/TutorialGroupKeywordsPredicate.java b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroupKeywordsPredicate.java
new file mode 100644
index 00000000000..8827be8ba31
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroupKeywordsPredicate.java
@@ -0,0 +1,35 @@
+package seedu.address.model.tutorialgroup;
+
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.StringUtil;
+import seedu.address.model.student.Student;
+
+/**
+ * Tests that a {@code Student}'s {@code Tutorial Group} matches any of the keywords given.
+ */
+public class TutorialGroupKeywordsPredicate implements Predicate {
+ private final String keywords;
+
+ /**
+ * Constructor of the tutorial group keywords predicate class
+ * @param keywords need to match exactly to an existing tutorial group(case-insensitive)
+ */
+ public TutorialGroupKeywordsPredicate(String keywords) {
+ assert(keywords != null) : "Invalid keywords";
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Student student) {
+ return student.getTutorialGroups().stream()
+ .anyMatch(tg -> StringUtil.containsFullSentenceIgnoreCase(tg.tutorialGroupName, keywords));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof TutorialGroupKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((TutorialGroupKeywordsPredicate) other).keywords)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..b6fc5f7296e 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -6,54 +6,54 @@
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
* Contains utility methods for populating {@code AddressBook} with sample data.
*/
public class SampleDataUtil {
- public static Person[] getSamplePersons() {
- return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
- new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
+ public static Student[] getSampleStudents() {
+ return new Student[] {
+ new Student(new Name("Alex Yeoh"), new Telegram(null), new Email("alexyeoh@u.nus.edu"),
+ new GitHub("alex-yeoh"),
+ getTutorialGroupSet("CS2100 G01", "CS3230 T03")),
+ new Student(new Name("Bernice Yu"), new Telegram("bernice01"), new Email("berniceyu@u.nus.edu"),
+ new GitHub(null),
+ getTutorialGroupSet("CS2100 G01", "CS2106 T05")),
+ new Student(new Name("Charlotte Oliveiro"), new Telegram("@CharlotteO"), new Email("charlotte@u.nus.edu"),
+ new GitHub("charlotte-oliveiro"),
+ getTutorialGroupSet("CS2106 T05")),
+ new Student(new Name("David Li"), new Telegram(null), new Email("callmedavid@u.nus.edu"),
+ new GitHub(null),
+ getTutorialGroupSet("CS2100 G01")),
+ new Student(new Name("Irfan Ibrahim"), new Telegram("irfanIbrahim"), new Email("irfan@u.nus.edu"),
+ new GitHub("irfan-the-jet-plane"),
+ getTutorialGroupSet("CS2100 G01", "CS2106 T05")),
+ new Student(new Name("Roy Balakrishnan"), new Telegram("@royBalakrishnan"), new Email("royb@u.nus.edu"),
+ new GitHub("roy-balakrishnan"),
+ getTutorialGroupSet("CS2106 T05", "CS3230 T03"))
};
}
public static ReadOnlyAddressBook getSampleAddressBook() {
AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
+ for (Student sampleStudent : getSampleStudents()) {
+ sampleAb.addStudent(sampleStudent);
}
return sampleAb;
}
/**
- * Returns a tag set containing the list of strings given.
+ * Returns a tutorial group set containing the list of strings given.
*/
- public static Set getTagSet(String... strings) {
+ public static Set getTutorialGroupSet(String... strings) {
return Arrays.stream(strings)
- .map(Tag::new)
+ .map(TutorialGroup::new)
.collect(Collectors.toSet());
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
deleted file mode 100644
index a6321cec2ea..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Person}.
- */
-class JsonAdaptedPerson {
-
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
-
- private final String name;
- private final String phone;
- private final String email;
- private final String address;
- private final List tagged = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonAdaptedPerson} with the given person details.
- */
- @JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tagged") List tagged) {
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- if (tagged != null) {
- this.tagged.addAll(tagged);
- }
- }
-
- /**
- * Converts a given {@code Person} into this class for Jackson use.
- */
- public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
- phone = source.getPhone().value;
- email = source.getEmail().value;
- address = source.getAddress().value;
- tagged.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
- }
-
- /**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
- */
- public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tagged) {
- personTags.add(tag.toModelType());
- }
-
- if (name == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
- }
- if (!Name.isValidName(name)) {
- throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
- }
- final Name modelName = new Name(name);
-
- if (phone == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
- }
- if (!Phone.isValidPhone(phone)) {
- throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
- }
- final Phone modelPhone = new Phone(phone);
-
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
- }
- if (!Email.isValidEmail(email)) {
- throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
- }
- final Email modelEmail = new Email(email);
-
- if (address == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
- }
- if (!Address.isValidAddress(address)) {
- throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
- }
- final Address modelAddress = new Address(address);
-
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedStudent.java b/src/main/java/seedu/address/storage/JsonAdaptedStudent.java
new file mode 100644
index 00000000000..c956e491b75
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedStudent.java
@@ -0,0 +1,114 @@
+package seedu.address.storage;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Jackson-friendly version of {@link Student}.
+ */
+class JsonAdaptedStudent {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Student's %s field is missing!";
+ public static final String NO_TUTORIAL_GROUP_MESSAGE_FORMAT = "Student has no tutorial group!";
+
+ private final String name;
+ private final String telegram;
+ private final String email;
+ private final String gitHub;
+ private final List inTutorialGroups = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedStudent} with the given student details.
+ */
+ @JsonCreator
+ public JsonAdaptedStudent(@JsonProperty("name") String name, @JsonProperty("telegram") String telegram,
+ @JsonProperty("email") String email, @JsonProperty("gitHub") String gitHub,
+ @JsonProperty("tutorialGroup") List tutorialGroup) {
+ this.name = name;
+ this.telegram = telegram;
+ this.email = email;
+ this.gitHub = gitHub;
+ if (tutorialGroup != null) {
+ this.inTutorialGroups.addAll(tutorialGroup);
+ }
+ }
+
+ /**
+ * Converts a given {@code Student} into this class for Jackson use.
+ */
+ public JsonAdaptedStudent(Student source) {
+ name = source.getName().fullName;
+ email = source.getEmail().value;
+ telegram = source.getTelegram().value;
+ gitHub = source.getGitHub().value;
+ inTutorialGroups.addAll(source.getTutorialGroups().stream()
+ .map(JsonAdaptedTutorialGroup::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted student object into the model's {@code Student} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted student.
+ */
+ public Student toModelType() throws IllegalValueException {
+ final List personTutorialGroups = new ArrayList<>();
+ if (inTutorialGroups.isEmpty()) {
+ throw new IllegalValueException(NO_TUTORIAL_GROUP_MESSAGE_FORMAT);
+ }
+ for (JsonAdaptedTutorialGroup tag : inTutorialGroups) {
+ personTutorialGroups.add(tag.toModelType());
+ }
+
+ if (name == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
+ }
+ if (!Name.isValidName(name)) {
+ throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
+ }
+ final Name modelName = new Name(name);
+
+ if (telegram == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Telegram.class.getSimpleName()));
+ }
+ if (!telegram.equals("") && !Telegram.isValidTelegram(telegram)) {
+ throw new IllegalValueException(Telegram.MESSAGE_CONSTRAINTS);
+ }
+ final Telegram modelTelegram = telegram.equals("") ? new Telegram(null) : new Telegram(telegram);
+
+ if (email == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
+ }
+ if (!Email.isValidEmail(email)) {
+ throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
+ }
+ final Email modelEmail = new Email(email);
+
+ if (gitHub == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, GitHub.class.getSimpleName()));
+ }
+ if (!gitHub.equals("") && !GitHub.isValidGitHub(gitHub)) {
+ throw new IllegalValueException(GitHub.MESSAGE_CONSTRAINTS);
+ }
+ final GitHub modelGitHub = gitHub.equals("") ? new GitHub(null) : new GitHub(gitHub);
+
+ final Set modelTutorialGroups = new HashSet<>(personTutorialGroups);
+ return new Student(modelName, modelTelegram, modelEmail, modelGitHub, modelTutorialGroups);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
deleted file mode 100644
index 0df22bdb754..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package seedu.address.storage;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonValue;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Tag}.
- */
-class JsonAdaptedTag {
-
- private final String tagName;
-
- /**
- * Constructs a {@code JsonAdaptedTag} with the given {@code tagName}.
- */
- @JsonCreator
- public JsonAdaptedTag(String tagName) {
- this.tagName = tagName;
- }
-
- /**
- * Converts a given {@code Tag} into this class for Jackson use.
- */
- public JsonAdaptedTag(Tag source) {
- tagName = source.tagName;
- }
-
- @JsonValue
- public String getTagName() {
- return tagName;
- }
-
- /**
- * Converts this Jackson-friendly adapted tag object into the model's {@code Tag} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted tag.
- */
- public Tag toModelType() throws IllegalValueException {
- if (!Tag.isValidTagName(tagName)) {
- throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(tagName);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTutorialGroup.java b/src/main/java/seedu/address/storage/JsonAdaptedTutorialGroup.java
new file mode 100644
index 00000000000..eabde31f10f
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedTutorialGroup.java
@@ -0,0 +1,48 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Jackson-friendly version of {@link TutorialGroup}.
+ */
+class JsonAdaptedTutorialGroup {
+
+ private final String tutorialGroupName;
+
+ /**
+ * Constructs a {@code JsonAdaptedTutorialGroup} with the given {@code tagName}.
+ */
+ @JsonCreator
+ public JsonAdaptedTutorialGroup(String tutorialGroupName) {
+ this.tutorialGroupName = tutorialGroupName;
+ }
+
+ /**
+ * Converts a given {@code TutorialGroup} into this class for Jackson use.
+ */
+ public JsonAdaptedTutorialGroup(TutorialGroup source) {
+ tutorialGroupName = source.tutorialGroupName;
+ }
+
+ @JsonValue
+ public String getTutorialGroupName() {
+ return tutorialGroupName;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted tutorial group object into the model's {@code TutorialGroup} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted tutorial group.
+ */
+ public TutorialGroup toModelType() throws IllegalValueException {
+ if (!TutorialGroup.isValidTutorialGroupName(tutorialGroupName)) {
+ throw new IllegalValueException(TutorialGroup.MESSAGE_CONSTRAINTS);
+ }
+ return new TutorialGroup(tutorialGroupName);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
index 5efd834091d..921fb608a5c 100644
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
@@ -11,7 +11,7 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* An Immutable AddressBook that is serializable to JSON format.
@@ -19,16 +19,16 @@
@JsonRootName(value = "addressbook")
class JsonSerializableAddressBook {
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
+ public static final String MESSAGE_DUPLICATE_STUDENT = "Students list contains duplicate student(s).";
- private final List persons = new ArrayList<>();
+ private final List students = new ArrayList<>();
/**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
+ * Constructs a {@code JsonSerializableAddressBook} with the given students.
*/
@JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
+ public JsonSerializableAddressBook(@JsonProperty("students") List students) {
+ this.students.addAll(students);
}
/**
@@ -37,7 +37,7 @@ public JsonSerializableAddressBook(@JsonProperty("persons") List {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
- public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
+ public static final String USERGUIDE_URL = "https://ay2122s2-cs2103t-w15-3.github.io/tp/UserGuide.html";
+ public static final String HELP_MESSAGE = "Refer to the full user guide here: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";
@@ -27,6 +35,13 @@ public class HelpWindow extends UiPart {
@FXML
private Label helpMessage;
+ @FXML
+ private ScrollPane scrollPane;
+
+ @FXML
+ private MarkdownView helpGuideView;
+
+
/**
* Creates a new HelpWindow.
*
@@ -34,6 +49,25 @@ public class HelpWindow extends UiPart {
*/
public HelpWindow(Stage root) {
super(FXML, root);
+
+ String helpGuide;
+
+ try {
+ helpGuide = IOUtils.toString(HelpWindow.class
+ .getResourceAsStream("/help/helpGuide.md"), StandardCharsets.UTF_8);
+ } catch (NullPointerException | IOException e) {
+ // could not find helpGuide path
+ helpGuide = "File not found!";
+ }
+
+ //Solution for viewing markDown from third party library https://github.com/JPro-one/markdown-javafx-renderer
+ helpGuideView = new MarkdownView(helpGuide);
+ helpGuideView.getStylesheets().add("/com/sandec/mdfx/mdfx-default.css");
+ helpGuideView.setPadding(new Insets(20));
+
+ scrollPane.setContent(helpGuideView);
+ scrollPane.setFitToWidth(true);
+
helpMessage.setText(HELP_MESSAGE);
}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 9106c3aa6e5..e0710168204 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -31,7 +31,7 @@ public class MainWindow extends UiPart {
private Logic logic;
// Independent Ui parts residing in this Ui container
- private PersonListPanel personListPanel;
+ private StudentListPanel studentListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
@@ -42,7 +42,7 @@ public class MainWindow extends UiPart {
private MenuItem helpMenuItem;
@FXML
- private StackPane personListPanelPlaceholder;
+ private StackPane studentListPanelPlaceholder;
@FXML
private StackPane resultDisplayPlaceholder;
@@ -110,8 +110,8 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
- personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ studentListPanel = new StudentListPanel(logic.getFilteredStudentList());
+ studentListPanelPlaceholder.getChildren().add(studentListPanel.getRoot());
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
@@ -163,8 +163,8 @@ private void handleExit() {
primaryStage.hide();
}
- public PersonListPanel getPersonListPanel() {
- return personListPanel;
+ public StudentListPanel getStudentListPanel() {
+ return studentListPanel;
}
/**
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
deleted file mode 100644
index 7fc927bc5d9..00000000000
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package seedu.address.ui;
-
-import java.util.Comparator;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Region;
-import seedu.address.model.person.Person;
-
-/**
- * An UI component that displays information of a {@code Person}.
- */
-public class PersonCard extends UiPart {
-
- private static final String FXML = "PersonListCard.fxml";
-
- /**
- * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
- * As a consequence, UI elements' variable names cannot be set to such keywords
- * or an exception will be thrown by JavaFX during runtime.
- *
- * @see The issue on AddressBook level 4
- */
-
- public final Person person;
-
- @FXML
- private HBox cardPane;
- @FXML
- private Label name;
- @FXML
- private Label id;
- @FXML
- private Label phone;
- @FXML
- private Label address;
- @FXML
- private Label email;
- @FXML
- private FlowPane tags;
-
- /**
- * Creates a {@code PersonCode} with the given {@code Person} and index to display.
- */
- public PersonCard(Person person, int displayedIndex) {
- super(FXML);
- this.person = person;
- id.setText(displayedIndex + ". ");
- name.setText(person.getName().fullName);
- phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof PersonCard)) {
- return false;
- }
-
- // state check
- PersonCard card = (PersonCard) other;
- return id.getText().equals(card.id.getText())
- && person.equals(card.person);
- }
-}
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
deleted file mode 100644
index f4c501a897b..00000000000
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Panel containing the list of persons.
- */
-public class PersonListPanel extends UiPart {
- private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
-
- @FXML
- private ListView personListView;
-
- /**
- * Creates a {@code PersonListPanel} with the given {@code ObservableList}.
- */
- public PersonListPanel(ObservableList personList) {
- super(FXML);
- personListView.setItems(personList);
- personListView.setCellFactory(listView -> new PersonListViewCell());
- }
-
- /**
- * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}.
- */
- class PersonListViewCell extends ListCell {
- @Override
- protected void updateItem(Person person, boolean empty) {
- super.updateItem(person, empty);
-
- if (empty || person == null) {
- setGraphic(null);
- setText(null);
- } else {
- setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
- }
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/ui/StudentCard.java b/src/main/java/seedu/address/ui/StudentCard.java
new file mode 100644
index 00000000000..d61a4820cff
--- /dev/null
+++ b/src/main/java/seedu/address/ui/StudentCard.java
@@ -0,0 +1,129 @@
+package seedu.address.ui;
+
+import java.util.Comparator;
+
+import javafx.fxml.FXML;
+import javafx.geometry.Insets;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import javafx.scene.paint.Paint;
+import javafx.scene.shape.Circle;
+import seedu.address.model.student.Student;
+
+/**
+ * A UI component that displays information of a {@code Student}.
+ */
+public class StudentCard extends UiPart {
+
+ private static final String FXML = "StudentListCard.fxml";
+ private static final String green = "#2E9675";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Student student;
+ private final int imageLength = 30;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private HBox telegramBox;
+ @FXML
+ private HBox gitHubBox;
+ @FXML
+ private HBox emailBox;
+ @FXML
+ private Label name;
+ @FXML
+ private Label id;
+ @FXML
+ private Label email;
+ @FXML
+ private Label telegram;
+ @FXML
+ private Label gitHub;
+ @FXML
+ private ImageView telegramImage;
+ @FXML
+ private ImageView gitHubImage;
+ @FXML
+ private ImageView emailImage;
+ @FXML
+ private FlowPane tutorialGroups;
+
+ private Image telegramLogo = new Image(this.getClass().getResourceAsStream("/images/TelegramLogo.png"));
+ private Image gitHubLogo = new Image(this.getClass().getResourceAsStream("/images/GithubLogo.png"));
+ private Image emailLogo = new Image(this.getClass().getResourceAsStream("/images/EmailLogo.png"));
+
+ /**
+ * Creates a {@code PersonCode} with the given {@code Student} and index to display.
+ */
+ public StudentCard(Student student, int displayedIndex) {
+ super(FXML);
+ this.student = student;
+ id.setText(String.valueOf(displayedIndex));
+ name.setText(student.getName().fullName);
+ setContacts(telegramBox, telegramImage, telegramLogo, telegram, student.getTelegram().value);
+ setContacts(gitHubBox, gitHubImage, gitHubLogo, gitHub, student.getGitHub().value);
+ setContacts(emailBox, emailImage, emailLogo, email, student.getEmail().value);
+ student.getTutorialGroups().stream()
+ .sorted(Comparator.comparing(tutorialGroup -> tutorialGroup.tutorialGroupName))
+ .forEach(tutorialGroup -> {
+ Label tgLabel = new Label(tutorialGroup.tutorialGroupName);
+ tgLabel.setBackground(getColorBackground(green));
+ tgLabel.setPadding(new Insets(0, 5, 0, 5));
+ tutorialGroups.getChildren().add(tgLabel); });
+ }
+
+ private void setContacts(HBox hb, ImageView iv, Image i, Label l, String s) {
+ if (s == null || s.isEmpty()) {
+ hb.setManaged(false);
+ iv.setManaged(false);
+ l.setManaged(false);
+ } else {
+ l.setText(s);
+ iv.setImage(i);
+ iv.setClip(getCircleClip(imageLength / 2));
+ }
+ }
+
+ private Circle getCircleClip(int radius) {
+ return new Circle(radius, radius, radius);
+ }
+
+ private Background getColorBackground(String colorString) {
+ Paint paint = Paint.valueOf(colorString);
+ BackgroundFill bf = new BackgroundFill(paint, new CornerRadii(3, false), null);
+ return new Background(bf);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof StudentCard)) {
+ return false;
+ }
+
+ // state check
+ StudentCard card = (StudentCard) other;
+ return id.getText().equals(card.id.getText())
+ && student.equals(card.student);
+ }
+}
diff --git a/src/main/java/seedu/address/ui/StudentListPanel.java b/src/main/java/seedu/address/ui/StudentListPanel.java
new file mode 100644
index 00000000000..c906d3f82b3
--- /dev/null
+++ b/src/main/java/seedu/address/ui/StudentListPanel.java
@@ -0,0 +1,49 @@
+package seedu.address.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.student.Student;
+
+/**
+ * Panel containing the list of students.
+ */
+public class StudentListPanel extends UiPart {
+ private static final String FXML = "StudentListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(StudentListPanel.class);
+
+ @FXML
+ private ListView studentListView;
+
+ /**
+ * Creates a {@code StudentListPanel} with the given {@code ObservableList}.
+ */
+ public StudentListPanel(ObservableList studentList) {
+ super(FXML);
+ studentListView.setItems(studentList);
+ studentListView.setCellFactory(listView -> new StudentListViewCell());
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Student} using a {@code StudentCard}.
+ */
+ class StudentListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Student student, boolean empty) {
+ super.updateItem(student, empty);
+
+ if (empty || student == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new StudentCard(student, getIndex() + 1).getRoot());
+ }
+ }
+ }
+
+}
diff --git a/src/main/resources/help/helpGuide.md b/src/main/resources/help/helpGuide.md
new file mode 100644
index 00000000000..b487050efc0
--- /dev/null
+++ b/src/main/resources/help/helpGuide.md
@@ -0,0 +1,38 @@
+>*Note*:
+>If you wish to copy-and-paste example commands, open up the full user guide
+in a browser using the URL above. This window is for viewing only.
+
+## Command Summary
+
+| Action | Format, Examples |
+|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Add Student** | `add n/NAME e/EMAIL [t/TELEGRAM] [g/GITHUB] tg/TUTORIAL_GROUP…` e.g. `add n/John Smith tg/CS2103T W15-3 e/e0123456@u.nus.edu t/johnsmyname g/johnsmyname` |
+| **Add Tutorial Group for Student** | `addtg INDEX tg/TUTORIAL_GROUP…` e.g. `addtg 5 tg/CS2100 G08` |
+| **Edit Student** | `edit INDEX [n/NAME] [e/EMAIL] [t/TELEGRAM] [g/GITHUB] [tg/TUTORIAL_GROUP]…` e.g. `edit 3 n/Mary Sue t/PresentPerfect` |
+| **Find Students by name** | `find KEYWORD [ADDTIONAL_KEYWORDS]` e.g.`find Jack Ho` |
+| **Find Students by Tutorial Group** | `findtg TUTORIAL_GROUP` e.g. `findtg CS2101 G08` |
+| **Delete Student** | `delete INDEX` e.g. `delete 4` |
+| **Deleting Tutorial Group from Student** | `deletetg INDEX tg/TUTORIAL_GROUP` e.g. `deletetg 4 tg/cs2030s t11` |
+| **Deleting Tutorial Group from all Students** | `deletetgall tg/TUTORIAL_GROUP…` e.g. `deletetgall tg/CS2106 T08` |
+| **List** | `list` |
+| **Clear** | `clear` (**WARNING:** Action cannot be undone) |
+| **Help** | `help` |
+
+
+## Input Requirements
+
+There are **parameters** (e.g. Names, Emails, and GitHub usernames) that must follow certain
+requirements so that TACH recognises them as valid parameters. Here is a list of requirements for every parameter to avoid invalid inputs.
+
+In the list, a **word** is defined as a bunch of *characters* (letters, numbers, punctuation, etc.) separated by spaces.
+e.g. `There A_RE 4 w0-rd_s.` has 4 words.
+
+| Parameter | Requirements |
+|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **INDEX** | Must be a positive number that can be a maximum of 2,147,483,647 (1, 2, 3, … , 2147483647). e.g. `100` |
+| **NAME** | Must contain letters. Can contain spaces, apostrophes and hyphens as long as they are in between letters. Consecutive spaces, apostrophes or hyphens are not allowed. Name must start with a letter. Numbers are allowed, but they must strictly be at the end of the name separated by a space. Cannot be empty, and must not be more than 100 characters long, including spaces. e.g. `John Smith 2` or `Johnson-Johnson Maxine d'Arby` |
+| **TUTORIAL_GROUP** | Must **STRICTLY** consist of a module code, followed by a space, then the tutorial name. It should not be blank. The tutorial name must have a non-zero digit and cannot start or end with a hyphen. The name can consist of a combination of letters, hyphens, digits, underscores. Tutorial groups can only have a maximum of 100 characters including spaces. e.g. `CS2103T W15-3_A`
**ALL** letters in tutorial group inputs will be converted into uppercase letters e.g. `addtg 2 tg/cs2101 t01` will add `CS2101 T01` into the list of tutorial groups of student 2, assuming there are at least 2 students in the list that you see. |
+| **EMAIL** | An email consists of three parts in the following order, the local part, the `@` sign, and the domain part. The local part should only contain letters, numbers, and these special symbols: `+` `_` `.` `-`. It cannot start or end with the special symbols. It must be at most 64 characters long. There must be an @ sign afterwards, followed by the domain name. The domain name must be one of the following: `u.nus.edu` `nus.edu.sg` `gmail.com` `yahoo.com` `outlook.com` `hotmail.com` e.g. `e0123456@u.nus.edu` or `jasminelim@gmail.com` (Our original intention is for you to put in your students' NUS emails which are given to you on LumiNUS, but we also provide the freedom to use some of the more popular email providers listed above, should they be more convenient.) |
+| **TELEGRAM** | May include `@` at the start. Must be exactly one word that can contain letters, numbers and underscores. It must be between 5 to 32 characters long (inclusive). This does not count the `@` symbol. e.g. `Dave3` or `@Lorem_ipsum_dolor_sit_amet_12345` |
+| **GITHUB** | Must be exactly one word that can contain letters, numbers and hyphens. It must be between 2 to 39 characters long (inclusive). e.g. `12345678` or `cake-is-a-lie77` |
+
diff --git a/src/main/resources/images/EmailLogo.png b/src/main/resources/images/EmailLogo.png
new file mode 100644
index 00000000000..d7e53962b99
Binary files /dev/null and b/src/main/resources/images/EmailLogo.png differ
diff --git a/src/main/resources/images/GithubLogo.png b/src/main/resources/images/GithubLogo.png
new file mode 100644
index 00000000000..c24e8309e87
Binary files /dev/null and b/src/main/resources/images/GithubLogo.png differ
diff --git a/src/main/resources/images/TelegramLogo.png b/src/main/resources/images/TelegramLogo.png
new file mode 100644
index 00000000000..ebd8866a011
Binary files /dev/null and b/src/main/resources/images/TelegramLogo.png differ
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..3bebbb8182c 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -120,9 +120,16 @@
-fx-text-fill: white;
}
+.cell_index {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 24px;
+ -fx-text-fill: #010504;
+ -fx-background-color: #2D5691DD;
+}
+
.cell_big_label {
-fx-font-family: "Segoe UI Semibold";
- -fx-font-size: 16px;
+ -fx-font-size: 32px;
-fx-text-fill: #010504;
}
diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml
index 5dea0adef70..48d82252096 100644
--- a/src/main/resources/view/HelpWindow.fxml
+++ b/src/main/resources/view/HelpWindow.fxml
@@ -5,11 +5,16 @@
+
+
-
+
+
+
@@ -18,27 +23,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index a431648f6c0..2560323a810 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -6,13 +6,12 @@
-
+
-
+
@@ -33,25 +32,24 @@
-
+
-
+
-
+
-
+
-
+
+
-
+
-
+
-
-
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
deleted file mode 100644
index f08ea32ad55..00000000000
--- a/src/main/resources/view/PersonListCard.fxml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml
index 58d5ad3dc56..b58628a4dfb 100644
--- a/src/main/resources/view/ResultDisplay.fxml
+++ b/src/main/resources/view/ResultDisplay.fxml
@@ -3,7 +3,6 @@
-
-
+
+
diff --git a/src/main/resources/view/StudentListCard.fxml b/src/main/resources/view/StudentListCard.fxml
new file mode 100644
index 00000000000..f7864e64f30
--- /dev/null
+++ b/src/main/resources/view/StudentListCard.fxml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/StudentListPanel.fxml
similarity index 77%
rename from src/main/resources/view/PersonListPanel.fxml
rename to src/main/resources/view/StudentListPanel.fxml
index 8836d323cc5..e6b906fed69 100644
--- a/src/main/resources/view/PersonListPanel.fxml
+++ b/src/main/resources/view/StudentListPanel.fxml
@@ -4,5 +4,5 @@
-
+
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
deleted file mode 100644
index 6a4d2b7181c..00000000000
--- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "persons": [ {
- "name": "Valid Person",
- "phone": "9482424",
- "email": "hans@example.com",
- "address": "4th street"
- }, {
- "name": "Person With Invalid Phone Field",
- "phone": "948asdf2424",
- "email": "hans@example.com",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidStudentAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidStudentAddressBook.json
new file mode 100644
index 00000000000..3adebd2a852
--- /dev/null
+++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidStudentAddressBook.json
@@ -0,0 +1,13 @@
+{
+ "students": [ {
+ "name": "Valid Person",
+ "telegram": "9482424",
+ "email": "hans@u.nus.edu",
+ "gitHub": "4th street"
+ }, {
+ "name": "Person With Invalid Phone Field",
+ "telegram": "948asdf2424!",
+ "email": "hans@u.nus.edu",
+ "gitHub": "person-wtih-invalid-field"
+ } ]
+}
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
deleted file mode 100644
index ccd21f7d1a9..00000000000
--- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "persons": [ {
- "name": "Person with invalid name field: Ha!ns Mu@ster",
- "phone": "9482424",
- "email": "hans@example.com",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidStudentAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidStudentAddressBook.json
new file mode 100644
index 00000000000..8757d0ece54
--- /dev/null
+++ b/src/test/data/JsonAddressBookStorageTest/invalidStudentAddressBook.json
@@ -0,0 +1,9 @@
+{
+ "students": [ {
+ "name": "Person with invalid name field: Ha!ns Mu@ster",
+ "telegram": "@HansMuster",
+ "email": "hans@u.nus.edu",
+ "gitHub": "hans-muster",
+ "tutorialGroup": [ ]
+ } ]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
deleted file mode 100644
index 48831cc7674..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "persons": [ {
- "name": "Alice Pauline",
- "phone": "94351253",
- "email": "alice@example.com",
- "address": "123, Jurong West Ave 6, #08-111",
- "tagged": [ "friends" ]
- }, {
- "name": "Alice Pauline",
- "phone": "94351253",
- "email": "pauline@example.com",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicateStudentAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicateStudentAddressBook.json
new file mode 100644
index 00000000000..17b036d75a1
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicateStudentAddressBook.json
@@ -0,0 +1,15 @@
+{
+ "students": [ {
+ "name" : "Alice Pauline",
+ "telegram": "@APauline",
+ "email" : "alice@u.nus.edu",
+ "gitHub": "alice10",
+ "tutorialGroup": [ "CS2103 W13-2" ]
+ }, {
+ "name": "Alice Pauline",
+ "telegram": "@APauline",
+ "email": "alice@u.nus.edu",
+ "gitHub": "alice10",
+ "tutorialGroup": [ "CS2103 W13-2" ]
+ } ]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
deleted file mode 100644
index ad3f135ae42..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "persons": [ {
- "name": "Hans Muster",
- "phone": "9482424",
- "email": "invalid@email!3e",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidStudentAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidStudentAddressBook.json
new file mode 100644
index 00000000000..d8549358793
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidStudentAddressBook.json
@@ -0,0 +1,9 @@
+{
+ "students": [ {
+ "name": "Hans Muster",
+ "telegram": "@HansMuster",
+ "email": "invalid@email!3e",
+ "gitHub": "hansMuster",
+ "tutorialGroup": [ "CS2103 W13-2" ]
+ } ]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
deleted file mode 100644
index f10eddee12e..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
- "persons" : [ {
- "name" : "Alice Pauline",
- "phone" : "94351253",
- "email" : "alice@example.com",
- "address" : "123, Jurong West Ave 6, #08-111",
- "tagged" : [ "friends" ]
- }, {
- "name" : "Benson Meier",
- "phone" : "98765432",
- "email" : "johnd@example.com",
- "address" : "311, Clementi Ave 2, #02-25",
- "tagged" : [ "owesMoney", "friends" ]
- }, {
- "name" : "Carl Kurz",
- "phone" : "95352563",
- "email" : "heinz@example.com",
- "address" : "wall street",
- "tagged" : [ ]
- }, {
- "name" : "Daniel Meier",
- "phone" : "87652533",
- "email" : "cornelia@example.com",
- "address" : "10th street",
- "tagged" : [ "friends" ]
- }, {
- "name" : "Elle Meyer",
- "phone" : "9482224",
- "email" : "werner@example.com",
- "address" : "michegan ave",
- "tagged" : [ ]
- }, {
- "name" : "Fiona Kunz",
- "phone" : "9482427",
- "email" : "lydia@example.com",
- "address" : "little tokyo",
- "tagged" : [ ]
- }, {
- "name" : "George Best",
- "phone" : "9482442",
- "email" : "anna@example.com",
- "address" : "4th street",
- "tagged" : [ ]
- } ]
-}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalStudentsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalStudentsAddressBook.json
new file mode 100644
index 00000000000..37f3c2d55ef
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalStudentsAddressBook.json
@@ -0,0 +1,46 @@
+{
+ "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
+ "students" : [ {
+ "name" : "Alice Pauline",
+ "telegram": "@APauline",
+ "email" : "alice@u.nus.edu",
+ "gitHub": "",
+ "tutorialGroup": [ "CS2103 W13-2" ]
+ }, {
+ "name" : "Benson Meier",
+ "telegram": "",
+ "email" : "johnd@u.nus.edu",
+ "gitHub": "bensonguy",
+ "tutorialGroup": [ "CS2106 T02", "CS2103 W13-2" ]
+ }, {
+ "name" : "Carl Kurz Meier",
+ "telegram": "@CarlJr",
+ "email" : "heinz@u.nus.edu",
+ "gitHub": "JrCarl",
+ "tutorialGroup": [ "CS2106 T02" ]
+ }, {
+ "name" : "Daniel Carl Meier",
+ "telegram": "@DanieltheName",
+ "email" : "cornelia@u.nus.edu",
+ "gitHub": "Dan-iel",
+ "tutorialGroup": [ "CS2103 W13-2" ]
+ }, {
+ "name" : "Elle Meyer",
+ "telegram": "@Elle20",
+ "email" : "werner@u.nus.edu",
+ "gitHub": "ELLE",
+ "tutorialGroup": [ "CS2106 T02", "CS2103 W13-2", "CS2101 G08" ]
+ }, {
+ "name" : "Fiona Kunz",
+ "telegram": "@Fiona14",
+ "email" : "lydia@u.nus.edu",
+ "gitHub": "Fiona-14",
+ "tutorialGroup": [ "CS2106 T02", "CS2103T W15-3"]
+ }, {
+ "name" : "George Fiona Kun",
+ "telegram": "@George11",
+ "email" : "anna@u.nus.edu",
+ "gitHub": "George-Not-Bush",
+ "tutorialGroup": [ "CS2106 T02" ]
+ } ]
+}
diff --git a/src/test/java/seedu/address/commons/core/index/IndexTest.java b/src/test/java/seedu/address/commons/core/index/IndexTest.java
index a3ec6f8e747..d9bbbb3aadb 100644
--- a/src/test/java/seedu/address/commons/core/index/IndexTest.java
+++ b/src/test/java/seedu/address/commons/core/index/IndexTest.java
@@ -39,22 +39,22 @@ public void createZeroBasedIndex() {
@Test
public void equals() {
- final Index fifthPersonIndex = Index.fromOneBased(5);
+ final Index fifthStudentIndex = Index.fromOneBased(5);
// same values -> returns true
- assertTrue(fifthPersonIndex.equals(Index.fromOneBased(5)));
- assertTrue(fifthPersonIndex.equals(Index.fromZeroBased(4)));
+ assertTrue(fifthStudentIndex.equals(Index.fromOneBased(5)));
+ assertTrue(fifthStudentIndex.equals(Index.fromZeroBased(4)));
// same object -> returns true
- assertTrue(fifthPersonIndex.equals(fifthPersonIndex));
+ assertTrue(fifthStudentIndex.equals(fifthStudentIndex));
// null -> returns false
- assertFalse(fifthPersonIndex.equals(null));
+ assertFalse(fifthStudentIndex.equals(null));
// different types -> returns false
- assertFalse(fifthPersonIndex.equals(5.0f));
+ assertFalse(fifthStudentIndex.equals(5.0f));
// different index -> returns false
- assertFalse(fifthPersonIndex.equals(Index.fromOneBased(1)));
+ assertFalse(fifthStudentIndex.equals(Index.fromOneBased(1)));
}
}
diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/address/commons/util/StringUtilTest.java
index c56d407bf3f..6bf07c01186 100644
--- a/src/test/java/seedu/address/commons/util/StringUtilTest.java
+++ b/src/test/java/seedu/address/commons/util/StringUtilTest.java
@@ -16,111 +16,137 @@ public class StringUtilTest {
public void isNonZeroUnsignedInteger() {
// EP: empty strings
- assertFalse(StringUtil.isNonZeroUnsignedInteger("")); // Boundary value
- assertFalse(StringUtil.isNonZeroUnsignedInteger(" "));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("")); // Boundary value
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit(" "));
// EP: not a number
- assertFalse(StringUtil.isNonZeroUnsignedInteger("a"));
- assertFalse(StringUtil.isNonZeroUnsignedInteger("aaa"));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("a"));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("aaa"));
// EP: zero
- assertFalse(StringUtil.isNonZeroUnsignedInteger("0"));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("0"));
// EP: zero as prefix
- assertTrue(StringUtil.isNonZeroUnsignedInteger("01"));
+ assertTrue(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("01"));
// EP: signed numbers
- assertFalse(StringUtil.isNonZeroUnsignedInteger("-1"));
- assertFalse(StringUtil.isNonZeroUnsignedInteger("+1"));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("-1"));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("+1"));
// EP: numbers with white space
- assertFalse(StringUtil.isNonZeroUnsignedInteger(" 10 ")); // Leading/trailing spaces
- assertFalse(StringUtil.isNonZeroUnsignedInteger("1 0")); // Spaces in the middle
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit(" 10 ")); // Leading/trailing spaces
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("1 0")); // Spaces in the middle
// EP: number larger than Integer.MAX_VALUE
- assertFalse(StringUtil.isNonZeroUnsignedInteger(Long.toString(Integer.MAX_VALUE + 1)));
+ assertFalse(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit(
+ Long.toString(Integer.MAX_VALUE + 1)));
+
+ // EP: number equal to Integer.MAX_VALUE
+ assertTrue(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit(Long.toString(Integer.MAX_VALUE)));
// EP: valid numbers, should return true
- assertTrue(StringUtil.isNonZeroUnsignedInteger("1")); // Boundary value
- assertTrue(StringUtil.isNonZeroUnsignedInteger("10"));
+ assertTrue(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("1")); // Boundary value
+ assertTrue(StringUtil.isNonZeroSignedIntegerLessThanOrEqualToIntegerLimit("10"));
}
- //---------------- Tests for containsWordIgnoreCase --------------------------------------
+ //---------------- Tests for containsPartialSentenceIgnoreCase --------------------------------------
/*
- * Invalid equivalence partitions for word: null, empty, multiple words
+ * Invalid equivalence partitions for keys: null, empty
* Invalid equivalence partitions for sentence: null
- * The four test cases below test one invalid input at a time.
+ * The three test cases below test one invalid input at a time.
*/
@Test
- public void containsWordIgnoreCase_nullWord_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> StringUtil.containsWordIgnoreCase("typical sentence", null));
- }
-
- @Test
- public void containsWordIgnoreCase_emptyWord_throwsIllegalArgumentException() {
- assertThrows(IllegalArgumentException.class, "Word parameter cannot be empty", ()
- -> StringUtil.containsWordIgnoreCase("typical sentence", " "));
+ public void containsPartialSentenceIgnoreCase_nullKeys_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, (
+ ) -> StringUtil.containsPartialSentenceIgnoreCase("typical sentence", null));
}
@Test
- public void containsWordIgnoreCase_multipleWords_throwsIllegalArgumentException() {
- assertThrows(IllegalArgumentException.class, "Word parameter should be a single word", ()
- -> StringUtil.containsWordIgnoreCase("typical sentence", "aaa BBB"));
+ public void containsPartialSentenceIgnoreCase_emptyKeys_throwsIllegalArgumentException() {
+ assertThrows(IllegalArgumentException.class, "Keys cannot be empty", ()
+ -> StringUtil.containsPartialSentenceIgnoreCase("typical sentence", " "));
}
@Test
- public void containsWordIgnoreCase_nullSentence_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> StringUtil.containsWordIgnoreCase(null, "abc"));
+ public void containsPartialSentenceIgnoreCase_nullSentence_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, (
+ ) -> StringUtil.containsPartialSentenceIgnoreCase(null, "abc"));
}
/*
- * Valid equivalence partitions for word:
- * - any word
- * - word containing symbols/numbers
- * - word with leading/trailing spaces
+ * Valid equivalence partitions for keys:
+ * - contain symbols/numbers
+ * - contain leading/trailing spaces
+ * - one word
+ * - multiple words
*
* Valid equivalence partitions for sentence:
* - empty string
* - one word
* - multiple words
- * - sentence with extra spaces
+ * - contain leading/trailing spaces
*
* Possible scenarios returning true:
- * - matches first word in sentence
- * - last word in sentence
- * - middle word in sentence
- * - matches multiple words
+ * - key fully matches first word in sentence
+ * - key partially matches first word in sentence
+ * - key matches sentence fully
+ * - key matches first 3 words of sentence fully and last word of sentence partially
*
* Possible scenarios returning false:
- * - query word matches part of a sentence word
- * - sentence word matches part of the query word
+ * - key is longer than sentence
+ * - key is not a substring of sentence
*
* The test method below tries to verify all above with a reasonably low number of test cases.
*/
@Test
- public void containsWordIgnoreCase_validInputs_correctResult() {
+ public void containsPartialSentenceIgnoreCase_validInputs_correctResult() {
// Empty sentence
- assertFalse(StringUtil.containsWordIgnoreCase("", "abc")); // Boundary case
- assertFalse(StringUtil.containsWordIgnoreCase(" ", "123"));
-
- // Matches a partial word only
- assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc", "bb")); // Sentence word bigger than query word
- assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc", "bbbb")); // Query word bigger than sentence word
-
- // Matches word in the sentence, different upper/lower case letters
- assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc", "Bbb")); // First word (boundary case)
- assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc@1", "CCc@1")); // Last word (boundary case)
- assertTrue(StringUtil.containsWordIgnoreCase(" AAA bBb ccc ", "aaa")); // Sentence has extra spaces
- assertTrue(StringUtil.containsWordIgnoreCase("Aaa", "aaa")); // Only one word in sentence (boundary case)
- assertTrue(StringUtil.containsWordIgnoreCase("aaa bbb ccc", " ccc ")); // Leading/trailing spaces
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("", "abc")); // Boundary case
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase(" ", "123"));
+
+ // Key matches sentences fully
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa", "aaa")); // one word (boundary)
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bBb cc", "aaa bBb cc")); // Multiple
+
+ // Key matches sentences partially
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa", "aa")); // one word (boundary)
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bbb ccc", "bb")); // partial match
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bbb ccc", "aaa bbb c")); // Multiple
+
+ // Key matches sentence partially, different upper/lower case letters
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bBb ccc", "AAA")); // First word
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bBb ccc", "CCc")); // Last word
+ // Keys with numerals and symbols
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa ccc@1", "@1"));
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("Aaa", "aaa")); // one word (boundary)
+ // Leading/trailing spaces in keys
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bbb ccc", " ccc "));
+ // Leading/trailing spaces in sentence
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase(" aaa bBb cc ", "AAA bbb cc"));
+
+ // Key matches sentence fully, different upper/lower case letters
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("aaa bBb cc", "AAA bbb cc"));
// Matches multiple words in sentence
- assertTrue(StringUtil.containsWordIgnoreCase("AAA bBb ccc bbb", "bbB"));
+ assertTrue(StringUtil.containsPartialSentenceIgnoreCase("AAA bBb ccc bbb", "bbB"));
+
+ // Key unable to match sentence
+ // Keyword longer than sentence
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("aaa", "aaaa"));
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("aaa", "aaa bb")); // Extra keywords
+ // Whitespace does not tally
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("aaa bbb", "aaab bb"));
+ // Different sequence
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("AAA bbb cc", "AAA cc bbb"));
+ // Different sequence
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("AAA bbb cc", "cc AAA"));
+ // Key is not a substring
+ assertFalse(StringUtil.containsPartialSentenceIgnoreCase("aaa bb", "cc"));
}
//---------------- Tests for getDetails --------------------------------------
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index ad923ac249a..0843e6ae80f 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -1,14 +1,15 @@
package seedu.address.logic;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.GITHUB_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.TELEGRAM_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.AMY;
+import static seedu.address.testutil.TypicalStudents.AMY;
import java.io.IOException;
import java.nio.file.Path;
@@ -17,8 +18,9 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddStudentCommand;
import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
@@ -26,11 +28,11 @@
import seedu.address.model.ModelManager;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
import seedu.address.storage.JsonAddressBookStorage;
import seedu.address.storage.JsonUserPrefsStorage;
import seedu.address.storage.StorageManager;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.testutil.StudentBuilder;
public class LogicManagerTest {
private static final IOException DUMMY_IO_EXCEPTION = new IOException("dummy exception");
@@ -57,9 +59,9 @@ public void execute_invalidCommandFormat_throwsParseException() {
}
@Test
- public void execute_commandExecutionError_throwsCommandException() {
- String deleteCommand = "delete 9";
- assertCommandException(deleteCommand, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ public void execute_commandExecutionErrorIndexOutOfRange_throwsCommandException() {
+ String deleteCommand = "delete 2000";
+ assertCommandException(deleteCommand, DeleteCommand.MESSAGE_INDEX_OUT_OF_RANGE);
}
@Test
@@ -78,19 +80,19 @@ public void execute_storageThrowsIoException_throwsCommandException() {
StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
- // Execute add command
- String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY
- + ADDRESS_DESC_AMY;
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
+ // Execute add student command
+ String addStudentCommand = AddStudentCommand.COMMAND_WORD + NAME_DESC_AMY + TELEGRAM_DESC_AMY + EMAIL_DESC_AMY
+ + GITHUB_DESC_AMY + TUTORIAL_GROUP_DESC_CS2101_G08;
+ Student expectedStudent = new StudentBuilder(AMY).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build();
ModelManager expectedModel = new ModelManager();
- expectedModel.addPerson(expectedPerson);
+ expectedModel.addStudent(expectedStudent);
String expectedMessage = LogicManager.FILE_OPS_ERROR_MESSAGE + DUMMY_IO_EXCEPTION;
- assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel);
+ assertCommandFailure(addStudentCommand, CommandException.class, expectedMessage, expectedModel);
}
@Test
- public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredPersonList().remove(0));
+ public void getFilteredStudentList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredStudentList().remove(0));
}
/**
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
index cb8714bb055..b89c3073661 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
@@ -2,7 +2,7 @@
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -10,8 +10,8 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.student.Student;
+import seedu.address.testutil.StudentBuilder;
/**
* Contains integration tests (interaction with the Model) for {@code AddCommand}.
@@ -26,20 +26,20 @@ public void setUp() {
}
@Test
- public void execute_newPerson_success() {
- Person validPerson = new PersonBuilder().build();
+ public void execute_newStudent_success() {
+ Student validStudent = new StudentBuilder().build();
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
- expectedModel.addPerson(validPerson);
+ expectedModel.addStudent(validStudent);
- assertCommandSuccess(new AddCommand(validPerson), model,
- String.format(AddCommand.MESSAGE_SUCCESS, validPerson), expectedModel);
+ assertCommandSuccess(new AddStudentCommand(validStudent), model,
+ String.format(AddStudentCommand.MESSAGE_SUCCESS, validStudent), expectedModel);
}
@Test
- public void execute_duplicatePerson_throwsCommandException() {
- Person personInList = model.getAddressBook().getPersonList().get(0);
- assertCommandFailure(new AddCommand(personInList), model, AddCommand.MESSAGE_DUPLICATE_PERSON);
+ public void execute_duplicateStudent_throwsCommandException() {
+ Student studentInList = model.getAddressBook().getStudentList().get(0);
+ assertCommandFailure(new AddStudentCommand(studentInList), model, AddStudentCommand.MESSAGE_DUPLICATE_STUDENT);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java
similarity index 54%
rename from src/test/java/seedu/address/logic/commands/AddCommandTest.java
rename to src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java
index 5865713d5dd..cb87357937e 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java
@@ -20,48 +20,49 @@
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.student.Student;
+import seedu.address.testutil.StudentBuilder;
-public class AddCommandTest {
+public class AddStudentCommandTest {
@Test
- public void constructor_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new AddCommand(null));
+ public void constructor_nullStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new AddStudentCommand(null));
}
@Test
- public void execute_personAcceptedByModel_addSuccessful() throws Exception {
- ModelStubAcceptingPersonAdded modelStub = new ModelStubAcceptingPersonAdded();
- Person validPerson = new PersonBuilder().build();
+ public void execute_studentAcceptedByModel_addSuccessful() throws Exception {
+ ModelStubAcceptingStudentAdded modelStub = new ModelStubAcceptingStudentAdded();
+ Student validStudent = new StudentBuilder().build();
- CommandResult commandResult = new AddCommand(validPerson).execute(modelStub);
+ CommandResult commandResult = new AddStudentCommand(validStudent).execute(modelStub);
- assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, validPerson), commandResult.getFeedbackToUser());
- assertEquals(Arrays.asList(validPerson), modelStub.personsAdded);
+ assertEquals(String.format(AddStudentCommand.MESSAGE_SUCCESS, validStudent), commandResult.getFeedbackToUser());
+ assertEquals(Arrays.asList(validStudent), modelStub.studentsAdded);
}
@Test
- public void execute_duplicatePerson_throwsCommandException() {
- Person validPerson = new PersonBuilder().build();
- AddCommand addCommand = new AddCommand(validPerson);
- ModelStub modelStub = new ModelStubWithPerson(validPerson);
+ public void execute_duplicateStudent_throwsCommandException() {
+ Student validStudent = new StudentBuilder().build();
+ AddStudentCommand addCommand = new AddStudentCommand(validStudent);
+ ModelStub modelStub = new ModelStubWithStudent(validStudent);
- assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PERSON, () -> addCommand.execute(modelStub));
+ assertThrows(CommandException.class,
+ AddStudentCommand.MESSAGE_DUPLICATE_STUDENT, () -> addCommand.execute(modelStub));
}
@Test
public void equals() {
- Person alice = new PersonBuilder().withName("Alice").build();
- Person bob = new PersonBuilder().withName("Bob").build();
- AddCommand addAliceCommand = new AddCommand(alice);
- AddCommand addBobCommand = new AddCommand(bob);
+ Student alice = new StudentBuilder().withName("Alice").build();
+ Student bob = new StudentBuilder().withName("Bob").build();
+ AddStudentCommand addAliceCommand = new AddStudentCommand(alice);
+ AddStudentCommand addBobCommand = new AddStudentCommand(bob);
// same object -> returns true
assertTrue(addAliceCommand.equals(addAliceCommand));
// same values -> returns true
- AddCommand addAliceCommandCopy = new AddCommand(alice);
+ AddStudentCommand addAliceCommandCopy = new AddStudentCommand(alice);
assertTrue(addAliceCommand.equals(addAliceCommandCopy));
// different types -> returns false
@@ -70,7 +71,7 @@ public void equals() {
// null -> returns false
assertFalse(addAliceCommand.equals(null));
- // different person -> returns false
+ // different student -> returns false
assertFalse(addAliceCommand.equals(addBobCommand));
}
@@ -109,7 +110,7 @@ public void setAddressBookFilePath(Path addressBookFilePath) {
}
@Override
- public void addPerson(Person person) {
+ public void addStudent(Student student) {
throw new AssertionError("This method should not be called.");
}
@@ -124,65 +125,70 @@ public ReadOnlyAddressBook getAddressBook() {
}
@Override
- public boolean hasPerson(Person person) {
+ public boolean hasStudent(Student student) {
throw new AssertionError("This method should not be called.");
}
@Override
- public void deletePerson(Person target) {
+ public void deleteStudent(Student target) {
throw new AssertionError("This method should not be called.");
}
@Override
- public void setPerson(Person target, Person editedPerson) {
+ public void setStudent(Student target, Student editedStudent) {
throw new AssertionError("This method should not be called.");
}
@Override
- public ObservableList getFilteredPersonList() {
+ public ObservableList getFilteredStudentList() {
throw new AssertionError("This method should not be called.");
}
@Override
- public void updateFilteredPersonList(Predicate predicate) {
+ public void updateFilteredStudentList(Predicate predicate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getSortedStudentList() {
throw new AssertionError("This method should not be called.");
}
}
/**
- * A Model stub that contains a single person.
+ * A Model stub that contains a single student.
*/
- private class ModelStubWithPerson extends ModelStub {
- private final Person person;
+ private class ModelStubWithStudent extends ModelStub {
+ private final Student student;
- ModelStubWithPerson(Person person) {
- requireNonNull(person);
- this.person = person;
+ ModelStubWithStudent(Student student) {
+ requireNonNull(student);
+ this.student = student;
}
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return this.person.isSamePerson(person);
+ public boolean hasStudent(Student student) {
+ requireNonNull(student);
+ return this.student.isSameStudent(student);
}
}
/**
- * A Model stub that always accept the person being added.
+ * A Model stub that always accept the student being added.
*/
- private class ModelStubAcceptingPersonAdded extends ModelStub {
- final ArrayList personsAdded = new ArrayList<>();
+ private class ModelStubAcceptingStudentAdded extends ModelStub {
+ final ArrayList studentsAdded = new ArrayList<>();
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return personsAdded.stream().anyMatch(person::isSamePerson);
+ public boolean hasStudent(Student student) {
+ requireNonNull(student);
+ return studentsAdded.stream().anyMatch(student::isSameStudent);
}
@Override
- public void addPerson(Person person) {
- requireNonNull(person);
- personsAdded.add(person);
+ public void addStudent(Student student) {
+ requireNonNull(student);
+ studentsAdded.add(student);
}
@Override
diff --git a/src/test/java/seedu/address/logic/commands/AddTutorialGroupCommandTest.java b/src/test/java/seedu/address/logic/commands/AddTutorialGroupCommandTest.java
new file mode 100644
index 00000000000..f7dc109cf5a
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/AddTutorialGroupCommandTest.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.showStudentAtIndex;
+import static seedu.address.testutil.AddTutorialGroupDescriptorBuilder.VALID_TUTORIAL_GROUP_DESCRIPTOR_AMY;
+import static seedu.address.testutil.AddTutorialGroupDescriptorBuilder.VALID_TUTORIAL_GROUP_DESCRIPTOR_BOB;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddTutorialGroupCommand.AddTutorialGroupDescriptor;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.testutil.AddTutorialGroupDescriptorBuilder;
+
+public class AddTutorialGroupCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_invalidStudentIndex_failure() {
+ // index out of bounds
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
+ Index outOfBoundIndex = INDEX_SECOND_STUDENT;
+ // ensures that outOfBoundIndex is still in bounds of address book list
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getStudentList().size());
+
+ AddTutorialGroupCommand addTutorialGroupCommand = new AddTutorialGroupCommand(outOfBoundIndex,
+ new AddTutorialGroupDescriptorBuilder().withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build());
+
+ assertCommandFailure(addTutorialGroupCommand, model, AddTutorialGroupCommand.MESSAGE_INDEX_OUT_OF_RANGE);
+ }
+
+ @Test
+ public void equals() {
+ final AddTutorialGroupCommand standardCommand =
+ new AddTutorialGroupCommand(INDEX_FIRST_STUDENT, VALID_TUTORIAL_GROUP_DESCRIPTOR_AMY);
+
+ // same values -> return true
+ AddTutorialGroupDescriptor copyDescriptor = VALID_TUTORIAL_GROUP_DESCRIPTOR_AMY;
+ AddTutorialGroupCommand commandWithSameValues =
+ new AddTutorialGroupCommand(INDEX_FIRST_STUDENT, copyDescriptor);
+ assertTrue(standardCommand.equals(commandWithSameValues));
+
+ // same object -> returns true
+ assertTrue(standardCommand.equals(standardCommand));
+
+ // null -> returns false
+ assertFalse(standardCommand.equals(null));
+
+ // different index -> returns false
+ assertFalse(standardCommand.equals(new ClearCommand()));
+
+ // different descriptor -> returns false
+ assertFalse(standardCommand.equals(new AddTutorialGroupCommand(INDEX_FIRST_STUDENT,
+ VALID_TUTORIAL_GROUP_DESCRIPTOR_BOB)));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
index 80d9110c03a..2020fcec74b 100644
--- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
@@ -1,7 +1,7 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..8ea7efed3f9 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -2,11 +2,11 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
import static seedu.address.testutil.Assert.assertThrows;
import java.util.ArrayList;
@@ -17,9 +17,9 @@
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
+import seedu.address.model.student.Student;
+import seedu.address.testutil.EditStudentDescriptorBuilder;
/**
* Contains helper methods for testing commands.
@@ -28,45 +28,59 @@ public class CommandTestUtil {
public static final String VALID_NAME_AMY = "Amy Bee";
public static final String VALID_NAME_BOB = "Bob Choo";
- public static final String VALID_PHONE_AMY = "11111111";
- public static final String VALID_PHONE_BOB = "22222222";
- public static final String VALID_EMAIL_AMY = "amy@example.com";
- public static final String VALID_EMAIL_BOB = "bob@example.com";
- public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
- public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
- public static final String VALID_TAG_HUSBAND = "husband";
- public static final String VALID_TAG_FRIEND = "friend";
-
+ public static final String VALID_TELEGRAM_AMY = "@11111111";
+ public static final String VALID_TELEGRAM_BOB = "@22222222";
+ public static final String VALID_EMAIL_AMY = "amy@u.nus.edu";
+ public static final String VALID_EMAIL_BOB = "bob@u.nus.edu";
+ public static final String VALID_EMPTY_GITHUB = "";
+ public static final String VALID_EMPTY_TELEGRAM = "";
+ public static final String VALID_GITHUB_AMY = "amybee14";
+ public static final String VALID_GITHUB_BOB = "boblim23";
+ public static final String VALID_TUTORIAL_GROUP_CS2103T_W15_3 = "CS2103T W15-3";
+ public static final String VALID_TUTORIAL_GROUP_CS2103_W13_2 = "CS2103 W13-2";
+ public static final String VALID_TUTORIAL_GROUP_CS2101_G08 = "CS2101 G08";
+ public static final String VALID_TUTORIAL_GROUP_CS2106_T02 = "CS2106 T02";
+
+ public static final String EMPTY_GITHUB_DESC = " " + PREFIX_GITHUB + VALID_EMPTY_GITHUB;
+ public static final String EMPTY_TELEGRAM_DESC = " " + PREFIX_TELEGRAM + VALID_EMPTY_TELEGRAM;
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
- public static final String PHONE_DESC_AMY = " " + PREFIX_PHONE + VALID_PHONE_AMY;
- public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB;
+ public static final String TELEGRAM_DESC_AMY = " " + PREFIX_TELEGRAM + VALID_TELEGRAM_AMY;
+ public static final String TELEGRAM_DESC_BOB = " " + PREFIX_TELEGRAM + VALID_TELEGRAM_BOB;
public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY;
public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB;
- public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY;
- public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
- public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
- public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String GITHUB_DESC_AMY = " " + PREFIX_GITHUB + VALID_GITHUB_AMY;
+ public static final String GITHUB_DESC_BOB = " " + PREFIX_GITHUB + VALID_GITHUB_BOB;
+ public static final String TUTORIAL_GROUP_DESC_CS2101_G08 = " " + PREFIX_TUTORIAL_GROUP
+ + VALID_TUTORIAL_GROUP_CS2101_G08;
+ public static final String TUTORIAL_GROUP_DESC_CS2103T_W15_3 = " " + PREFIX_TUTORIAL_GROUP
+ + VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+ public static final String TUTORIAL_GROUP_DESC_CS2103_W13_2 = " " + PREFIX_TUTORIAL_GROUP
+ + VALID_TUTORIAL_GROUP_CS2103_W13_2;
+ public static final String TUTORIAL_GROUP_DESC_CS2106_T02 = " " + PREFIX_TUTORIAL_GROUP
+ + VALID_TUTORIAL_GROUP_CS2106_T02;
public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
- public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
+ public static final String INVALID_TELEGRAM_DESC = " " + PREFIX_TELEGRAM + "911!"; // non-alphanumeric character
public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
- public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
- public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
+ public static final String INVALID_GITHUB_DESC = " " + PREFIX_GITHUB + "johson!"; // non-alphanumeric
+ public static final String INVALID_TUTORIAL_GROUP_DESC = " " + PREFIX_TUTORIAL_GROUP
+ + "CS2106* T05"; // '*' not allowed as a tutorial group
+ public static final String INVALID_EMPTY_TUTORIAL_GROUP = " " + PREFIX_TUTORIAL_GROUP;
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
- public static final EditCommand.EditPersonDescriptor DESC_AMY;
- public static final EditCommand.EditPersonDescriptor DESC_BOB;
+ public static final EditCommand.EditStudentDescriptor DESC_AMY;
+ public static final EditCommand.EditStudentDescriptor DESC_BOB;
static {
- DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_FRIEND).build();
- DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ DESC_AMY = new EditStudentDescriptorBuilder().withName(VALID_NAME_AMY)
+ .withTelegram(VALID_TELEGRAM_AMY).withEmail(VALID_EMAIL_AMY).withGitHub(VALID_GITHUB_AMY)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build();
+ DESC_BOB = new EditStudentDescriptorBuilder().withName(VALID_NAME_BOB)
+ .withTelegram(VALID_TELEGRAM_BOB).withEmail(VALID_EMAIL_BOB).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3, VALID_TUTORIAL_GROUP_CS2101_G08).build();
}
/**
@@ -75,7 +89,7 @@ public class CommandTestUtil {
* - the {@code actualModel} matches {@code expectedModel}
*/
public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult,
- Model expectedModel) {
+ Model expectedModel) {
try {
CommandResult result = command.execute(actualModel);
assertEquals(expectedCommandResult, result);
@@ -90,7 +104,7 @@ public static void assertCommandSuccess(Command command, Model actualModel, Comm
* that takes a string {@code expectedMessage}.
*/
public static void assertCommandSuccess(Command command, Model actualModel, String expectedMessage,
- Model expectedModel) {
+ Model expectedModel) {
CommandResult expectedCommandResult = new CommandResult(expectedMessage);
assertCommandSuccess(command, actualModel, expectedCommandResult, expectedModel);
}
@@ -99,30 +113,31 @@ public static void assertCommandSuccess(Command command, Model actualModel, Stri
* Executes the given {@code command}, confirms that
* - a {@code CommandException} is thrown
* - the CommandException message matches {@code expectedMessage}
- * - the address book, filtered person list and selected person in {@code actualModel} remain unchanged
+ * - the address book, filtered student list and selected student in {@code actualModel} remain unchanged
*/
public static void assertCommandFailure(Command command, Model actualModel, String expectedMessage) {
// we are unable to defensively copy the model for comparison later, so we can
// only do so by copying its components.
AddressBook expectedAddressBook = new AddressBook(actualModel.getAddressBook());
- List expectedFilteredList = new ArrayList<>(actualModel.getFilteredPersonList());
+ List expectedFilteredList = new ArrayList<>(actualModel.getFilteredStudentList());
assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel));
assertEquals(expectedAddressBook, actualModel.getAddressBook());
- assertEquals(expectedFilteredList, actualModel.getFilteredPersonList());
+ assertEquals(expectedFilteredList, actualModel.getFilteredStudentList());
}
+
/**
- * Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the
+ * Updates {@code model}'s filtered list to show only the student at the given {@code targetIndex} in the
* {@code model}'s address book.
*/
- public static void showPersonAtIndex(Model model, Index targetIndex) {
- assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size());
+ public static void showStudentAtIndex(Model model, Index targetIndex) {
+ assertTrue(targetIndex.getZeroBased() < model.getFilteredStudentList().size());
- Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased());
- final String[] splitName = person.getName().fullName.split("\\s+");
- model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
+ Student student = model.getFilteredStudentList().get(targetIndex.getZeroBased());
+ final String[] splitName = student.getName().fullName.split("\\s+");
+ model.updateFilteredStudentList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
- assertEquals(1, model.getFilteredPersonList().size());
+ assertEquals(1, model.getFilteredStudentList().size());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
index 45a8c910ba1..3384c41d9d6 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
@@ -4,19 +4,18 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.logic.commands.CommandTestUtil.showStudentAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.Messages;
import seedu.address.commons.core.index.Index;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* Contains integration tests (interaction with the Model) and unit tests for
@@ -28,64 +27,64 @@ public class DeleteCommandTest {
@Test
public void execute_validIndexUnfilteredList_success() {
- Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ Student studentToDelete = model.getFilteredStudentList().get(INDEX_FIRST_STUDENT.getZeroBased());
+ DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_STUDENT);
- String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete);
+ String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_STUDENT_SUCCESS, studentToDelete);
ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
- expectedModel.deletePerson(personToDelete);
+ expectedModel.deleteStudent(studentToDelete);
assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_invalidIndexUnfilteredList_throwsCommandException() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredStudentList().size() + 1);
DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deleteCommand, model, DeleteCommand.MESSAGE_INDEX_OUT_OF_RANGE);
}
@Test
public void execute_validIndexFilteredList_success() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
- Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ Student studentToDelete = model.getFilteredStudentList().get(INDEX_FIRST_STUDENT.getZeroBased());
+ DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_STUDENT);
- String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete);
+ String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_STUDENT_SUCCESS, studentToDelete);
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
- expectedModel.deletePerson(personToDelete);
- showNoPerson(expectedModel);
+ expectedModel.deleteStudent(studentToDelete);
+ showNoStudent(expectedModel);
assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_invalidIndexFilteredList_throwsCommandException() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
+ Index outOfBoundIndex = INDEX_SECOND_STUDENT;
// ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getStudentList().size());
DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deleteCommand, model, DeleteCommand.MESSAGE_INDEX_OUT_OF_RANGE);
}
@Test
public void equals() {
- DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON);
- DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON);
+ DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_STUDENT);
+ DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_STUDENT);
// same object -> returns true
assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
// same values -> returns true
- DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_STUDENT);
assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
// different types -> returns false
@@ -94,16 +93,16 @@ public void equals() {
// null -> returns false
assertFalse(deleteFirstCommand.equals(null));
- // different person -> returns false
+ // different student -> returns false
assertFalse(deleteFirstCommand.equals(deleteSecondCommand));
}
/**
* Updates {@code model}'s filtered list to show no one.
*/
- private void showNoPerson(Model model) {
- model.updateFilteredPersonList(p -> false);
+ private void showNoStudent(Model model) {
+ model.updateFilteredStudentList(s -> false);
- assertTrue(model.getFilteredPersonList().isEmpty());
+ assertTrue(model.getFilteredStudentList().isEmpty());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteTutorialGroupCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTutorialGroupCommandTest.java
new file mode 100644
index 00000000000..204d0c52d32
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/DeleteTutorialGroupCommandTest.java
@@ -0,0 +1,118 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103_W13_2;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2106_T02;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.logic.commands.CommandTestUtil.showStudentAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.model.AddressBook;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.testutil.StudentBuilder;
+
+public class DeleteTutorialGroupCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_invalidStudentIndexWithFilteredList_failure() {
+ // filtered list size of 1
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
+ // index is larger than size of filteredList
+ Index outOfBoundIndex = INDEX_SECOND_STUDENT;
+ // ensures that outOfBoundIndex is still in bounds of address book list
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getStudentList().size());
+
+ DeleteTutorialGroupCommand deleteTutorialGroupCommand = new DeleteTutorialGroupCommand(
+ outOfBoundIndex, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08));
+
+ assertCommandFailure(deleteTutorialGroupCommand, model,
+ DeleteTutorialGroupCommand.MESSAGE_INDEX_OUT_OF_RANGE);
+ }
+
+ @Test
+ public void execute_deleteTutorialGroup_success() {
+ Index indexSecondStudent = INDEX_SECOND_STUDENT;
+ Student secondStudent = model.getFilteredStudentList().get(indexSecondStudent.getZeroBased());
+
+ StudentBuilder studentInList = new StudentBuilder(secondStudent);
+ Student editedStudent = studentInList.withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103_W13_2).build();
+
+ DeleteTutorialGroupCommand deleteTutorialGroupCommand =
+ new DeleteTutorialGroupCommand(indexSecondStudent, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2106_T02));
+
+ String expectedMessage = String.format(DeleteTutorialGroupCommand.MESSAGE_DELETE_TUTORIAL_GROUP_SUCCESS,
+ editedStudent);
+
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ expectedModel.setStudent(secondStudent, editedStudent);
+
+ assertCommandSuccess(deleteTutorialGroupCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_noSuchTutorialGroup_failure() {
+ Index indexSecondStudent = INDEX_SECOND_STUDENT;
+
+ DeleteTutorialGroupCommand deleteTutorialGroupCommand =
+ new DeleteTutorialGroupCommand(indexSecondStudent, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08));
+
+ assertCommandFailure(deleteTutorialGroupCommand, model,
+ DeleteTutorialGroupCommand.MESSAGE_NO_SUCH_TUTORIAL_GROUP);
+ }
+
+ @Test
+ public void execute_onlyTutorialGroup_failure() {
+ Index indexFirstStudent = INDEX_FIRST_STUDENT;
+
+ DeleteTutorialGroupCommand deleteTutorialGroupCommand =
+ new DeleteTutorialGroupCommand(indexFirstStudent, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2103_W13_2));
+
+ assertCommandFailure(deleteTutorialGroupCommand, model,
+ DeleteTutorialGroupCommand.MESSAGE_CANNOT_DELETE_ONLY_TUTORIAL_GROUP);
+ }
+
+ @Test
+ public void equals() {
+ final DeleteTutorialGroupCommand standardCommand =
+ new DeleteTutorialGroupCommand(
+ INDEX_FIRST_STUDENT, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08));
+
+ // same values -> return true
+ DeleteTutorialGroupCommand commandWithSameValues =
+ new DeleteTutorialGroupCommand(
+ INDEX_FIRST_STUDENT, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08));
+ assertTrue(standardCommand.equals(commandWithSameValues));
+
+ // same object -> returns true
+ assertTrue(standardCommand.equals(standardCommand));
+
+ // null -> returns false
+ assertFalse(standardCommand.equals(null));
+
+ // different types -> returns false
+ assertFalse(standardCommand.equals(new ClearCommand()));
+
+ // different index -> returns false
+ assertFalse(standardCommand.equals(new DeleteTutorialGroupCommand(
+ INDEX_SECOND_STUDENT, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08))));
+
+ // different tutorial group -> returns false
+ assertFalse(standardCommand.equals(new DeleteTutorialGroupCommand(
+ INDEX_FIRST_STUDENT, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2106_T02))));
+
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteTutorialGroupsFromStudentsCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTutorialGroupsFromStudentsCommandTest.java
new file mode 100644
index 00000000000..f7edaa1c653
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/DeleteTutorialGroupsFromStudentsCommandTest.java
@@ -0,0 +1,122 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103_W13_2;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2106_T02;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.logic.commands.CommandTestUtil.showStudentAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIFTH_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FOURTH_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SEVENTH_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SIXTH_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_STUDENT;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.testutil.StudentBuilder;
+
+class DeleteTutorialGroupsFromStudentsCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ void execute_tutorialGroupsToDeleteWithFilteredList_studentDeletedOrEditedInMainListSuccess() throws Exception {
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ showStudentAtIndex(model, INDEX_FOURTH_STUDENT);
+ showStudentAtIndex(expectedModel, INDEX_FOURTH_STUDENT);
+ expectedModel.updateFilteredStudentList(Model.PREDICATE_SHOW_ALL_STUDENTS);
+
+ List tutorialGroupsToDelete = new ArrayList<>(Arrays.asList(
+ new TutorialGroup(VALID_TUTORIAL_GROUP_CS2103_W13_2),
+ new TutorialGroup(VALID_TUTORIAL_GROUP_CS2106_T02)));
+
+ deleteStudentsOfExpectedModelInTestcase(expectedModel);
+ updateStudentsOfExpectedModelInTestcase(expectedModel);
+
+ String expectedMessage = String.format(DeleteTutorialGroupsFromStudentsCommand
+ .MESSAGE_TUTORIAL_GROUP_DELETE_SUCCESS, tutorialGroupsToDelete);
+ DeleteTutorialGroupsFromStudentsCommand deleteTutorialGroupsFromStudentsCommand =
+ new DeleteTutorialGroupsFromStudentsCommand(new HashSet<>(tutorialGroupsToDelete));
+
+ assertCommandSuccess(deleteTutorialGroupsFromStudentsCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void equals() {
+ Set firstTutorialGroups = new HashSet<>(
+ Arrays.asList(new TutorialGroup(VALID_TUTORIAL_GROUP_CS2106_T02)));
+ Set secondTutorialGroups = new HashSet<>(
+ Arrays.asList(new TutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3)));
+ DeleteTutorialGroupsFromStudentsCommand deleteTutorialGroupsFirstCommand =
+ new DeleteTutorialGroupsFromStudentsCommand(firstTutorialGroups);
+ DeleteTutorialGroupsFromStudentsCommand deleteTutorialGroupsSecondCommand =
+ new DeleteTutorialGroupsFromStudentsCommand(secondTutorialGroups);
+
+ // same object -> returns true
+ assertTrue(deleteTutorialGroupsFirstCommand.equals(deleteTutorialGroupsFirstCommand));
+
+ // same values -> returns true
+ DeleteTutorialGroupsFromStudentsCommand deleteTutorialGroupsFirstCommandCopy =
+ new DeleteTutorialGroupsFromStudentsCommand(firstTutorialGroups);
+ assertTrue(deleteTutorialGroupsFirstCommand.equals(deleteTutorialGroupsFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(deleteTutorialGroupsFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(deleteTutorialGroupsFirstCommand.equals(null));
+
+ // different student -> returns false
+ assertFalse(deleteTutorialGroupsFirstCommand.equals(deleteTutorialGroupsSecondCommand));
+ }
+
+ private void deleteStudentsOfExpectedModelInTestcase(Model expectedModel) {
+ //Students have 1 out of the 2 tutorial groups to be deleted and have 0 tutorial groups after deletion.
+ Student firstStudentToDelete = model.getSortedStudentList().get(INDEX_FIRST_STUDENT.getZeroBased());
+ expectedModel.deleteStudent(firstStudentToDelete);
+ Student secondStudentToDelete = model.getSortedStudentList().get(INDEX_THIRD_STUDENT.getZeroBased());
+ expectedModel.deleteStudent(secondStudentToDelete);
+ Student thirdStudentToDelete = model.getSortedStudentList().get(INDEX_FOURTH_STUDENT.getZeroBased());
+ expectedModel.deleteStudent(thirdStudentToDelete);
+ Student fourthStudentToDelete = model.getSortedStudentList().get(INDEX_SEVENTH_STUDENT.getZeroBased());
+ expectedModel.deleteStudent(fourthStudentToDelete);
+
+ //Student have both tutorial groups to be deleted and have 0 tutorial groups after deletion.
+ Student fifthStudentToDelete = model.getSortedStudentList().get(INDEX_SECOND_STUDENT.getZeroBased());
+ expectedModel.deleteStudent(fifthStudentToDelete);
+ }
+
+ private void updateStudentsOfExpectedModelInTestcase(Model expectedModel) {
+ //Student with tutorial group modified and have 1 out of the 2 given tutorial groups.
+ Student studentToRemoveOneTutorialGroup = model.getSortedStudentList()
+ .get(INDEX_SIXTH_STUDENT.getZeroBased());
+ Student studentWithOneTutorialGroupRemoved = new StudentBuilder(studentToRemoveOneTutorialGroup)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ expectedModel.setStudent(studentToRemoveOneTutorialGroup, studentWithOneTutorialGroupRemoved);
+
+ //Student with tutorial group modified and have both of the given tutorial group.
+ Student studentToRemoveTwoTutorialGroup = model.getSortedStudentList()
+ .get(INDEX_FIFTH_STUDENT.getZeroBased());
+ Student studentWithTwoTutorialGroupRemoved = new StudentBuilder(studentToRemoveTwoTutorialGroup)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build();
+ expectedModel.setStudent(studentToRemoveTwoTutorialGroup, studentWithTwoTutorialGroupRemoved);
+
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
index 214c6c2507b..3c3f36f8efe 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
@@ -5,27 +5,29 @@
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.logic.commands.CommandTestUtil.showStudentAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
+
+import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.Messages;
import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditCommand.EditStudentDescriptor;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.student.Student;
+import seedu.address.testutil.EditStudentDescriptorBuilder;
+import seedu.address.testutil.StudentBuilder;
+
/**
* Contains integration tests (interaction with the Model) and unit tests for EditCommand.
@@ -36,45 +38,45 @@ public class EditCommandTest {
@Test
public void execute_allFieldsSpecifiedUnfilteredList_success() {
- Person editedPerson = new PersonBuilder().build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
+ Student editedStudent = new StudentBuilder().build();
+ EditCommand.EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder(editedStudent).build();
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_STUDENT, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ expectedModel.setStudent(model.getFilteredStudentList().get(0), editedStudent);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_someFieldsSpecifiedUnfilteredList_success() {
- Index indexLastPerson = Index.fromOneBased(model.getFilteredPersonList().size());
- Person lastPerson = model.getFilteredPersonList().get(indexLastPerson.getZeroBased());
+ Index indexLastStudent = Index.fromOneBased(model.getFilteredStudentList().size());
+ Student lastStudent = model.getFilteredStudentList().get(indexLastStudent.getZeroBased());
- PersonBuilder personInList = new PersonBuilder(lastPerson);
- Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withTags(VALID_TAG_HUSBAND).build();
+ StudentBuilder studentInList = new StudentBuilder(lastStudent);
+ Student editedStudent = studentInList.withName(VALID_NAME_BOB).withTelegram(VALID_TELEGRAM_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
- EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
+ EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder().withName(VALID_NAME_BOB)
+ .withTelegram(VALID_TELEGRAM_BOB).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ EditCommand editCommand = new EditCommand(indexLastStudent, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(lastPerson, editedPerson);
+ expectedModel.setStudent(lastStudent, editedStudent);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_noFieldSpecifiedUnfilteredList_success() {
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
- Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_STUDENT, new EditCommand.EditStudentDescriptor());
+ Student editedStudent = model.getFilteredStudentList().get(INDEX_FIRST_STUDENT.getZeroBased());
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
@@ -83,49 +85,52 @@ public void execute_noFieldSpecifiedUnfilteredList_success() {
@Test
public void execute_filteredList_success() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
+
+ Student studentInFilteredList = model.getFilteredStudentList().get(INDEX_FIRST_STUDENT.getZeroBased());
+ Student editedStudent = new StudentBuilder(studentInFilteredList).withName(VALID_NAME_BOB).build();
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_STUDENT,
+ new EditStudentDescriptorBuilder().withName(VALID_NAME_BOB).build());
- Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- Person editedPerson = new PersonBuilder(personInFilteredList).withName(VALID_NAME_BOB).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ Predicate predicateToObtainEditedStudent = (Student s) -> s.equals(editedStudent);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ expectedModel.setStudent(model.getFilteredStudentList().get(0), editedStudent);
+ expectedModel.updateFilteredStudentList(predicateToObtainEditedStudent);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
- public void execute_duplicatePersonUnfilteredList_failure() {
- Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor);
+ public void execute_duplicateStudentUnfilteredList_failure() {
+ Student firstStudent = model.getFilteredStudentList().get(INDEX_FIRST_STUDENT.getZeroBased());
+ EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder(firstStudent).build();
+ EditCommand editCommand = new EditCommand(INDEX_SECOND_STUDENT, descriptor);
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_STUDENT);
}
@Test
- public void execute_duplicatePersonFilteredList_failure() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ public void execute_duplicateStudentFilteredList_failure() {
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
- // edit person in filtered list into a duplicate in address book
- Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
- new EditPersonDescriptorBuilder(personInList).build());
+ // edit student in filtered list into a duplicate in address book
+ Student studentInList = model.getAddressBook().getStudentList().get(INDEX_SECOND_STUDENT.getZeroBased());
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_STUDENT,
+ new EditStudentDescriptorBuilder(studentInList).build());
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_STUDENT);
}
@Test
- public void execute_invalidPersonIndexUnfilteredList_failure() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build();
+ public void execute_invalidStudentIndexUnfilteredList_failure() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredStudentList().size() + 1);
+ EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder().withName(VALID_NAME_BOB).build();
EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor);
- assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_INDEX_OUT_OF_RANGE);
}
/**
@@ -133,25 +138,25 @@ public void execute_invalidPersonIndexUnfilteredList_failure() {
* but smaller than size of address book
*/
@Test
- public void execute_invalidPersonIndexFilteredList_failure() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
+ public void execute_invalidStudentIndexFilteredList_failure() {
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
+ Index outOfBoundIndex = INDEX_SECOND_STUDENT;
// ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getStudentList().size());
EditCommand editCommand = new EditCommand(outOfBoundIndex,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ new EditStudentDescriptorBuilder().withName(VALID_NAME_BOB).build());
- assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_INDEX_OUT_OF_RANGE);
}
@Test
public void equals() {
- final EditCommand standardCommand = new EditCommand(INDEX_FIRST_PERSON, DESC_AMY);
+ final EditCommand standardCommand = new EditCommand(INDEX_FIRST_STUDENT, DESC_AMY);
// same values -> returns true
- EditPersonDescriptor copyDescriptor = new EditPersonDescriptor(DESC_AMY);
- EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_PERSON, copyDescriptor);
+ EditStudentDescriptor copyDescriptor = new EditStudentDescriptor(DESC_AMY);
+ EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_STUDENT, copyDescriptor);
assertTrue(standardCommand.equals(commandWithSameValues));
// same object -> returns true
@@ -164,10 +169,10 @@ public void equals() {
assertFalse(standardCommand.equals(new ClearCommand()));
// different index -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_PERSON, DESC_AMY)));
+ assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_STUDENT, DESC_AMY)));
// different descriptor -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_PERSON, DESC_BOB)));
+ assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_STUDENT, DESC_BOB)));
}
}
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditStudentDescriptorTest.java
similarity index 59%
rename from src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
rename to src/test/java/seedu/address/logic/commands/EditStudentDescriptorTest.java
index e0288792e72..73ef01464b6 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditStudentDescriptorTest.java
@@ -4,23 +4,23 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.logic.commands.EditCommand.EditStudentDescriptor;
+import seedu.address.testutil.EditStudentDescriptorBuilder;
-public class EditPersonDescriptorTest {
+public class EditStudentDescriptorTest {
@Test
public void equals() {
// same values -> returns true
- EditPersonDescriptor descriptorWithSameValues = new EditPersonDescriptor(DESC_AMY);
+ EditStudentDescriptor descriptorWithSameValues = new EditStudentDescriptor(DESC_AMY);
assertTrue(DESC_AMY.equals(descriptorWithSameValues));
// same object -> returns true
@@ -36,23 +36,24 @@ public void equals() {
assertFalse(DESC_AMY.equals(DESC_BOB));
// different name -> returns false
- EditPersonDescriptor editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withName(VALID_NAME_BOB).build();
+ EditStudentDescriptor editedAmy = new EditStudentDescriptorBuilder(DESC_AMY).withName(VALID_NAME_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
- // different phone -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withPhone(VALID_PHONE_BOB).build();
+ // different telegram -> returns false
+ editedAmy = new EditStudentDescriptorBuilder(DESC_AMY).withTelegram(VALID_TELEGRAM_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different email -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build();
+ editedAmy = new EditStudentDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
- // different address -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build();
+ // different gitHub -> returns false
+ editedAmy = new EditStudentDescriptorBuilder(DESC_AMY).withGitHub(VALID_GITHUB_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
- // different tags -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build();
+ // different tutorial group -> returns false
+ editedAmy = new EditStudentDescriptorBuilder(DESC_AMY)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
assertFalse(DESC_AMY.equals(editedAmy));
}
}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index 9b15db28bbb..1f95edd78c5 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -3,12 +3,15 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.commons.core.Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.CARL;
-import static seedu.address.testutil.TypicalPersons.ELLE;
-import static seedu.address.testutil.TypicalPersons.FIONA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalStudents.BENSON;
+import static seedu.address.testutil.TypicalStudents.CARL;
+import static seedu.address.testutil.TypicalStudents.DANIEL;
+import static seedu.address.testutil.TypicalStudents.FIONA;
+import static seedu.address.testutil.TypicalStudents.GEORGE;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import java.util.Arrays;
import java.util.Collections;
@@ -18,7 +21,7 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
@@ -50,28 +53,55 @@ public void equals() {
// null -> returns false
assertFalse(findFirstCommand.equals(null));
- // different person -> returns false
+ // different student -> returns false
assertFalse(findFirstCommand.equals(findSecondCommand));
}
@Test
- public void execute_zeroKeywords_noPersonFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
- NameContainsKeywordsPredicate predicate = preparePredicate(" ");
+ public void execute_multipleKeywords_zeroStudentFound() {
+ NameContainsKeywordsPredicate predicate = preparePredicate("Carl Kurz Elle");
+ model.updateFilteredStudentList(predicate);
+ boolean zeroStudentFound = model.getFilteredStudentList().isEmpty();
+ assertEquals(true, zeroStudentFound);
+ }
+
+ @Test
+ public void execute_multipleKeywords_oneStudentFound() {
+ String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 1);
+ NameContainsKeywordsPredicate predicate = preparePredicate("Carl Kurz");
+ FindCommand command = new FindCommand(predicate);
+ expectedModel.updateFilteredStudentList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(CARL), model.getFilteredStudentList());
+ }
+
+ @Test
+ public void execute_oneKeyword_multipleStudentsFound() {
+ String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 3);
+ NameContainsKeywordsPredicate predicate = preparePredicate("Meier");
FindCommand command = new FindCommand(predicate);
- expectedModel.updateFilteredPersonList(predicate);
+ expectedModel.updateFilteredStudentList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ assertEquals(Arrays.asList(BENSON, CARL, DANIEL), model.getFilteredStudentList());
}
@Test
- public void execute_multipleKeywords_multiplePersonsFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
- NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
+ public void execute_multipleKeywords_multipleStudentsFound() {
+ String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 2);
+ NameContainsKeywordsPredicate predicate = preparePredicate("Fiona Kun");
FindCommand command = new FindCommand(predicate);
- expectedModel.updateFilteredPersonList(predicate);
+ expectedModel.updateFilteredStudentList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
+ assertEquals(Arrays.asList(FIONA, GEORGE), model.getFilteredStudentList());
+ }
+
+ @Test
+ public void zeroKeywords_throwsIllegalArgumentException() {
+ NameContainsKeywordsPredicate predicate = preparePredicate(" ");
+ FindCommand command = new FindCommand(predicate);
+ // empty keys not allowed
+ assertThrows(IllegalArgumentException.class, "Keys cannot be empty", (
+ ) -> command.execute(model));
}
/**
diff --git a/src/test/java/seedu/address/logic/commands/FindTutorialGroupCommandTest.java b/src/test/java/seedu/address/logic/commands/FindTutorialGroupCommandTest.java
new file mode 100644
index 00000000000..5b13bc7bc54
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindTutorialGroupCommandTest.java
@@ -0,0 +1,85 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.commons.core.Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalStudents.BENSON;
+import static seedu.address.testutil.TypicalStudents.CARL;
+import static seedu.address.testutil.TypicalStudents.ELLE;
+import static seedu.address.testutil.TypicalStudents.FIONA;
+import static seedu.address.testutil.TypicalStudents.GEORGE;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.tutorialgroup.TutorialGroupKeywordsPredicate;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FindTutorialGroupCommand}.
+ */
+public class FindTutorialGroupCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ TutorialGroupKeywordsPredicate firstPredicate = new TutorialGroupKeywordsPredicate("CS2103 W13-2");
+ TutorialGroupKeywordsPredicate secondPredicate = new TutorialGroupKeywordsPredicate("CS2106 T02");
+
+ FindTutorialGroupCommand findFirstTutorialGroupCommand = new FindTutorialGroupCommand(firstPredicate);
+ FindTutorialGroupCommand findSecondTutorialGroupCommand = new FindTutorialGroupCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(findFirstTutorialGroupCommand.equals(findFirstTutorialGroupCommand));
+
+ // same values -> returns true
+ FindTutorialGroupCommand findFirstTutorialGroupCommandCopy = new FindTutorialGroupCommand(firstPredicate);
+ assertTrue(findFirstTutorialGroupCommand.equals(findFirstTutorialGroupCommandCopy));
+
+ // different types -> returns false
+ assertFalse(findFirstTutorialGroupCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(findFirstTutorialGroupCommand.equals(null));
+
+ // different student -> returns false
+ assertFalse(findFirstTutorialGroupCommand.equals(findSecondTutorialGroupCommand));
+
+ }
+
+ @Test
+ public void execute_tutorialGroupNotFound_noStudentList() {
+ String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 0);
+ TutorialGroupKeywordsPredicate predicate = preparePredicate("MA1000 A08");
+ FindTutorialGroupCommand command = new FindTutorialGroupCommand(predicate);
+ expectedModel.updateFilteredStudentList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredStudentList());
+ }
+
+ @Test
+ public void execute_tutorialGroupFound_multipleStudentsList() {
+ String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 5);
+ TutorialGroupKeywordsPredicate predicate = preparePredicate("CS2106 T02");
+ FindTutorialGroupCommand command = new FindTutorialGroupCommand(predicate);
+ expectedModel.updateFilteredStudentList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(BENSON, CARL, ELLE, FIONA, GEORGE), model.getFilteredStudentList());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code TutorialGroupKeywordsPredicate}.
+ */
+ private TutorialGroupKeywordsPredicate preparePredicate(String userInput) {
+ return new TutorialGroupKeywordsPredicate(userInput);
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
index 435ff1f7275..b6c00c69f86 100644
--- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
@@ -1,9 +1,9 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.logic.commands.CommandTestUtil.showStudentAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -33,7 +33,7 @@ public void execute_listIsNotFiltered_showsSameList() {
@Test
public void execute_listIsFiltered_showsEverything() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showStudentAtIndex(model, INDEX_FIRST_STUDENT);
assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
deleted file mode 100644
index 5cf487d7ebb..00000000000
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
-import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalPersons.AMY;
-import static seedu.address.testutil.TypicalPersons.BOB;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.testutil.PersonBuilder;
-
-public class AddCommandParserTest {
- private AddCommandParser parser = new AddCommandParser();
-
- @Test
- public void parse_allFieldsPresent_success() {
- Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND).build();
-
- // whitespace only preamble
- assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
-
- // multiple names - last name accepted
- assertParseSuccess(parser, NAME_DESC_AMY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
-
- // multiple phones - last phone accepted
- assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_AMY + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
-
- // multiple emails - last email accepted
- assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_AMY + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
-
- // multiple addresses - last address accepted
- assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_AMY
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
-
- // multiple tags - all accepted
- Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
- .build();
- assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, new AddCommand(expectedPersonMultipleTags));
- }
-
- @Test
- public void parse_optionalFieldsMissing_success() {
- // zero tags
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
- assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY,
- new AddCommand(expectedPerson));
- }
-
- @Test
- public void parse_compulsoryFieldMissing_failure() {
- String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE);
-
- // missing name prefix
- assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
-
- // missing phone prefix
- assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
-
- // missing email prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
-
- // missing address prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_ADDRESS_BOB,
- expectedMessage);
-
- // all prefixes missing
- assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_ADDRESS_BOB,
- expectedMessage);
- }
-
- @Test
- public void parse_invalidValue_failure() {
- // invalid name
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS);
-
- // invalid phone
- assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS);
-
- // invalid email
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS);
-
- // invalid address
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS);
-
- // invalid tag
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS);
-
- // two invalid values, only first invalid value reported
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC,
- Name.MESSAGE_CONSTRAINTS);
-
- // non-empty preamble
- assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- }
-}
diff --git a/src/test/java/seedu/address/logic/parser/AddStudentCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddStudentCommandParserTest.java
new file mode 100644
index 00000000000..c4ff08b58ca
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/AddStudentCommandParserTest.java
@@ -0,0 +1,144 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.GITHUB_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.GITHUB_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_GITHUB_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_TELEGRAM_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_TUTORIAL_GROUP_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
+import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
+import static seedu.address.logic.commands.CommandTestUtil.TELEGRAM_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.TELEGRAM_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.testutil.TypicalStudents.AMY;
+import static seedu.address.testutil.TypicalStudents.BOB;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.AddStudentCommand;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.testutil.StudentBuilder;
+
+public class AddStudentCommandParserTest {
+ private AddStudentCommandParser parser = new AddStudentCommandParser();
+
+ @Test
+ public void parse_allFieldsPresent_success() {
+ Student expectedStudent = new StudentBuilder(BOB).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build();
+
+ // whitespace only preamble
+ assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudent));
+
+ // multiple names - last name accepted
+ assertParseSuccess(parser, NAME_DESC_AMY + NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudent));
+
+ // multiple telegram - last telegram accepted
+ assertParseSuccess(parser, NAME_DESC_BOB + TELEGRAM_DESC_AMY + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudent));
+
+ // multiple emails - last email accepted
+ assertParseSuccess(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_AMY + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudent));
+
+ // multiple gitHub - last gitHub accepted
+ assertParseSuccess(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB + GITHUB_DESC_AMY
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudent));
+
+ // multiple tutorial groups - all accepted
+ Student expectedStudentMultipleTags = new StudentBuilder(BOB).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08,
+ VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ assertParseSuccess(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB + GITHUB_DESC_BOB
+ + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08,
+ new AddStudentCommand(expectedStudentMultipleTags));
+ }
+
+ @Test
+ public void parse_optionalFieldsMissing_success() {
+ // missing telegram
+ Student expectedStudentWithoutTelegram = new StudentBuilder(AMY).withTelegram(null).build();
+ assertParseSuccess(parser, NAME_DESC_AMY + EMAIL_DESC_AMY + GITHUB_DESC_AMY
+ + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudentWithoutTelegram));
+
+ // missing github
+ Student expectedStudentWithoutGithub = new StudentBuilder(AMY).withGitHub(null).build();
+ assertParseSuccess(parser, NAME_DESC_AMY + EMAIL_DESC_AMY + TELEGRAM_DESC_AMY
+ + TUTORIAL_GROUP_DESC_CS2101_G08, new AddStudentCommand(expectedStudentWithoutGithub));
+ }
+
+ @Test
+ public void parse_compulsoryFieldMissing_failure() {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddStudentCommand.MESSAGE_USAGE);
+
+ // missing name prefix
+ assertParseFailure(parser, VALID_NAME_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2103T_W15_3, expectedMessage);
+
+ // missing tutorial group prefix
+ assertParseFailure(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + VALID_TUTORIAL_GROUP_CS2103T_W15_3, expectedMessage);
+
+ // missing email prefix
+ assertParseFailure(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + VALID_EMAIL_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2103T_W15_3, expectedMessage);
+
+ // all prefixes missing
+ assertParseFailure(parser, VALID_NAME_BOB + VALID_TELEGRAM_BOB + VALID_EMAIL_BOB
+ + VALID_GITHUB_BOB + VALID_TUTORIAL_GROUP_CS2103T_W15_3, expectedMessage);
+ }
+
+ @Test
+ public void parse_invalidValue_failure() {
+ // invalid name
+ assertParseFailure(parser, INVALID_NAME_DESC + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB + GITHUB_DESC_BOB
+ + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08, Name.MESSAGE_CONSTRAINTS);
+
+ // invalid telegram
+ assertParseFailure(parser, NAME_DESC_BOB + INVALID_TELEGRAM_DESC + EMAIL_DESC_BOB + GITHUB_DESC_BOB
+ + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08, Telegram.MESSAGE_CONSTRAINTS);
+
+ // invalid email
+ assertParseFailure(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + INVALID_EMAIL_DESC + GITHUB_DESC_BOB
+ + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08, Email.MESSAGE_CONSTRAINTS);
+
+ // invalid gitHub
+ assertParseFailure(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB + INVALID_GITHUB_DESC
+ + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08, GitHub.MESSAGE_CONSTRAINTS);
+
+ // invalid tutorial group
+ assertParseFailure(parser, NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB + GITHUB_DESC_BOB
+ + INVALID_TUTORIAL_GROUP_DESC + VALID_TUTORIAL_GROUP_CS2101_G08, TutorialGroup.MESSAGE_CONSTRAINTS);
+
+ // two invalid values, only first invalid value reported
+ assertParseFailure(parser, INVALID_NAME_DESC + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + INVALID_GITHUB_DESC + TUTORIAL_GROUP_DESC_CS2101_G08,
+ Name.MESSAGE_CONSTRAINTS);
+
+ // non-empty preamble
+ assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + TELEGRAM_DESC_BOB + EMAIL_DESC_BOB
+ + GITHUB_DESC_BOB + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddStudentCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddTutorialGroupParserTest.java b/src/test/java/seedu/address/logic/parser/AddTutorialGroupParserTest.java
new file mode 100644
index 00000000000..66baf07fb02
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/AddTutorialGroupParserTest.java
@@ -0,0 +1,79 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_TUTORIAL_GROUP_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.testutil.AddTutorialGroupDescriptorBuilder.VALID_TUTORIAL_GROUP_DESCRIPTOR_BOB;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddTutorialGroupCommand;
+import seedu.address.logic.commands.AddTutorialGroupCommand.AddTutorialGroupDescriptor;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+public class AddTutorialGroupParserTest {
+
+ private static final String TUTORIAL_GROUP_EMPTY = " " + PREFIX_TUTORIAL_GROUP;
+
+ private static final String MESSAGE_INVALID_FORMAT =
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTutorialGroupCommand.MESSAGE_USAGE);
+
+ private AddTutorialGroupParser parser = new AddTutorialGroupParser();
+
+ @Test
+ public void parse_missingParts_failure() {
+ // no index specified
+ assertParseFailure(parser, TUTORIAL_GROUP_DESC_CS2101_G08,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+ // no field specified
+ assertParseFailure(parser, "1", MESSAGE_INVALID_FORMAT);
+
+ // no index and no field specified
+ assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
+
+ //index larger than 2147483647
+ assertParseFailure(parser, "2147483648" + TUTORIAL_GROUP_DESC_CS2103T_W15_3,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+ }
+
+ @Test
+ public void parse_invalidPreamble_failure() {
+ // negative index
+ assertParseFailure(parser, "-5" + TUTORIAL_GROUP_DESC_CS2103T_W15_3,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+
+ // zero
+ assertParseFailure(parser, "0" + TUTORIAL_GROUP_DESC_CS2103T_W15_3,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+ }
+
+ @Test
+ public void parse_invalidValue_failure() {
+ // empty tutorial group
+ assertParseFailure(parser, "1"
+ + TUTORIAL_GROUP_EMPTY, TutorialGroup.MESSAGE_CONSTRAINTS);
+
+ // multiple invalid values, but only the first invalid value is captured
+ assertParseFailure(parser, "-1" + INVALID_TUTORIAL_GROUP_DESC,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+ }
+
+ @Test
+ public void parse_allFieldsSpecified_success() {
+ // valid index and tutorial group
+ Index targetIndex = INDEX_SECOND_STUDENT;
+ String input = targetIndex.getOneBased() + TUTORIAL_GROUP_DESC_CS2101_G08 + TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+
+ AddTutorialGroupDescriptor desc = VALID_TUTORIAL_GROUP_DESCRIPTOR_BOB;
+ AddTutorialGroupCommand expectedCommand = new AddTutorialGroupCommand(targetIndex, desc);
+
+ assertParseSuccess(parser, input, expectedCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
index d9659205b57..b1a90491679 100644
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
@@ -4,40 +4,51 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddStudentCommand;
+import seedu.address.logic.commands.AddTutorialGroupCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.logic.commands.DeleteTutorialGroupCommand;
+import seedu.address.logic.commands.DeleteTutorialGroupsFromStudentsCommand;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindTutorialGroupCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
-import seedu.address.testutil.PersonUtil;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.model.tutorialgroup.TutorialGroupKeywordsPredicate;
+import seedu.address.testutil.AddTutorialGroupDescriptorBuilder;
+import seedu.address.testutil.EditStudentDescriptorBuilder;
+import seedu.address.testutil.StudentBuilder;
+import seedu.address.testutil.StudentUtil;
public class AddressBookParserTest {
private final AddressBookParser parser = new AddressBookParser();
@Test
- public void parseCommand_add() throws Exception {
- Person person = new PersonBuilder().build();
- AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person));
- assertEquals(new AddCommand(person), command);
+ public void parseCommand_addStudent() throws Exception {
+ Student student = new StudentBuilder().build();
+ AddStudentCommand command = (AddStudentCommand) parser.parseCommand(StudentUtil.getAddStudentCommand(student));
+ assertEquals(new AddStudentCommand(student), command);
}
@Test
@@ -49,17 +60,17 @@ public void parseCommand_clear() throws Exception {
@Test
public void parseCommand_delete() throws Exception {
DeleteCommand command = (DeleteCommand) parser.parseCommand(
- DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
- assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
+ DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_STUDENT.getOneBased());
+ assertEquals(new DeleteCommand(INDEX_FIRST_STUDENT), command);
}
@Test
public void parseCommand_edit() throws Exception {
- Person person = new PersonBuilder().build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
+ Student student = new StudentBuilder().build();
+ EditCommand.EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder(student).build();
EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
- + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
- assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
+ + INDEX_FIRST_STUDENT.getOneBased() + " " + StudentUtil.getEditStudentDescriptorDetails(descriptor));
+ assertEquals(new EditCommand(INDEX_FIRST_STUDENT, descriptor), command);
}
@Test
@@ -76,6 +87,14 @@ public void parseCommand_find() throws Exception {
assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
}
+ @Test
+ public void parseCommand_findTutorialGroup() throws Exception {
+ String keyword = "CS2101 G08";
+ FindTutorialGroupCommand command = (FindTutorialGroupCommand) parser.parseCommand(
+ FindTutorialGroupCommand.COMMAND_WORD + " " + keyword);
+ assertEquals(new FindTutorialGroupCommand(new TutorialGroupKeywordsPredicate(keyword)), command);
+ }
+
@Test
public void parseCommand_help() throws Exception {
assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
@@ -88,6 +107,32 @@ public void parseCommand_list() throws Exception {
assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
}
+ @Test
+ public void parseCommand_addTutorialGroup() throws Exception {
+ AddTutorialGroupCommand.AddTutorialGroupDescriptor desc =
+ AddTutorialGroupDescriptorBuilder.VALID_TUTORIAL_GROUP_DESCRIPTOR_AMY;
+ assertTrue(new AddTutorialGroupCommand(INDEX_FIRST_STUDENT, desc) instanceof AddTutorialGroupCommand);
+ }
+
+ @Test
+ public void parseCommand_deleteTutorialGroupsFromStudents() throws Exception {
+ DeleteTutorialGroupsFromStudentsCommand command = (DeleteTutorialGroupsFromStudentsCommand) parser
+ .parseCommand(DeleteTutorialGroupsFromStudentsCommand.COMMAND_WORD
+ + " " + TUTORIAL_GROUP_DESC_CS2101_G08);
+ Set tutGroups = new HashSet<>(Arrays.asList(new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08)));
+ assertEquals(new DeleteTutorialGroupsFromStudentsCommand(tutGroups), command);
+ }
+
+ @Test
+ public void parseCommand_deleteTutorialGroup() throws Exception {
+ Student student = new StudentBuilder().build();
+ DeleteTutorialGroupCommand command = (DeleteTutorialGroupCommand) parser.parseCommand(
+ DeleteTutorialGroupCommand.COMMAND_WORD + " " + INDEX_FIRST_STUDENT.getOneBased()
+ + " " + PREFIX_TUTORIAL_GROUP + VALID_TUTORIAL_GROUP_CS2101_G08);
+ assertEquals(new DeleteTutorialGroupCommand(
+ INDEX_FIRST_STUDENT, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08)), command);
+ }
+
@Test
public void parseCommand_unrecognisedInput_throwsParseException() {
assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
index 27eaec84450..ff1cf943f84 100644
--- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
@@ -1,12 +1,13 @@
package seedu.address.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
import org.junit.jupiter.api.Test;
+import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.DeleteCommand;
/**
@@ -22,11 +23,12 @@ public class DeleteCommandParserTest {
@Test
public void parse_validArgs_returnsDeleteCommand() {
- assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
+ assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_STUDENT));
}
@Test
public void parse_invalidArgs_throwsParseException() {
- assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "a",
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteTutorialGroupParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteTutorialGroupParserTest.java
new file mode 100644
index 00000000000..4377d9274cf
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/DeleteTutorialGroupParserTest.java
@@ -0,0 +1,91 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_TUTORIAL_GROUP_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteTutorialGroupCommand;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+public class DeleteTutorialGroupParserTest {
+
+ private static final String TUTORIAL_GROUP_EMPTY = " " + PREFIX_TUTORIAL_GROUP;
+
+ private static final String MESSAGE_INVALID_FORMAT =
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTutorialGroupCommand.MESSAGE_USAGE);
+
+ private DeleteTutorialGroupParser parser = new DeleteTutorialGroupParser();
+
+ @Test
+ public void parse_missingParts_failure() {
+ // no index specified
+ assertParseFailure(parser, TUTORIAL_GROUP_DESC_CS2101_G08,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+
+ // no field specified
+ assertParseFailure(parser, "1", MESSAGE_INVALID_FORMAT);
+
+ // no index and no field specified
+ assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
+
+ }
+
+ @Test
+ public void parse_invalidPreamble_failure() {
+ // negative index
+ assertParseFailure(parser, "-6" + TUTORIAL_GROUP_DESC_CS2103T_W15_3,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+
+ // zero
+ assertParseFailure(parser, "0" + TUTORIAL_GROUP_DESC_CS2103T_W15_3,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+
+ // invalid preamble and invalid tutorial group, but only the first is captured
+ assertParseFailure(parser, "-1" + INVALID_TUTORIAL_GROUP_DESC,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+
+ //index larger than 2147483647
+ assertParseFailure(parser, "2147483648" + TUTORIAL_GROUP_DESC_CS2103T_W15_3,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+ }
+
+ @Test
+ public void parse_invalidValue_failure() {
+ // empty tutorial group
+ assertParseFailure(parser, "1" + TUTORIAL_GROUP_EMPTY, TutorialGroup.MESSAGE_CONSTRAINTS);
+
+ // invalid tutorial group
+ assertParseFailure(parser, "1" + INVALID_TUTORIAL_GROUP_DESC, TutorialGroup.MESSAGE_CONSTRAINTS);
+ }
+
+ @Test
+ public void parse_multipleValues_failure() {
+ // more than one tutorial group
+ assertParseFailure(parser,
+ "1" + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2101_G08,
+ DeleteTutorialGroupCommand.MESSAGE_NOT_DELETED);
+ }
+
+ @Test
+ public void parse_allFieldsSpecified_success() {
+ // valid index and tutorial group
+ Index targetIndex = INDEX_FIRST_STUDENT;
+ String input = targetIndex.getOneBased() + TUTORIAL_GROUP_DESC_CS2101_G08;
+
+ DeleteTutorialGroupCommand expectedCommand = new DeleteTutorialGroupCommand(
+ targetIndex, new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08));
+
+ assertParseSuccess(parser, input, expectedCommand);
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteTutorialGroupsFromStudentsParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteTutorialGroupsFromStudentsParserTest.java
new file mode 100644
index 00000000000..7c200305e6a
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/DeleteTutorialGroupsFromStudentsParserTest.java
@@ -0,0 +1,66 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.DeleteTutorialGroupsFromStudentsCommand;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+public class DeleteTutorialGroupsFromStudentsParserTest {
+
+ private static final String TUTORIAL_GROUP_EMPTY = " " + PREFIX_TUTORIAL_GROUP;
+
+ private static final String MESSAGE_INVALID_FORMAT =
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTutorialGroupsFromStudentsCommand.MESSAGE_USAGE);
+
+ private DeleteTutorialGroupsFromStudentsParser parser = new DeleteTutorialGroupsFromStudentsParser();
+
+ @Test
+ public void parse_missingParts_failure() {
+ // no prefix
+ assertParseFailure(parser, VALID_TUTORIAL_GROUP_CS2101_G08, MESSAGE_INVALID_FORMAT);
+
+ // empty string
+ assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
+
+ //no tutorial group given but name is given
+ assertParseFailure(parser, VALID_EMAIL_BOB, MESSAGE_INVALID_FORMAT);
+ }
+
+ @Test
+ public void parse_invalidValue_failure() {
+ // empty tutorial group
+ assertParseFailure(parser, TUTORIAL_GROUP_EMPTY, TutorialGroup.MESSAGE_CONSTRAINTS);
+
+ // valid then invalid tutorial group
+ assertParseFailure(parser, VALID_TUTORIAL_GROUP_CS2101_G08 + TUTORIAL_GROUP_EMPTY,
+ TutorialGroup.MESSAGE_CONSTRAINTS);
+ }
+
+ @Test
+ public void parse_allFieldsSpecified_success() {
+ // valid tutorial groups
+ String input = TUTORIAL_GROUP_DESC_CS2101_G08 + TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+ Set tutorialGroupInputToDeleteTutorialGroupFromStudentsCommand = new HashSet<>(Arrays.asList(
+ new TutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08),
+ new TutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3)));
+
+ DeleteTutorialGroupsFromStudentsCommand expectedCommand = new DeleteTutorialGroupsFromStudentsCommand(
+ tutorialGroupInputToDeleteTutorialGroupFromStudentsCommand);
+
+ assertParseSuccess(parser, input, expectedCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
index 2ff31522486..c8abe43c824 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
@@ -1,52 +1,53 @@
package seedu.address.logic.parser;
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.EMPTY_GITHUB_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.EMPTY_TELEGRAM_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.GITHUB_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.GITHUB_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMPTY_TUTORIAL_GROUP;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_GITHUB_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_TELEGRAM_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_TUTORIAL_GROUP_DESC;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.TELEGRAM_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.TELEGRAM_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_GROUP_DESC_CS2103T_W15_3;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_STUDENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_STUDENT;
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.logic.commands.EditCommand.EditStudentDescriptor;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.testutil.EditStudentDescriptorBuilder;
public class EditCommandParserTest {
- private static final String TAG_EMPTY = " " + PREFIX_TAG;
-
private static final String MESSAGE_INVALID_FORMAT =
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE);
@@ -55,65 +56,81 @@ public class EditCommandParserTest {
@Test
public void parse_missingParts_failure() {
// no index specified
- assertParseFailure(parser, VALID_NAME_AMY, MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, VALID_NAME_AMY,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
// no field specified
assertParseFailure(parser, "1", EditCommand.MESSAGE_NOT_EDITED);
// no index and no field specified
- assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "",
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
}
@Test
public void parse_invalidPreamble_failure() {
// negative index
- assertParseFailure(parser, "-5" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "-5" + NAME_DESC_AMY,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
// zero index
- assertParseFailure(parser, "0" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "0" + NAME_DESC_AMY,
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
// invalid arguments being parsed as preamble
- assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "1 some random string",
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
// invalid prefix being parsed as preamble
- assertParseFailure(parser, "1 i/ string", MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "1 i/ string",
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
+
+ //index larger than 2147483647
+ assertParseFailure(parser, "2147483648",
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, Index.MESSAGE_CONSTRAINT));
}
@Test
public void parse_invalidValue_failure() {
- assertParseFailure(parser, "1" + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name
- assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone
- assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email
- assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address
- assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag
-
- // invalid phone followed by valid email
- assertParseFailure(parser, "1" + INVALID_PHONE_DESC + EMAIL_DESC_AMY, Phone.MESSAGE_CONSTRAINTS);
-
- // valid phone followed by invalid phone. The test case for invalid phone followed by valid phone
+ assertParseFailure(parser, "1"
+ + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name
+ assertParseFailure(parser, "1"
+ + INVALID_TELEGRAM_DESC, Telegram.MESSAGE_CONSTRAINTS); // invalid telegram
+ assertParseFailure(parser, "1"
+ + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email
+ assertParseFailure(parser, "1"
+ + INVALID_GITHUB_DESC, GitHub.MESSAGE_CONSTRAINTS); // invalid gitHub
+ assertParseFailure(parser, "1"
+ + INVALID_TUTORIAL_GROUP_DESC, TutorialGroup.MESSAGE_CONSTRAINTS); // invalid tutorial group
+ assertParseFailure(parser, "1" + INVALID_EMPTY_TUTORIAL_GROUP,
+ TutorialGroup.MESSAGE_CONSTRAINTS); //empty tutorial group
+
+ // invalid telegram followed by valid email
+ assertParseFailure(parser, "1" + INVALID_TELEGRAM_DESC + EMAIL_DESC_AMY, Telegram.MESSAGE_CONSTRAINTS);
+
+ // valid telegram followed by invalid telegram. The test case for invalid telegram followed by valid telegram
// is tested at {@code parse_invalidValueFollowedByValidValue_success()}
- assertParseFailure(parser, "1" + PHONE_DESC_BOB + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS);
-
- // while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited,
- // parsing it together with a valid tag results in error
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + TELEGRAM_DESC_BOB + INVALID_TELEGRAM_DESC,
+ Telegram.MESSAGE_CONSTRAINTS);
// multiple invalid values, but only the first invalid value is captured
- assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY,
- Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC
+ + VALID_GITHUB_AMY + VALID_TELEGRAM_AMY, Name.MESSAGE_CONSTRAINTS);
+
+ //valid tutorial group followed by empty tutorial group
+ assertParseFailure(parser, "1" + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + INVALID_EMPTY_TUTORIAL_GROUP,
+ TutorialGroup.MESSAGE_CONSTRAINTS);
}
@Test
public void parse_allFieldsSpecified_success() {
- Index targetIndex = INDEX_SECOND_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + TAG_DESC_HUSBAND
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY + TAG_DESC_FRIEND;
+ Index targetIndex = INDEX_SECOND_STUDENT;
+ String userInput = targetIndex.getOneBased() + TELEGRAM_DESC_BOB + TUTORIAL_GROUP_DESC_CS2103T_W15_3
+ + EMAIL_DESC_AMY + GITHUB_DESC_AMY + NAME_DESC_AMY + TUTORIAL_GROUP_DESC_CS2101_G08;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ EditCommand.EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder().withName(VALID_NAME_AMY)
+ .withTelegram(VALID_TELEGRAM_BOB).withEmail(VALID_EMAIL_AMY).withGitHub(VALID_GITHUB_AMY)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3, VALID_TUTORIAL_GROUP_CS2101_G08).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
@@ -121,91 +138,113 @@ public void parse_allFieldsSpecified_success() {
@Test
public void parse_someFieldsSpecified_success() {
- Index targetIndex = INDEX_FIRST_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + EMAIL_DESC_AMY;
+ Index targetIndex = INDEX_FIRST_STUDENT;
+ String userInput = targetIndex.getOneBased() + TELEGRAM_DESC_BOB + EMAIL_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_AMY).build();
+ EditCommand.EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder()
+ .withTelegram(VALID_TELEGRAM_BOB).withEmail(VALID_EMAIL_AMY).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
+
}
@Test
public void parse_oneFieldSpecified_success() {
// name
- Index targetIndex = INDEX_THIRD_PERSON;
+ Index targetIndex = INDEX_THIRD_STUDENT;
String userInput = targetIndex.getOneBased() + NAME_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY).build();
+ EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder().withName(VALID_NAME_AMY).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
- // phone
- userInput = targetIndex.getOneBased() + PHONE_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_AMY).build();
+ // telegram
+ userInput = targetIndex.getOneBased() + TELEGRAM_DESC_AMY;
+ descriptor = new EditStudentDescriptorBuilder().withTelegram(VALID_TELEGRAM_AMY).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
// email
userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build();
+ descriptor = new EditStudentDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
- // address
- userInput = targetIndex.getOneBased() + ADDRESS_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withAddress(VALID_ADDRESS_AMY).build();
+ // gitHub
+ userInput = targetIndex.getOneBased() + GITHUB_DESC_AMY;
+ descriptor = new EditStudentDescriptorBuilder().withGitHub(VALID_GITHUB_AMY).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
- // tags
- userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND;
- descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build();
+ // tutorial groups
+ userInput = targetIndex.getOneBased() + TUTORIAL_GROUP_DESC_CS2101_G08;
+ descriptor = new EditStudentDescriptorBuilder().withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@Test
- public void parse_multipleRepeatedFields_acceptsLast() {
- Index targetIndex = INDEX_FIRST_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
- + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND
- + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + TAG_DESC_HUSBAND;
-
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
- .build();
+ public void parse_emptyFields_success() {
+ //Only for gitHub and telegram
+
+ //gitHub
+ Index targetIndex = INDEX_THIRD_STUDENT;
+ String userInput = targetIndex.getOneBased() + EMPTY_GITHUB_DESC;
+ EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder()
+ .withGitHub(null).build(); //empty gitHub instantiated using null during the parsing
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
+ assertParseSuccess(parser, userInput, expectedCommand);
+ //telegram
+ userInput = targetIndex.getOneBased() + EMPTY_TELEGRAM_DESC;
+ descriptor = new EditStudentDescriptorBuilder()
+ .withTelegram(null).build(); //empty telegram instantiated using null during the parsing
+ expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@Test
- public void parse_invalidValueFollowedByValidValue_success() {
- // no other valid values specified
- Index targetIndex = INDEX_FIRST_PERSON;
- String userInput = targetIndex.getOneBased() + INVALID_PHONE_DESC + PHONE_DESC_BOB;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB).build();
+ public void parse_multipleRepeatedFields_acceptsLast() {
+ Index targetIndex = INDEX_FIRST_STUDENT;
+ String userInput = targetIndex.getOneBased() + TELEGRAM_DESC_AMY + GITHUB_DESC_AMY + EMAIL_DESC_AMY
+ + TUTORIAL_GROUP_DESC_CS2101_G08 + TELEGRAM_DESC_AMY + GITHUB_DESC_AMY + EMAIL_DESC_AMY
+ + TUTORIAL_GROUP_DESC_CS2101_G08 + TELEGRAM_DESC_BOB + GITHUB_DESC_BOB + EMAIL_DESC_BOB
+ + TUTORIAL_GROUP_DESC_CS2103T_W15_3;
+
+ EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder().withTelegram(VALID_TELEGRAM_BOB)
+ .withEmail(VALID_EMAIL_BOB).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08, VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
+
assertParseSuccess(parser, userInput, expectedCommand);
- // other valid values specified
- userInput = targetIndex.getOneBased() + EMAIL_DESC_BOB + INVALID_PHONE_DESC + ADDRESS_DESC_BOB
- + PHONE_DESC_BOB;
- descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
- .withAddress(VALID_ADDRESS_BOB).build();
+ //repeatedTutorialGroups
+ userInput = targetIndex.getOneBased() + TUTORIAL_GROUP_DESC_CS2103T_W15_3 + TUTORIAL_GROUP_DESC_CS2103T_W15_3
+ + TUTORIAL_GROUP_DESC_CS2101_G08 + TUTORIAL_GROUP_DESC_CS2101_G08 + TUTORIAL_GROUP_DESC_CS2101_G08;
+ descriptor = new EditStudentDescriptorBuilder()
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08, VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
+
assertParseSuccess(parser, userInput, expectedCommand);
}
@Test
- public void parse_resetTags_success() {
- Index targetIndex = INDEX_THIRD_PERSON;
- String userInput = targetIndex.getOneBased() + TAG_EMPTY;
-
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build();
+ public void parse_invalidValueFollowedByValidValue_success() {
+ // no other valid values specified
+ Index targetIndex = INDEX_FIRST_STUDENT;
+ String userInput = targetIndex.getOneBased() + INVALID_TELEGRAM_DESC + TELEGRAM_DESC_BOB;
+ EditCommand.EditStudentDescriptor descriptor = new EditStudentDescriptorBuilder()
+ .withTelegram(VALID_TELEGRAM_BOB).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
+ assertParseSuccess(parser, userInput, expectedCommand);
+ // other valid values specified
+ userInput = targetIndex.getOneBased() + EMAIL_DESC_BOB + INVALID_TELEGRAM_DESC + GITHUB_DESC_BOB
+ + TELEGRAM_DESC_BOB;
+ descriptor = new EditStudentDescriptorBuilder().withTelegram(VALID_TELEGRAM_BOB).withEmail(VALID_EMAIL_BOB)
+ .withGitHub(VALID_GITHUB_BOB).build();
+ expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
+
}
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
index 70f4f0e79c4..1c03f57be05 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
@@ -9,7 +9,7 @@
import org.junit.jupiter.api.Test;
import seedu.address.logic.commands.FindCommand;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
public class FindCommandParserTest {
@@ -17,7 +17,8 @@ public class FindCommandParserTest {
@Test
public void parse_emptyArg_throwsParseException() {
- assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
}
@Test
diff --git a/src/test/java/seedu/address/logic/parser/FindTutorialGroupParserTest.java b/src/test/java/seedu/address/logic/parser/FindTutorialGroupParserTest.java
new file mode 100644
index 00000000000..6b0f6b27f67
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindTutorialGroupParserTest.java
@@ -0,0 +1,41 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindTutorialGroupCommand;
+import seedu.address.model.tutorialgroup.TutorialGroupKeywordsPredicate;
+
+public class FindTutorialGroupParserTest {
+ private FindTutorialGroupParser parser = new FindTutorialGroupParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindTutorialGroupCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsPArseException() {
+ // no whitespace character to separate module and tutorial group
+ assertParseFailure(parser, "cs2100", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindTutorialGroupCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindCommand() {
+ // no leading and trailing whitespaces
+ FindTutorialGroupCommand expectedFindCommand =
+ new FindTutorialGroupCommand(new TutorialGroupKeywordsPredicate("CS2101 G08"));
+ assertParseSuccess(parser, "CS2101 G08", expectedFindCommand);
+
+ // with leading and trailing whitespaces
+ assertParseSuccess(parser, " \n CS2101 G08 \n", expectedFindCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, "CS2101 \n G08", expectedFindCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
index 4256788b1a7..96de79b03f8 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
@@ -2,9 +2,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_STUDENT;
import java.util.Arrays;
import java.util.Collections;
@@ -14,25 +13,25 @@
import org.junit.jupiter.api.Test;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
public class ParserUtilTest {
private static final String INVALID_NAME = "R@chel";
- private static final String INVALID_PHONE = "+651234";
- private static final String INVALID_ADDRESS = " ";
- private static final String INVALID_EMAIL = "example.com";
- private static final String INVALID_TAG = "#friend";
+ private static final String INVALID_TELEGRAM = "+651234";
+ private static final String INVALID_GITHUB = " ";
+ private static final String INVALID_EMAIL = "u.nus.edu";
+ private static final String INVALID_TUTORIAL_GROUP = "#friend";
private static final String VALID_NAME = "Rachel Walker";
- private static final String VALID_PHONE = "123456";
- private static final String VALID_ADDRESS = "123 Main Street #0505";
- private static final String VALID_EMAIL = "rachel@example.com";
- private static final String VALID_TAG_1 = "friend";
- private static final String VALID_TAG_2 = "neighbour";
+ private static final String VALID_TELEGRAM = "@123456";
+ private static final String VALID_GITHUB = "Walk-Rachel";
+ private static final String VALID_EMAIL = "rachel@u.nus.edu";
+ private static final String VALID_TUTORIAL_GROUP_1 = "ST2334 T01";
+ private static final String VALID_TUTORIAL_GROUP_2 = "ES2660 G04";
private static final String WHITESPACE = " \t\r\n";
@@ -43,17 +42,29 @@ public void parseIndex_invalidInput_throwsParseException() {
@Test
public void parseIndex_outOfRangeInput_throwsParseException() {
- assertThrows(ParseException.class, MESSAGE_INVALID_INDEX, ()
+ assertThrows(ParseException.class, ()
-> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1)));
}
@Test
public void parseIndex_validInput_success() throws Exception {
// No whitespaces
- assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex("1"));
+ assertEquals(INDEX_FIRST_STUDENT, ParserUtil.parseIndex("1"));
// Leading and trailing whitespaces
- assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex(" 1 "));
+ assertEquals(INDEX_FIRST_STUDENT, ParserUtil.parseIndex(" 1 "));
+ }
+
+ @Test
+ public void parseTelegram_null_returnsEmptyTelegram() throws ParseException {
+ Telegram telegram = new Telegram(null);
+ assertEquals(telegram, ParserUtil.parseTelegram(null));
+ }
+
+ @Test
+ public void parseGitHub_null_returnsEmptyGitHub() throws ParseException {
+ GitHub github = new GitHub(null);
+ assertEquals(github, ParserUtil.parseGitHub(null));
}
@Test
@@ -80,49 +91,39 @@ public void parseName_validValueWithWhitespace_returnsTrimmedName() throws Excep
}
@Test
- public void parsePhone_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parsePhone((String) null));
+ public void parseTelegram_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseTelegram(INVALID_TELEGRAM));
}
@Test
- public void parsePhone_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parsePhone(INVALID_PHONE));
+ public void parseTelegram_validValueWithoutWhitespace_returnsTelegram() throws Exception {
+ Telegram expectedTelegram = new Telegram(VALID_TELEGRAM);
+ assertEquals(expectedTelegram, ParserUtil.parseTelegram(VALID_TELEGRAM));
}
@Test
- public void parsePhone_validValueWithoutWhitespace_returnsPhone() throws Exception {
- Phone expectedPhone = new Phone(VALID_PHONE);
- assertEquals(expectedPhone, ParserUtil.parsePhone(VALID_PHONE));
+ public void parseTelegram_validValueWithWhitespace_returnsTrimmedTelegram() throws Exception {
+ String telegramWithWhitespace = WHITESPACE + VALID_TELEGRAM + WHITESPACE;
+ Telegram expectedTelegram = new Telegram(VALID_TELEGRAM);
+ assertEquals(expectedTelegram, ParserUtil.parseTelegram(telegramWithWhitespace));
}
@Test
- public void parsePhone_validValueWithWhitespace_returnsTrimmedPhone() throws Exception {
- String phoneWithWhitespace = WHITESPACE + VALID_PHONE + WHITESPACE;
- Phone expectedPhone = new Phone(VALID_PHONE);
- assertEquals(expectedPhone, ParserUtil.parsePhone(phoneWithWhitespace));
+ public void parseGitHub_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseGitHub(INVALID_GITHUB));
}
@Test
- public void parseAddress_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseAddress((String) null));
+ public void parseGitHub_validValueWithoutWhitespace_returnsGitHub() throws Exception {
+ GitHub expectedGitHub = new GitHub(VALID_GITHUB);
+ assertEquals(expectedGitHub, ParserUtil.parseGitHub(VALID_GITHUB));
}
@Test
- public void parseAddress_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseAddress(INVALID_ADDRESS));
- }
-
- @Test
- public void parseAddress_validValueWithoutWhitespace_returnsAddress() throws Exception {
- Address expectedAddress = new Address(VALID_ADDRESS);
- assertEquals(expectedAddress, ParserUtil.parseAddress(VALID_ADDRESS));
- }
-
- @Test
- public void parseAddress_validValueWithWhitespace_returnsTrimmedAddress() throws Exception {
- String addressWithWhitespace = WHITESPACE + VALID_ADDRESS + WHITESPACE;
- Address expectedAddress = new Address(VALID_ADDRESS);
- assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace));
+ public void parseGitHub_validValueWithWhitespace_returnsTrimmedGitHub() throws Exception {
+ String gitHubWithWhitespace = WHITESPACE + VALID_GITHUB + WHITESPACE;
+ GitHub expectedGitHub = new GitHub(VALID_GITHUB);
+ assertEquals(expectedGitHub, ParserUtil.parseGitHub(gitHubWithWhitespace));
}
@Test
@@ -149,48 +150,58 @@ public void parseEmail_validValueWithWhitespace_returnsTrimmedEmail() throws Exc
}
@Test
- public void parseTag_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTag(null));
+ public void parseTutorialGroup_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseTutorialGroup(null));
+ }
+
+ @Test
+ public void parseTutorialGroup_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseTutorialGroup(INVALID_TUTORIAL_GROUP));
}
@Test
- public void parseTag_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTag(INVALID_TAG));
+ public void parseTutorialGroup_validValueWithoutWhitespace_returnsTutorialGroup() throws Exception {
+ TutorialGroup expectedTutorialGroup = new TutorialGroup(VALID_TUTORIAL_GROUP_1);
+ assertEquals(expectedTutorialGroup, ParserUtil.parseTutorialGroup(VALID_TUTORIAL_GROUP_1));
}
@Test
- public void parseTag_validValueWithoutWhitespace_returnsTag() throws Exception {
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(VALID_TAG_1));
+ public void parseTutorialGroup_validValueWithWhitespace_returnsTrimmedTutorialGroup() throws Exception {
+ String tutorialGroupWithWhitespace = WHITESPACE + VALID_TUTORIAL_GROUP_1 + WHITESPACE;
+ TutorialGroup expectedTutorialGroup = new TutorialGroup(VALID_TUTORIAL_GROUP_1);
+ assertEquals(expectedTutorialGroup, ParserUtil.parseTutorialGroup(tutorialGroupWithWhitespace));
}
@Test
- public void parseTag_validValueWithWhitespace_returnsTrimmedTag() throws Exception {
- String tagWithWhitespace = WHITESPACE + VALID_TAG_1 + WHITESPACE;
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(tagWithWhitespace));
+ public void parseTutorialGroup_validTutorialInLowercase_returnsTutorialGroupInUppercase() throws Exception {
+ String validTutorialGroupInLowercase = VALID_TUTORIAL_GROUP_1.toLowerCase();
+ TutorialGroup expectedTutorialGroup = new TutorialGroup(VALID_TUTORIAL_GROUP_1.toUpperCase());
+ assertEquals(expectedTutorialGroup, ParserUtil.parseTutorialGroup(validTutorialGroupInLowercase));
}
@Test
- public void parseTags_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTags(null));
+ public void parseTutorialGroups_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseTutorialGroups(null));
}
@Test
- public void parseTags_collectionWithInvalidTags_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, INVALID_TAG)));
+ public void parseTutorialGroups_collectionWithInvalidTutorialGroups_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseTutorialGroups(
+ Arrays.asList(VALID_TUTORIAL_GROUP_1, INVALID_TUTORIAL_GROUP)));
}
@Test
- public void parseTags_emptyCollection_returnsEmptySet() throws Exception {
- assertTrue(ParserUtil.parseTags(Collections.emptyList()).isEmpty());
+ public void parseTutorialGroups_emptyCollection_returnsEmptySet() throws Exception {
+ assertTrue(ParserUtil.parseTutorialGroups(Collections.emptyList()).isEmpty());
}
@Test
- public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception {
- Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, VALID_TAG_2));
- Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2)));
+ public void parseTutorialGroups_collectionWithValidTutorialGroups_returnsTutorialGroupSet() throws Exception {
+ Set actualTutorialGroupSet = ParserUtil.parseTutorialGroups(
+ Arrays.asList(VALID_TUTORIAL_GROUP_1, VALID_TUTORIAL_GROUP_2));
+ Set expectedTutorialGroupSet = new HashSet(
+ Arrays.asList(new TutorialGroup(VALID_TUTORIAL_GROUP_1), new TutorialGroup(VALID_TUTORIAL_GROUP_2)));
- assertEquals(expectedTagSet, actualTagSet);
+ assertEquals(expectedTutorialGroupSet, actualTutorialGroupSet);
}
}
diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java
index 87782528ecd..de49975c043 100644
--- a/src/test/java/seedu/address/model/AddressBookTest.java
+++ b/src/test/java/seedu/address/model/AddressBookTest.java
@@ -3,11 +3,11 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalStudents.ALICE;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import java.util.Arrays;
import java.util.Collection;
@@ -18,9 +18,9 @@
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.exceptions.DuplicateStudentException;
+import seedu.address.testutil.StudentBuilder;
public class AddressBookTest {
@@ -28,7 +28,7 @@ public class AddressBookTest {
@Test
public void constructor() {
- assertEquals(Collections.emptyList(), addressBook.getPersonList());
+ assertEquals(Collections.emptyList(), addressBook.getStudentList());
}
@Test
@@ -44,58 +44,58 @@ public void resetData_withValidReadOnlyAddressBook_replacesData() {
}
@Test
- public void resetData_withDuplicatePersons_throwsDuplicatePersonException() {
- // Two persons with the same identity fields
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- List newPersons = Arrays.asList(ALICE, editedAlice);
- AddressBookStub newData = new AddressBookStub(newPersons);
-
- assertThrows(DuplicatePersonException.class, () -> addressBook.resetData(newData));
+ public void resetData_withDuplicateStudents_throwsDuplicateStudentException() {
+ // Two students with the same identity fields
+ Student editedAlice = new StudentBuilder(ALICE).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ List newStudents = Arrays.asList(ALICE, editedAlice);
+ AddressBookStub newData = new AddressBookStub(newStudents);
+
+ assertThrows(DuplicateStudentException.class, () -> addressBook.resetData(newData));
}
@Test
- public void hasPerson_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> addressBook.hasPerson(null));
+ public void hasStudent_nullStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> addressBook.hasStudent(null));
}
@Test
- public void hasPerson_personNotInAddressBook_returnsFalse() {
- assertFalse(addressBook.hasPerson(ALICE));
+ public void hasStudent_studentNotInAddressBook_returnsFalse() {
+ assertFalse(addressBook.hasStudent(ALICE));
}
@Test
- public void hasPerson_personInAddressBook_returnsTrue() {
- addressBook.addPerson(ALICE);
- assertTrue(addressBook.hasPerson(ALICE));
+ public void hasStudent_studentInAddressBook_returnsTrue() {
+ addressBook.addStudent(ALICE);
+ assertTrue(addressBook.hasStudent(ALICE));
}
@Test
- public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() {
- addressBook.addPerson(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- assertTrue(addressBook.hasPerson(editedAlice));
+ public void hasStudent_studentWithSameIdentityFieldsInAddressBook_returnsTrue() {
+ addressBook.addStudent(ALICE);
+ Student editedAlice = new StudentBuilder(ALICE).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ assertTrue(addressBook.hasStudent(editedAlice));
}
@Test
- public void getPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> addressBook.getPersonList().remove(0));
+ public void getStudentList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> addressBook.getStudentList().remove(0));
}
/**
- * A stub ReadOnlyAddressBook whose persons list can violate interface constraints.
+ * A stub ReadOnlyAddressBook whose students list can violate interface constraints.
*/
private static class AddressBookStub implements ReadOnlyAddressBook {
- private final ObservableList persons = FXCollections.observableArrayList();
+ private final ObservableList students = FXCollections.observableArrayList();
- AddressBookStub(Collection persons) {
- this.persons.setAll(persons);
+ AddressBookStub(Collection students) {
+ this.students.setAll(students);
}
@Override
- public ObservableList getPersonList() {
- return persons;
+ public ObservableList getStudentList() {
+ return students;
}
}
diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java
index 2cf1418d116..466563a3022 100644
--- a/src/test/java/seedu/address/model/ModelManagerTest.java
+++ b/src/test/java/seedu/address/model/ModelManagerTest.java
@@ -3,10 +3,10 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalStudents.ALICE;
+import static seedu.address.testutil.TypicalStudents.BENSON;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -15,7 +15,7 @@
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
import seedu.address.testutil.AddressBookBuilder;
public class ModelManagerTest {
@@ -73,29 +73,29 @@ public void setAddressBookFilePath_validPath_setsAddressBookFilePath() {
}
@Test
- public void hasPerson_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> modelManager.hasPerson(null));
+ public void hasStudent_nullStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> modelManager.hasStudent(null));
}
@Test
- public void hasPerson_personNotInAddressBook_returnsFalse() {
- assertFalse(modelManager.hasPerson(ALICE));
+ public void hasStudent_studentNotInAddressBook_returnsFalse() {
+ assertFalse(modelManager.hasStudent(ALICE));
}
@Test
- public void hasPerson_personInAddressBook_returnsTrue() {
- modelManager.addPerson(ALICE);
- assertTrue(modelManager.hasPerson(ALICE));
+ public void hasStudent_studentInAddressBook_returnsTrue() {
+ modelManager.addStudent(ALICE);
+ assertTrue(modelManager.hasStudent(ALICE));
}
@Test
- public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0));
+ public void getFilteredStudentList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredStudentList().remove(0));
}
@Test
public void equals() {
- AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build();
+ AddressBook addressBook = new AddressBookBuilder().withStudent(ALICE).withStudent(BENSON).build();
AddressBook differentAddressBook = new AddressBook();
UserPrefs userPrefs = new UserPrefs();
@@ -118,11 +118,11 @@ public void equals() {
// different filteredList -> returns false
String[] keywords = ALICE.getName().fullName.split("\\s+");
- modelManager.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(keywords)));
+ modelManager.updateFilteredStudentList(new NameContainsKeywordsPredicate(Arrays.asList(keywords)));
assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs)));
// resets modelManager to initial state for upcoming tests
- modelManager.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ modelManager.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
// different userPrefs -> returns false
UserPrefs differentUserPrefs = new UserPrefs();
diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/person/AddressTest.java
deleted file mode 100644
index dcd3be87b3a..00000000000
--- a/src/test/java/seedu/address/model/person/AddressTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class AddressTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Address(null));
- }
-
- @Test
- public void constructor_invalidAddress_throwsIllegalArgumentException() {
- String invalidAddress = "";
- assertThrows(IllegalArgumentException.class, () -> new Address(invalidAddress));
- }
-
- @Test
- public void isValidAddress() {
- // null address
- assertThrows(NullPointerException.class, () -> Address.isValidAddress(null));
-
- // invalid addresses
- assertFalse(Address.isValidAddress("")); // empty string
- assertFalse(Address.isValidAddress(" ")); // spaces only
-
- // valid addresses
- assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355"));
- assertTrue(Address.isValidAddress("-")); // one character
- assertTrue(Address.isValidAddress("Leng Inc; 1234 Market St; San Francisco CA 2349879; USA")); // long address
- }
-}
diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/seedu/address/model/person/EmailTest.java
deleted file mode 100644
index bbcc6c8c98e..00000000000
--- a/src/test/java/seedu/address/model/person/EmailTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class EmailTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Email(null));
- }
-
- @Test
- public void constructor_invalidEmail_throwsIllegalArgumentException() {
- String invalidEmail = "";
- assertThrows(IllegalArgumentException.class, () -> new Email(invalidEmail));
- }
-
- @Test
- public void isValidEmail() {
- // null email
- assertThrows(NullPointerException.class, () -> Email.isValidEmail(null));
-
- // blank email
- assertFalse(Email.isValidEmail("")); // empty string
- assertFalse(Email.isValidEmail(" ")); // spaces only
-
- // missing parts
- assertFalse(Email.isValidEmail("@example.com")); // missing local part
- assertFalse(Email.isValidEmail("peterjackexample.com")); // missing '@' symbol
- assertFalse(Email.isValidEmail("peterjack@")); // missing domain name
-
- // invalid parts
- assertFalse(Email.isValidEmail("peterjack@-")); // invalid domain name
- assertFalse(Email.isValidEmail("peterjack@exam_ple.com")); // underscore in domain name
- assertFalse(Email.isValidEmail("peter jack@example.com")); // spaces in local part
- assertFalse(Email.isValidEmail("peterjack@exam ple.com")); // spaces in domain name
- assertFalse(Email.isValidEmail(" peterjack@example.com")); // leading space
- assertFalse(Email.isValidEmail("peterjack@example.com ")); // trailing space
- assertFalse(Email.isValidEmail("peterjack@@example.com")); // double '@' symbol
- assertFalse(Email.isValidEmail("peter@jack@example.com")); // '@' symbol in local part
- assertFalse(Email.isValidEmail("-peterjack@example.com")); // local part starts with a hyphen
- assertFalse(Email.isValidEmail("peterjack-@example.com")); // local part ends with a hyphen
- assertFalse(Email.isValidEmail("peter..jack@example.com")); // local part has two consecutive periods
- assertFalse(Email.isValidEmail("peterjack@example@com")); // '@' symbol in domain name
- assertFalse(Email.isValidEmail("peterjack@.example.com")); // domain name starts with a period
- assertFalse(Email.isValidEmail("peterjack@example.com.")); // domain name ends with a period
- assertFalse(Email.isValidEmail("peterjack@-example.com")); // domain name starts with a hyphen
- assertFalse(Email.isValidEmail("peterjack@example.com-")); // domain name ends with a hyphen
- assertFalse(Email.isValidEmail("peterjack@example.c")); // top level domain has less than two chars
-
- // valid email
- assertTrue(Email.isValidEmail("PeterJack_1190@example.com")); // underscore in local part
- assertTrue(Email.isValidEmail("PeterJack.1190@example.com")); // period in local part
- assertTrue(Email.isValidEmail("PeterJack+1190@example.com")); // '+' symbol in local part
- assertTrue(Email.isValidEmail("PeterJack-1190@example.com")); // hyphen in local part
- assertTrue(Email.isValidEmail("a@bc")); // minimal
- assertTrue(Email.isValidEmail("test@localhost")); // alphabets only
- assertTrue(Email.isValidEmail("123@145")); // numeric local part and domain name
- assertTrue(Email.isValidEmail("a1+be.d@example1.com")); // mixture of alphanumeric and special characters
- assertTrue(Email.isValidEmail("peter_jack@very-very-very-long-example.com")); // long domain name
- assertTrue(Email.isValidEmail("if.you.dream.it_you.can.do.it@example.com")); // long local part
- assertTrue(Email.isValidEmail("e1234567@u.nus.edu")); // more than one period in domain
- }
-}
diff --git a/src/test/java/seedu/address/model/person/NameTest.java b/src/test/java/seedu/address/model/person/NameTest.java
deleted file mode 100644
index c9801392874..00000000000
--- a/src/test/java/seedu/address/model/person/NameTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class NameTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Name(null));
- }
-
- @Test
- public void constructor_invalidName_throwsIllegalArgumentException() {
- String invalidName = "";
- assertThrows(IllegalArgumentException.class, () -> new Name(invalidName));
- }
-
- @Test
- public void isValidName() {
- // null name
- assertThrows(NullPointerException.class, () -> Name.isValidName(null));
-
- // invalid name
- assertFalse(Name.isValidName("")); // empty string
- assertFalse(Name.isValidName(" ")); // spaces only
- assertFalse(Name.isValidName("^")); // only non-alphanumeric characters
- assertFalse(Name.isValidName("peter*")); // contains non-alphanumeric characters
-
- // valid name
- assertTrue(Name.isValidName("peter jack")); // alphabets only
- assertTrue(Name.isValidName("12345")); // numbers only
- assertTrue(Name.isValidName("peter the 2nd")); // alphanumeric characters
- assertTrue(Name.isValidName("Capital Tan")); // with capital letters
- assertTrue(Name.isValidName("David Roger Jackson Ray Jr 2nd")); // long names
- }
-}
diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java
deleted file mode 100644
index b29c097cfd4..00000000000
--- a/src/test/java/seedu/address/model/person/PersonTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BOB;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.testutil.PersonBuilder;
-
-public class PersonTest {
-
- @Test
- public void asObservableList_modifyList_throwsUnsupportedOperationException() {
- Person person = new PersonBuilder().build();
- assertThrows(UnsupportedOperationException.class, () -> person.getTags().remove(0));
- }
-
- @Test
- public void isSamePerson() {
- // same object -> returns true
- assertTrue(ALICE.isSamePerson(ALICE));
-
- // null -> returns false
- assertFalse(ALICE.isSamePerson(null));
-
- // same name, all other attributes different -> returns true
- Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
- .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND).build();
- assertTrue(ALICE.isSamePerson(editedAlice));
-
- // different name, all other attributes same -> returns false
- editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
- assertFalse(ALICE.isSamePerson(editedAlice));
-
- // name differs in case, all other attributes same -> returns false
- Person editedBob = new PersonBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build();
- assertFalse(BOB.isSamePerson(editedBob));
-
- // name has trailing spaces, all other attributes same -> returns false
- String nameWithTrailingSpaces = VALID_NAME_BOB + " ";
- editedBob = new PersonBuilder(BOB).withName(nameWithTrailingSpaces).build();
- assertFalse(BOB.isSamePerson(editedBob));
- }
-
- @Test
- public void equals() {
- // same values -> returns true
- Person aliceCopy = new PersonBuilder(ALICE).build();
- assertTrue(ALICE.equals(aliceCopy));
-
- // same object -> returns true
- assertTrue(ALICE.equals(ALICE));
-
- // null -> returns false
- assertFalse(ALICE.equals(null));
-
- // different type -> returns false
- assertFalse(ALICE.equals(5));
-
- // different person -> returns false
- assertFalse(ALICE.equals(BOB));
-
- // different name -> returns false
- Person editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different phone -> returns false
- editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different email -> returns false
- editedAlice = new PersonBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different address -> returns false
- editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different tags -> returns false
- editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build();
- assertFalse(ALICE.equals(editedAlice));
- }
-}
diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/seedu/address/model/person/PhoneTest.java
deleted file mode 100644
index 8dd52766a5f..00000000000
--- a/src/test/java/seedu/address/model/person/PhoneTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class PhoneTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Phone(null));
- }
-
- @Test
- public void constructor_invalidPhone_throwsIllegalArgumentException() {
- String invalidPhone = "";
- assertThrows(IllegalArgumentException.class, () -> new Phone(invalidPhone));
- }
-
- @Test
- public void isValidPhone() {
- // null phone number
- assertThrows(NullPointerException.class, () -> Phone.isValidPhone(null));
-
- // invalid phone numbers
- assertFalse(Phone.isValidPhone("")); // empty string
- assertFalse(Phone.isValidPhone(" ")); // spaces only
- assertFalse(Phone.isValidPhone("91")); // less than 3 numbers
- assertFalse(Phone.isValidPhone("phone")); // non-numeric
- assertFalse(Phone.isValidPhone("9011p041")); // alphabets within digits
- assertFalse(Phone.isValidPhone("9312 1534")); // spaces within digits
-
- // valid phone numbers
- assertTrue(Phone.isValidPhone("911")); // exactly 3 numbers
- assertTrue(Phone.isValidPhone("93121534"));
- assertTrue(Phone.isValidPhone("124293842033123")); // long phone numbers
- }
-}
diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/seedu/address/model/person/UniquePersonListTest.java
deleted file mode 100644
index 1cc5fe9e0fe..00000000000
--- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BOB;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-import seedu.address.testutil.PersonBuilder;
-
-public class UniquePersonListTest {
-
- private final UniquePersonList uniquePersonList = new UniquePersonList();
-
- @Test
- public void contains_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.contains(null));
- }
-
- @Test
- public void contains_personNotInList_returnsFalse() {
- assertFalse(uniquePersonList.contains(ALICE));
- }
-
- @Test
- public void contains_personInList_returnsTrue() {
- uniquePersonList.add(ALICE);
- assertTrue(uniquePersonList.contains(ALICE));
- }
-
- @Test
- public void contains_personWithSameIdentityFieldsInList_returnsTrue() {
- uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- assertTrue(uniquePersonList.contains(editedAlice));
- }
-
- @Test
- public void add_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.add(null));
- }
-
- @Test
- public void add_duplicatePerson_throwsDuplicatePersonException() {
- uniquePersonList.add(ALICE);
- assertThrows(DuplicatePersonException.class, () -> uniquePersonList.add(ALICE));
- }
-
- @Test
- public void setPerson_nullTargetPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPerson(null, ALICE));
- }
-
- @Test
- public void setPerson_nullEditedPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPerson(ALICE, null));
- }
-
- @Test
- public void setPerson_targetPersonNotInList_throwsPersonNotFoundException() {
- assertThrows(PersonNotFoundException.class, () -> uniquePersonList.setPerson(ALICE, ALICE));
- }
-
- @Test
- public void setPerson_editedPersonIsSamePerson_success() {
- uniquePersonList.add(ALICE);
- uniquePersonList.setPerson(ALICE, ALICE);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(ALICE);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPerson_editedPersonHasSameIdentity_success() {
- uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- uniquePersonList.setPerson(ALICE, editedAlice);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(editedAlice);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPerson_editedPersonHasDifferentIdentity_success() {
- uniquePersonList.add(ALICE);
- uniquePersonList.setPerson(ALICE, BOB);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(BOB);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPerson_editedPersonHasNonUniqueIdentity_throwsDuplicatePersonException() {
- uniquePersonList.add(ALICE);
- uniquePersonList.add(BOB);
- assertThrows(DuplicatePersonException.class, () -> uniquePersonList.setPerson(ALICE, BOB));
- }
-
- @Test
- public void remove_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.remove(null));
- }
-
- @Test
- public void remove_personDoesNotExist_throwsPersonNotFoundException() {
- assertThrows(PersonNotFoundException.class, () -> uniquePersonList.remove(ALICE));
- }
-
- @Test
- public void remove_existingPerson_removesPerson() {
- uniquePersonList.add(ALICE);
- uniquePersonList.remove(ALICE);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPersons_nullUniquePersonList_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPersons((UniquePersonList) null));
- }
-
- @Test
- public void setPersons_uniquePersonList_replacesOwnListWithProvidedUniquePersonList() {
- uniquePersonList.add(ALICE);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(BOB);
- uniquePersonList.setPersons(expectedUniquePersonList);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPersons_nullList_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPersons((List) null));
- }
-
- @Test
- public void setPersons_list_replacesOwnListWithProvidedList() {
- uniquePersonList.add(ALICE);
- List personList = Collections.singletonList(BOB);
- uniquePersonList.setPersons(personList);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(BOB);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPersons_listWithDuplicatePersons_throwsDuplicatePersonException() {
- List listWithDuplicatePersons = Arrays.asList(ALICE, ALICE);
- assertThrows(DuplicatePersonException.class, () -> uniquePersonList.setPersons(listWithDuplicatePersons));
- }
-
- @Test
- public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, ()
- -> uniquePersonList.asUnmodifiableObservableList().remove(0));
- }
-}
diff --git a/src/test/java/seedu/address/model/student/EmailTest.java b/src/test/java/seedu/address/model/student/EmailTest.java
new file mode 100644
index 00000000000..9c38f35c991
--- /dev/null
+++ b/src/test/java/seedu/address/model/student/EmailTest.java
@@ -0,0 +1,74 @@
+package seedu.address.model.student;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class EmailTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Email(null));
+ }
+
+ @Test
+ public void constructor_invalidEmail_throwsIllegalArgumentException() {
+ String invalidEmail = "";
+ assertThrows(IllegalArgumentException.class, () -> new Email(invalidEmail));
+ }
+
+ @Test
+ public void isValidEmail() {
+ // null email
+ assertThrows(NullPointerException.class, () -> Email.isValidEmail(null));
+
+ // blank email
+ assertFalse(Email.isValidEmail("")); // empty string
+ assertFalse(Email.isValidEmail(" ")); // spaces only
+
+ // missing parts
+ assertFalse(Email.isValidEmail("@u.nus.edu")); // missing local part
+ assertFalse(Email.isValidEmail("peterjacku.nus.edu")); // missing '@' symbol
+ assertFalse(Email.isValidEmail("peterjack@")); // missing domain name
+
+ // invalid parts
+ assertFalse(Email.isValidEmail("peterjack@-")); // invalid domain name
+ assertFalse(Email.isValidEmail("peterjack@u_nus.edu")); // underscore in domain name
+ assertFalse(Email.isValidEmail("peter jack@u.nus.edu")); // spaces in local part
+ assertFalse(Email.isValidEmail("peterjack@u nus.edu")); // spaces in domain name
+ assertFalse(Email.isValidEmail(" peterjack@u.nus.edu")); // leading space
+ assertFalse(Email.isValidEmail("peterjack@u.nus.edu ")); // trailing space
+ assertFalse(Email.isValidEmail("peterjack@@u.nus.edu")); // double '@' symbol
+ assertFalse(Email.isValidEmail("peter@jack@u.nus.edu")); // '@' symbol in local part
+ assertFalse(Email.isValidEmail("-peterjack@u.nus.edu")); // local part starts with a hyphen
+ assertFalse(Email.isValidEmail("peterjack-@u.nus.edu")); // local part ends with a hyphen
+ assertFalse(Email.isValidEmail("peter..jack@u.nus.edu")); // local part has two consecutive periods
+ assertFalse(Email.isValidEmail("peterjack@u.nus@edu")); // '@' symbol in domain name
+ assertFalse(Email.isValidEmail("peterjack@.u.nus.edu")); // domain name starts with a period
+ assertFalse(Email.isValidEmail("peterjack@u.nus.edu.")); // domain name ends with a period
+ assertFalse(Email.isValidEmail("peterjack@-u.nus.edu")); // domain name starts with a hyphen
+ assertFalse(Email.isValidEmail("peterjack@u.nus.edu-")); // domain name ends with a hyphen
+ assertFalse(Email.isValidEmail("peterjack@u.nus.e")); // top level domain has less than two chars
+ assertFalse(Email.isValidEmail("peterjack@email.com")); // Unaccepted domain name
+ assertFalse(Email.isValidEmail("1234567890123456789012345678901234567890"
+ + "1234567890123456789012345@gmail.com")); // 65 character long local name (too long)
+
+ // valid email
+ assertTrue(Email.isValidEmail("PeterJack_1190@u.nus.edu")); // underscore in local part
+ assertTrue(Email.isValidEmail("PeterJack.1190@u.nus.edu")); // period in local part
+ assertTrue(Email.isValidEmail("PeterJack+1190@u.nus.edu")); // '+' symbol in local part
+ assertTrue(Email.isValidEmail("PeterJack-1190@u.nus.edu")); // hyphen in local part
+ assertTrue(Email.isValidEmail("1234567890123456789012345678901234567890"
+ + "123456789012345678901234@gmail.com")); // 64 character long local name
+
+ // accepted domains
+ assertTrue(Email.isValidEmail("peterjack@u.nus.edu"));
+ assertTrue(Email.isValidEmail("peterjack@nus.edu.sg"));
+ assertTrue(Email.isValidEmail("peterjack@gmail.com"));
+ assertTrue(Email.isValidEmail("peterjack@yahoo.com"));
+ assertTrue(Email.isValidEmail("peterjack@outlook.com"));
+ assertTrue(Email.isValidEmail("peterjack@hotmail.com"));
+ }
+}
diff --git a/src/test/java/seedu/address/model/student/GitHubTest.java b/src/test/java/seedu/address/model/student/GitHubTest.java
new file mode 100644
index 00000000000..e574b4ace7d
--- /dev/null
+++ b/src/test/java/seedu/address/model/student/GitHubTest.java
@@ -0,0 +1,36 @@
+package seedu.address.model.student;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class GitHubTest {
+
+ @Test
+ public void constructor_invalidGitHub_throwsIllegalArgumentException() {
+ String invalidGitHub = "";
+ assertThrows(IllegalArgumentException.class, () -> new GitHub(invalidGitHub));
+ }
+
+ @Test
+ public void isValidGitHub() {
+ // null address
+ assertThrows(NullPointerException.class, () -> GitHub.isValidGitHub(null));
+
+ // invalid addresses
+ assertFalse(GitHub.isValidGitHub("")); // empty string
+ assertFalse(GitHub.isValidGitHub(" ")); // spaces only
+ assertFalse(GitHub.isValidGitHub("a")); // only 1 character
+ assertFalse(GitHub.isValidGitHub("-alexa")); //start with hyphen
+ assertFalse(GitHub.isValidGitHub("alexa-")); //end with hyphen
+ assertFalse(GitHub.isValidGitHub("alexa!")); //non-alphanumeric character
+ assertFalse(GitHub.isValidGitHub("alexandra-rock-is-the-name-i-like-drinks")); // more than 39 character gitHub
+
+ // valid addresses
+ assertTrue(GitHub.isValidGitHub("alex-o"));
+ assertTrue(GitHub.isValidGitHub("as")); // two character
+ assertTrue(GitHub.isValidGitHub("alexandra-rock-is-the-name-i-like-drink")); // 39 character gitHub
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/student/NameContainsKeywordsPredicateTest.java
similarity index 66%
rename from src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
rename to src/test/java/seedu/address/model/student/NameContainsKeywordsPredicateTest.java
index f136664e017..bfefd06e742 100644
--- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
+++ b/src/test/java/seedu/address/model/student/NameContainsKeywordsPredicateTest.java
@@ -1,7 +1,8 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
import java.util.Arrays;
import java.util.Collections;
@@ -9,7 +10,7 @@
import org.junit.jupiter.api.Test;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.testutil.StudentBuilder;
public class NameContainsKeywordsPredicateTest {
@@ -34,7 +35,7 @@ public void equals() {
// null -> returns false
assertFalse(firstPredicate.equals(null));
- // different person -> returns false
+ // different student -> returns false
assertFalse(firstPredicate.equals(secondPredicate));
}
@@ -42,34 +43,40 @@ public void equals() {
public void test_nameContainsKeywords_returnsTrue() {
// One keyword
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Alice"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new StudentBuilder().withName("Alice Bob").build()));
// Multiple keywords
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new StudentBuilder().withName("Alice Bob").build()));
- // Only one matching keyword
- predicate = new NameContainsKeywordsPredicate(Arrays.asList("Bob", "Carol"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Carol").build()));
+ // Matching both keywords
+ predicate = new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Carol"));
+ assertTrue(predicate.test(new StudentBuilder().withName("Alice Carol").build()));
// Mixed-case keywords
predicate = new NameContainsKeywordsPredicate(Arrays.asList("aLIce", "bOB"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new StudentBuilder().withName("Alice Bob").build()));
}
@Test
public void test_nameDoesNotContainKeywords_returnsFalse() {
- // Zero keywords
- NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.emptyList());
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").build()));
+ NameContainsKeywordsPredicate predicate;
// Non-matching keyword
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Carol"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertFalse(predicate.test(new StudentBuilder().withName("Alice Bob").build()));
// Keywords match phone, email and address, but does not match name
- predicate = new NameContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
- .withEmail("alice@email.com").withAddress("Main Street").build()));
+ predicate = new NameContainsKeywordsPredicate(Arrays.asList("@alice14", "alice@gmail.com", "alice10"));
+ assertFalse(predicate.test(new StudentBuilder().withName("Alice").withTelegram("@alice14")
+ .withEmail("alice@gmail.com").withGitHub("alice10").build()));
+ }
+
+ @Test
+ public void test_zeroKeywords_throwsIllegalArgumentException() {
+ // Zero keywords
+ NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.emptyList());
+ assertThrows(IllegalArgumentException.class, "Keys cannot be empty", (
+ ) -> predicate.test(new StudentBuilder().withName("Alice").build()));
}
}
diff --git a/src/test/java/seedu/address/model/student/NameTest.java b/src/test/java/seedu/address/model/student/NameTest.java
new file mode 100644
index 00000000000..77b6541adba
--- /dev/null
+++ b/src/test/java/seedu/address/model/student/NameTest.java
@@ -0,0 +1,57 @@
+package seedu.address.model.student;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class NameTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Name(null));
+ }
+
+ @Test
+ public void constructor_invalidName_throwsIllegalArgumentException() {
+ String invalidName = "";
+ assertThrows(IllegalArgumentException.class, () -> new Name(invalidName));
+ }
+
+ @Test
+ public void isValidName() {
+ // null name
+ assertThrows(NullPointerException.class, () -> Name.isValidName(null));
+
+ // invalid name
+ assertFalse(Name.isValidName("")); // empty string
+ assertFalse(Name.isValidName(" ")); // spaces only
+ assertFalse(Name.isValidName("12345")); // numbers only
+ assertFalse(Name.isValidName("peter the 2nd")); // alphanumeric characters
+ assertFalse(Name.isValidName("^")); // only non-alphabetical characters
+ assertFalse(Name.isValidName("peter*")); // contains unaccepted characters
+ assertFalse(Name.isValidName("peter-")); // hyphen at the end
+ assertFalse(Name.isValidName("-peter")); // hyphen at the start
+ assertFalse(Name.isValidName("peter\'")); // apostrophe at the end
+ assertFalse(Name.isValidName("\'peter")); // apostrophe at the start
+ assertFalse(Name.isValidName("peter--jack")); // consecutive hyphens
+ assertFalse(Name.isValidName("peter jack")); // consecutive spaces
+ assertFalse(Name.isValidName("peter\'\'jack")); // consecutive apostrophes
+ assertFalse(Name.isValidName("Peter Jack 2jjj")); // Has a number but does not end with it
+ assertFalse(Name.isValidName("Peter Jack 2 jjj")); // Has a number but does not end with it
+ assertFalse(Name.isValidName("WatermelonWatermelonWatermelonWatermelonWatermelon"
+ + "WatermelonWatermelonWatermelonWatermelonWatermelons")); // 101 characters
+
+ // valid name
+ assertTrue(Name.isValidName("peter jack")); // alphabets only
+ assertTrue(Name.isValidName("Capital Tan")); // with capital letters
+ assertTrue(Name.isValidName("Max-Ernest")); // name with hyphen
+ assertTrue(Name.isValidName("Jeanne d'Arc")); // name with apostrophe
+ assertTrue(Name.isValidName("Johnson-Johnson d'Arby")); // name with a hyphen, space and apostrophe
+ assertTrue(Name.isValidName("Peter Jack 2")); // ends with a number
+ assertTrue(Name.isValidName("Peter Jack 000000000000000")); // ends with a number
+ assertTrue(Name.isValidName("WatermelonWatermelonWatermelonWatermelonWatermelon"
+ + "WatermelonWatermelonWatermelonWatermelonWatermelon")); // exactly 100 characters
+ }
+}
diff --git a/src/test/java/seedu/address/model/student/StudentTest.java b/src/test/java/seedu/address/model/student/StudentTest.java
new file mode 100644
index 00000000000..d8b263a29f4
--- /dev/null
+++ b/src/test/java/seedu/address/model/student/StudentTest.java
@@ -0,0 +1,109 @@
+package seedu.address.model.student;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalStudents.ALICE;
+import static seedu.address.testutil.TypicalStudents.BOB;
+
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.testutil.StudentBuilder;
+
+public class StudentTest {
+
+ @Test
+ public void asObservableList_modifyList_throwsUnsupportedOperationException() {
+ Student student = new StudentBuilder().build();
+ assertThrows(UnsupportedOperationException.class, () -> student.getTutorialGroups().remove(0));
+ }
+
+ @Test
+ public void isSameStudent() {
+ // same object -> returns true
+ assertTrue(ALICE.isSameStudent(ALICE));
+
+ // null -> returns false
+ assertFalse(ALICE.isSameStudent(null));
+
+ // same name, all other attributes different -> returns true
+ Student editedAlice = new StudentBuilder(ALICE).withTelegram(VALID_TELEGRAM_BOB).withEmail(VALID_EMAIL_BOB)
+ .withGitHub(VALID_GITHUB_BOB).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ assertTrue(ALICE.isSameStudent(editedAlice));
+
+ // different name, all other attributes same -> returns false
+ editedAlice = new StudentBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ assertFalse(ALICE.isSameStudent(editedAlice));
+
+ // name differs in case, all other attributes same -> returns false
+ Student editedBob = new StudentBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build();
+ assertFalse(BOB.isSameStudent(editedBob));
+
+ // name has trailing spaces, all other attributes same -> returns true
+ String nameWithTrailingSpaces = VALID_NAME_BOB + " ";
+ editedBob = new StudentBuilder(BOB).withName(nameWithTrailingSpaces).build();
+ assertTrue(BOB.isSameStudent(editedBob));
+ }
+
+ @Test
+ public void equals() {
+ // same values -> returns true
+ Student aliceCopy = new StudentBuilder(ALICE).build();
+ assertTrue(ALICE.equals(aliceCopy));
+
+ // same object -> returns true
+ assertTrue(ALICE.equals(ALICE));
+
+ // null -> returns false
+ assertFalse(ALICE.equals(null));
+
+ // different type -> returns false
+ assertFalse(ALICE.equals(5));
+
+ // different student -> returns false
+ assertFalse(ALICE.equals(BOB));
+
+ // different name -> returns false
+ Student editedAlice = new StudentBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different telegram -> returns false
+ editedAlice = new StudentBuilder(ALICE).withTelegram(VALID_TELEGRAM_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different email -> returns false
+ editedAlice = new StudentBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different gitHub -> returns false
+ editedAlice = new StudentBuilder(ALICE).withGitHub(VALID_GITHUB_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different tutorial groups -> returns false
+ editedAlice = new StudentBuilder(ALICE).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ assertFalse(ALICE.equals(editedAlice));
+ }
+
+ @Test
+ public void tutorialGroupExists() {
+ Student aliceCopy = new StudentBuilder(ALICE).build();
+
+ // same tutorial group -> returns true
+ assertTrue(ALICE.tutorialGroupExists(aliceCopy.getTutorialGroups()));
+
+ // different tutorial group -> returns false
+ Student editedAlice = new StudentBuilder(ALICE).withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ assertFalse(editedAlice.tutorialGroupExists(aliceCopy.getTutorialGroups()));
+
+ // null -> returns false
+ assertFalse(ALICE.tutorialGroupExists((Set) null));
+ }
+}
diff --git a/src/test/java/seedu/address/model/student/TelegramTest.java b/src/test/java/seedu/address/model/student/TelegramTest.java
new file mode 100644
index 00000000000..d346795904f
--- /dev/null
+++ b/src/test/java/seedu/address/model/student/TelegramTest.java
@@ -0,0 +1,33 @@
+package seedu.address.model.student;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class TelegramTest {
+
+ @Test
+ public void constructor_invalidTelegram_throwsIllegalArgumentException() {
+ String invalidTelegram = "";
+ assertThrows(IllegalArgumentException.class, () -> new Telegram(invalidTelegram));
+ }
+
+ @Test
+ public void isValidTelegram() {
+ // null telegram
+ assertThrows(NullPointerException.class, () -> Telegram.isValidTelegram(null));
+
+ // invalid telegrams
+ assertFalse(Telegram.isValidTelegram("")); // empty string
+ assertFalse(Telegram.isValidTelegram(" ")); // spaces only
+ assertFalse(Telegram.isValidTelegram("tele")); // less than 5 characters
+ assertFalse(Telegram.isValidTelegram("@amy bee10")); // spaces within telegram
+
+ // valid telegrams
+ assertTrue(Telegram.isValidTelegram("@amybe")); // exactly 5 characters
+ assertTrue(Telegram.isValidTelegram("johnsmith14")); // without '@' symbol
+ assertTrue(Telegram.isValidTelegram("@NathanBalakrishnanTheMan1")); // long telegram
+ }
+}
diff --git a/src/test/java/seedu/address/model/student/UniqueStudentListTest.java b/src/test/java/seedu/address/model/student/UniqueStudentListTest.java
new file mode 100644
index 00000000000..48abfdc9284
--- /dev/null
+++ b/src/test/java/seedu/address/model/student/UniqueStudentListTest.java
@@ -0,0 +1,170 @@
+package seedu.address.model.student;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalStudents.ALICE;
+import static seedu.address.testutil.TypicalStudents.BOB;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.student.exceptions.DuplicateStudentException;
+import seedu.address.model.student.exceptions.StudentNotFoundException;
+import seedu.address.testutil.StudentBuilder;
+
+public class UniqueStudentListTest {
+
+ private final UniqueStudentList uniqueStudentList = new UniqueStudentList();
+
+ @Test
+ public void contains_nullStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.contains(null));
+ }
+
+ @Test
+ public void contains_studentNotInList_returnsFalse() {
+ assertFalse(uniqueStudentList.contains(ALICE));
+ }
+
+ @Test
+ public void contains_studentInList_returnsTrue() {
+ uniqueStudentList.add(ALICE);
+ assertTrue(uniqueStudentList.contains(ALICE));
+ }
+
+ @Test
+ public void contains_studentWithSameIdentityFieldsInList_returnsTrue() {
+ uniqueStudentList.add(ALICE);
+ Student editedAlice = new StudentBuilder(ALICE).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ assertTrue(uniqueStudentList.contains(editedAlice));
+ }
+
+ @Test
+ public void add_nullStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.add(null));
+ }
+
+ @Test
+ public void add_duplicateStudent_throwsDuplicateStudentException() {
+ uniqueStudentList.add(ALICE);
+ assertThrows(DuplicateStudentException.class, () -> uniqueStudentList.add(ALICE));
+ }
+
+ @Test
+ public void setStudent_nullTargetStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.setStudent(null, ALICE));
+ }
+
+ @Test
+ public void setStudent_nullEditedStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.setStudent(ALICE, null));
+ }
+
+ @Test
+ public void setStudent_targetStudentNotInList_throwsStudentNotFoundException() {
+ assertThrows(StudentNotFoundException.class, () -> uniqueStudentList.setStudent(ALICE, ALICE));
+ }
+
+ @Test
+ public void setStudent_editedStudentIsSameStudent_success() {
+ uniqueStudentList.add(ALICE);
+ uniqueStudentList.setStudent(ALICE, ALICE);
+ UniqueStudentList expectedUniqueStudentList = new UniqueStudentList();
+ expectedUniqueStudentList.add(ALICE);
+ assertEquals(expectedUniqueStudentList, uniqueStudentList);
+ }
+
+ @Test
+ public void setStudent_editedStudentHasSameIdentity_success() {
+ uniqueStudentList.add(ALICE);
+ Student editedAlice = new StudentBuilder(ALICE).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3).build();
+ uniqueStudentList.setStudent(ALICE, editedAlice);
+ UniqueStudentList expectedUniqueStudentList = new UniqueStudentList();
+ expectedUniqueStudentList.add(editedAlice);
+ assertEquals(expectedUniqueStudentList, uniqueStudentList);
+ }
+
+ @Test
+ public void setStudent_editedStudentHasDifferentIdentity_success() {
+ uniqueStudentList.add(ALICE);
+ uniqueStudentList.setStudent(ALICE, BOB);
+ UniqueStudentList expectedUniqueStudentList = new UniqueStudentList();
+ expectedUniqueStudentList.add(BOB);
+ assertEquals(expectedUniqueStudentList, uniqueStudentList);
+ }
+
+ @Test
+ public void setStudent_editedStudentHasNonUniqueIdentity_throwsDuplicateStudentException() {
+ uniqueStudentList.add(ALICE);
+ uniqueStudentList.add(BOB);
+ assertThrows(DuplicateStudentException.class, () -> uniqueStudentList.setStudent(ALICE, BOB));
+ }
+
+ @Test
+ public void remove_nullStudent_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.remove(null));
+ }
+
+ @Test
+ public void remove_studentDoesNotExist_throwsStudentNotFoundException() {
+ assertThrows(StudentNotFoundException.class, () -> uniqueStudentList.remove(ALICE));
+ }
+
+ @Test
+ public void remove_existingStudent_removesStudent() {
+ uniqueStudentList.add(ALICE);
+ uniqueStudentList.remove(ALICE);
+ UniqueStudentList expectedUniqueStudentList = new UniqueStudentList();
+ assertEquals(expectedUniqueStudentList, uniqueStudentList);
+ }
+
+ @Test
+ public void setStudents_nullUniqueStudentList_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.setStudents((UniqueStudentList) null));
+ }
+
+ @Test
+ public void setStudents_uniqueStudentList_replacesOwnListWithProvidedUniqueStudentList() {
+ uniqueStudentList.add(ALICE);
+ UniqueStudentList expectedUniqueStudentList = new UniqueStudentList();
+ expectedUniqueStudentList.add(BOB);
+ uniqueStudentList.setStudents(expectedUniqueStudentList);
+ assertEquals(expectedUniqueStudentList, uniqueStudentList);
+ }
+
+ @Test
+ public void setStudents_nullList_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniqueStudentList.setStudents((List) null));
+ }
+
+ @Test
+ public void setStudents_list_replacesOwnListWithProvidedList() {
+ uniqueStudentList.add(ALICE);
+ List studentList = Collections.singletonList(BOB);
+ uniqueStudentList.setStudents(studentList);
+ UniqueStudentList expectedUniqueStudentList = new UniqueStudentList();
+ expectedUniqueStudentList.add(BOB);
+ assertEquals(expectedUniqueStudentList, uniqueStudentList);
+ }
+
+ @Test
+ public void setStudents_listWithDuplicateStudents_throwsDuplicateStudentException() {
+ List listWithDuplicateStudents = Arrays.asList(ALICE, ALICE);
+ assertThrows(DuplicateStudentException.class, () -> uniqueStudentList.setStudents(listWithDuplicateStudents));
+ }
+
+ @Test
+ public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, ()
+ -> uniqueStudentList.asUnmodifiableObservableList().remove(0));
+ }
+}
diff --git a/src/test/java/seedu/address/model/tag/TagTest.java b/src/test/java/seedu/address/model/tag/TagTest.java
deleted file mode 100644
index 64d07d79ee2..00000000000
--- a/src/test/java/seedu/address/model/tag/TagTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package seedu.address.model.tag;
-
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class TagTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Tag(null));
- }
-
- @Test
- public void constructor_invalidTagName_throwsIllegalArgumentException() {
- String invalidTagName = "";
- assertThrows(IllegalArgumentException.class, () -> new Tag(invalidTagName));
- }
-
- @Test
- public void isValidTagName() {
- // null tag name
- assertThrows(NullPointerException.class, () -> Tag.isValidTagName(null));
- }
-
-}
diff --git a/src/test/java/seedu/address/model/tutorialgroup/TutorialGroupKeywordsPredicateTest.java b/src/test/java/seedu/address/model/tutorialgroup/TutorialGroupKeywordsPredicateTest.java
new file mode 100644
index 00000000000..2073652d399
--- /dev/null
+++ b/src/test/java/seedu/address/model/tutorialgroup/TutorialGroupKeywordsPredicateTest.java
@@ -0,0 +1,67 @@
+package seedu.address.model.tutorialgroup;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.StudentBuilder;
+
+public class TutorialGroupKeywordsPredicateTest {
+ @Test
+ public void equals() {
+ String firstPredicateKeyword = "CS2101 G08";
+ String secondPredicateKeyword = "CS2103 W15-3";
+
+ TutorialGroupKeywordsPredicate firstPredicate = new TutorialGroupKeywordsPredicate(firstPredicateKeyword);
+ TutorialGroupKeywordsPredicate secondPredicate = new TutorialGroupKeywordsPredicate(secondPredicateKeyword);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ TutorialGroupKeywordsPredicate firstPredicateCopy = new TutorialGroupKeywordsPredicate(firstPredicateKeyword);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different student -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_tutorialGroupFound_returnsTrue() {
+ // Matching keyword
+ TutorialGroupKeywordsPredicate predicate = new TutorialGroupKeywordsPredicate("CS2101 G08");
+ assertTrue(predicate.test(new StudentBuilder().withTutorialGroup("CS2103T W15-3", "CS2101 G08").build()));
+
+ // Mixed-case keyword
+ predicate = new TutorialGroupKeywordsPredicate("cS2101 g08");
+ assertTrue(predicate.test(new StudentBuilder().withTutorialGroup("CS2101 G08").build()));
+ }
+
+ @Test
+ public void test_nameDoesNotContainKeywords_returnsFalse() {
+ // Non-matching keywords
+ TutorialGroupKeywordsPredicate predicate = new TutorialGroupKeywordsPredicate("MA1501 T03");
+ assertFalse(predicate.test(new StudentBuilder().withTutorialGroup("CS2103T W15-3", "CS2101 G08").build()));
+
+ // Keywords match email, github, and telegram, but does not match tutorial group
+ predicate = new TutorialGroupKeywordsPredicate("MA1501_T03");
+ assertFalse(predicate.test(new StudentBuilder().withName("Alice").withTelegram("MA1501_T03")
+ .withEmail("MA1501_T03@gmail.com").withGitHub("MA1501-T03")
+ .withTutorialGroup("CS2101 G08").build()));
+
+ // Too many keywords
+ predicate = new TutorialGroupKeywordsPredicate("CS2103T W15-3" + "CS2101 G08");
+ assertFalse(predicate.test(new StudentBuilder().withTutorialGroup("CS2103T W15-3", "CS2101 G08").build()));
+
+ // Zero keywords
+ predicate = new TutorialGroupKeywordsPredicate(" ");
+ assertFalse(predicate.test(new StudentBuilder().withTutorialGroup("CS2103T W15-3", "CS2101 G08").build()));
+ }
+}
diff --git a/src/test/java/seedu/address/model/tutorialgroup/TutorialGroupTest.java b/src/test/java/seedu/address/model/tutorialgroup/TutorialGroupTest.java
new file mode 100644
index 00000000000..f22590da25a
--- /dev/null
+++ b/src/test/java/seedu/address/model/tutorialgroup/TutorialGroupTest.java
@@ -0,0 +1,54 @@
+package seedu.address.model.tutorialgroup;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class TutorialGroupTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new TutorialGroup(null));
+ }
+
+ @Test
+ public void constructor_invalidTutorialGroupName_throwsIllegalArgumentException() {
+ String invalidTutorialGroupName = "";
+ assertThrows(IllegalArgumentException.class, () -> new TutorialGroup(invalidTutorialGroupName));
+ }
+
+ @Test
+ public void isValidTutorialGroupName() {
+ assertThrows(NullPointerException.class, () ->
+ TutorialGroup.isValidTutorialGroupName(null)); // null tutorial group name
+
+ assertFalse(TutorialGroup.isValidTutorialGroupName("")); // empty tutorial group
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2040S")); // without tutorial name
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS50 T01")); // module code only 2 digits
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2040S T05")); // 2 spaces
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2040S T05-")); // end with hyphen
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2040S -T05")); // tutorial name start with hyphen
+ assertFalse(TutorialGroup.isValidTutorialGroupName(
+ "CS2040S T05!")); // tutorial name has special character
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2040S* T05")); // module has special character
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2103T "
+ + "WT1234567890123456789012345678901234567890123456789"
+ + "012345678901234567890123456789012345678901")); // tutorial group with 101 characters
+ assertFalse(TutorialGroup.isValidTutorialGroupName("CS2103T "
+ + "W00000000000000000000000000000000000000000000"
+ + "0000000000000")); // long tutorial group with only 0 digits for tutorial name.
+
+ assertTrue(TutorialGroup.isValidTutorialGroupName("CS2103T "
+ + "WT1234567890123456789012345678901234567890123456789"
+ + "01234567890123456789012345678901234567890")); // tutorial group with 100 characters
+ assertTrue(TutorialGroup.isValidTutorialGroupName("CS2103T "
+ + "WT1234567890123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789")); // tutorial group with 99 characters
+ assertTrue(TutorialGroup.isValidTutorialGroupName("CS2106 T05")); // valid tutorial group
+ assertTrue(TutorialGroup.isValidTutorialGroupName("CS2103T W15-3")); // hyphen
+ assertTrue(TutorialGroup.isValidTutorialGroupName(
+ "CS2106 5")); // only has tutorial name with one non-zero digit
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
deleted file mode 100644
index 83b11331cdb..00000000000
--- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package seedu.address.storage;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.BENSON;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-
-public class JsonAdaptedPersonTest {
- private static final String INVALID_NAME = "R@chel";
- private static final String INVALID_PHONE = "+651234";
- private static final String INVALID_ADDRESS = " ";
- private static final String INVALID_EMAIL = "example.com";
- private static final String INVALID_TAG = "#friend";
-
- private static final String VALID_NAME = BENSON.getName().toString();
- private static final String VALID_PHONE = BENSON.getPhone().toString();
- private static final String VALID_EMAIL = BENSON.getEmail().toString();
- private static final String VALID_ADDRESS = BENSON.getAddress().toString();
- private static final List VALID_TAGS = BENSON.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList());
-
- @Test
- public void toModelType_validPersonDetails_returnsPerson() throws Exception {
- JsonAdaptedPerson person = new JsonAdaptedPerson(BENSON);
- assertEquals(BENSON, person.toModelType());
- }
-
- @Test
- public void toModelType_invalidName_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = Name.MESSAGE_CONSTRAINTS;
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_nullName_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_invalidPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = Phone.MESSAGE_CONSTRAINTS;
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_nullPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName());
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_invalidEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = Email.MESSAGE_CONSTRAINTS;
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_nullEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS);
- String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_invalidAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS);
- String expectedMessage = Address.MESSAGE_CONSTRAINTS;
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_nullAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS);
- String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
- assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
- }
-
- @Test
- public void toModelType_invalidTags_throwsIllegalValueException() {
- List invalidTags = new ArrayList<>(VALID_TAGS);
- invalidTags.add(new JsonAdaptedTag(INVALID_TAG));
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags);
- assertThrows(IllegalValueException.class, person::toModelType);
- }
-
-}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedStudentTest.java b/src/test/java/seedu/address/storage/JsonAdaptedStudentTest.java
new file mode 100644
index 00000000000..90936e17d98
--- /dev/null
+++ b/src/test/java/seedu/address/storage/JsonAdaptedStudentTest.java
@@ -0,0 +1,123 @@
+package seedu.address.storage;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.storage.JsonAdaptedStudent.MISSING_FIELD_MESSAGE_FORMAT;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalStudents.BENSON;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Telegram;
+
+public class JsonAdaptedStudentTest {
+ private static final String INVALID_GITHUB = " ";
+ private static final String INVALID_NAME = "R@chel";
+ private static final String INVALID_TELEGRAM = "+651234";
+ private static final String INVALID_EMAIL = "u.nus.edu";
+ private static final String INVALID_TUTORIAL_GROUP = "#friend";
+
+ private static final String VALID_NAME = BENSON.getName().toString();
+ private static final String VALID_TELEGRAM = BENSON.getTelegram().toString();
+ private static final String VALID_EMAIL = BENSON.getEmail().toString();
+ private static final String VALID_GITHUB = BENSON.getGitHub().toString();
+ private static final List VALID_TUTORIAL_GROUP = BENSON.getTutorialGroups().stream()
+ .map(JsonAdaptedTutorialGroup::new)
+ .collect(Collectors.toList());
+
+ @Test
+ public void toModelType_validStudentDetails_returnsStudent() throws Exception {
+ JsonAdaptedStudent student = new JsonAdaptedStudent(BENSON);
+ assertEquals(BENSON, student.toModelType());
+ }
+
+ @Test
+ public void toModelType_invalidName_throwsIllegalValueException() {
+ JsonAdaptedStudent student =
+ new JsonAdaptedStudent(INVALID_NAME, VALID_TELEGRAM, VALID_EMAIL, VALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = Name.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullName_throwsIllegalValueException() {
+ JsonAdaptedStudent student = new JsonAdaptedStudent(null, VALID_TELEGRAM, VALID_EMAIL,
+ VALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidTelegram_throwsIllegalValueException() {
+ JsonAdaptedStudent student =
+ new JsonAdaptedStudent(VALID_NAME, INVALID_TELEGRAM, VALID_EMAIL,
+ VALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = Telegram.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullTelegram_throwsIllegalValueException() {
+ JsonAdaptedStudent student = new JsonAdaptedStudent(VALID_NAME, null, VALID_EMAIL,
+ VALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Telegram.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidEmail_throwsIllegalValueException() {
+ JsonAdaptedStudent student =
+ new JsonAdaptedStudent(VALID_NAME, VALID_TELEGRAM, INVALID_EMAIL,
+ VALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = Email.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullEmail_throwsIllegalValueException() {
+ JsonAdaptedStudent student = new JsonAdaptedStudent(VALID_NAME, VALID_TELEGRAM, null,
+ VALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidGitHub_throwsIllegalValueException() {
+ JsonAdaptedStudent student =
+ new JsonAdaptedStudent(VALID_NAME, VALID_TELEGRAM, VALID_EMAIL, INVALID_GITHUB, VALID_TUTORIAL_GROUP);
+ String expectedMessage = GitHub.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullGitHub_throwsIllegalValueException() {
+ JsonAdaptedStudent student = new JsonAdaptedStudent(VALID_NAME, VALID_TELEGRAM, VALID_EMAIL,
+ null, VALID_TUTORIAL_GROUP);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, GitHub.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidTutorialGroup_throwsIllegalValueException() {
+ List invalidTags = new ArrayList<>(VALID_TUTORIAL_GROUP);
+ invalidTags.add(new JsonAdaptedTutorialGroup(INVALID_TUTORIAL_GROUP));
+ JsonAdaptedStudent student =
+ new JsonAdaptedStudent(VALID_NAME, VALID_TELEGRAM, VALID_EMAIL, VALID_GITHUB, invalidTags);
+ assertThrows(IllegalValueException.class, student::toModelType);
+ }
+
+ @Test
+ public void toModelType_zeroTutorialGroup_throwsIllegalValueException() {
+ List emptyTutorialGroups = new ArrayList<>();
+ JsonAdaptedStudent student =
+ new JsonAdaptedStudent(VALID_NAME, VALID_TELEGRAM, VALID_EMAIL, VALID_GITHUB, emptyTutorialGroups);
+ assertThrows(IllegalValueException.class, student::toModelType);
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
index ac3c3af9566..0e1b1f5647e 100644
--- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
+++ b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
@@ -3,10 +3,10 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.HOON;
-import static seedu.address.testutil.TypicalPersons.IDA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalStudents.ALICE;
+import static seedu.address.testutil.TypicalStudents.HOON;
+import static seedu.address.testutil.TypicalStudents.IDA;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import java.io.IOException;
import java.nio.file.Path;
@@ -51,13 +51,13 @@ public void read_notJsonFormat_exceptionThrown() {
}
@Test
- public void readAddressBook_invalidPersonAddressBook_throwDataConversionException() {
- assertThrows(DataConversionException.class, () -> readAddressBook("invalidPersonAddressBook.json"));
+ public void readAddressBook_invalidStudentAddressBook_throwDataConversionException() {
+ assertThrows(DataConversionException.class, () -> readAddressBook("invalidStudentAddressBook.json"));
}
@Test
- public void readAddressBook_invalidAndValidPersonAddressBook_throwDataConversionException() {
- assertThrows(DataConversionException.class, () -> readAddressBook("invalidAndValidPersonAddressBook.json"));
+ public void readAddressBook_invalidAndValidStudentAddressBook_throwDataConversionException() {
+ assertThrows(DataConversionException.class, () -> readAddressBook("invalidAndValidStudentAddressBook.json"));
}
@Test
@@ -72,14 +72,14 @@ public void readAndSaveAddressBook_allInOrder_success() throws Exception {
assertEquals(original, new AddressBook(readBack));
// Modify data, overwrite exiting file, and read back
- original.addPerson(HOON);
- original.removePerson(ALICE);
+ original.addStudent(HOON);
+ original.removeStudent(ALICE);
jsonAddressBookStorage.saveAddressBook(original, filePath);
readBack = jsonAddressBookStorage.readAddressBook(filePath).get();
assertEquals(original, new AddressBook(readBack));
// Save and read without specifying file path
- original.addPerson(IDA);
+ original.addStudent(IDA);
jsonAddressBookStorage.saveAddressBook(original); // file path not specified
readBack = jsonAddressBookStorage.readAddressBook().get(); // file path not specified
assertEquals(original, new AddressBook(readBack));
diff --git a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
index 188c9058d20..642d7cd7f9b 100644
--- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
+++ b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
@@ -11,36 +11,36 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.commons.util.JsonUtil;
import seedu.address.model.AddressBook;
-import seedu.address.testutil.TypicalPersons;
+import seedu.address.testutil.TypicalStudents;
public class JsonSerializableAddressBookTest {
private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableAddressBookTest");
- private static final Path TYPICAL_PERSONS_FILE = TEST_DATA_FOLDER.resolve("typicalPersonsAddressBook.json");
- private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json");
- private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json");
+ private static final Path TYPICAL_STUDENTS_FILE = TEST_DATA_FOLDER.resolve("typicalStudentsAddressBook.json");
+ private static final Path INVALID_STUDENT_FILE = TEST_DATA_FOLDER.resolve("invalidStudentAddressBook.json");
+ private static final Path DUPLICATE_STUDENT_FILE = TEST_DATA_FOLDER.resolve("duplicateStudentAddressBook.json");
@Test
- public void toModelType_typicalPersonsFile_success() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE,
+ public void toModelType_typicalStudentsFile_success() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_STUDENTS_FILE,
JsonSerializableAddressBook.class).get();
AddressBook addressBookFromFile = dataFromFile.toModelType();
- AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook();
- assertEquals(addressBookFromFile, typicalPersonsAddressBook);
+ AddressBook typicalStudentsAddressBook = TypicalStudents.getTypicalAddressBook();
+ assertEquals(addressBookFromFile, typicalStudentsAddressBook);
}
@Test
- public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE,
+ public void toModelType_invalidStudentFile_throwsIllegalValueException() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_STUDENT_FILE,
JsonSerializableAddressBook.class).get();
assertThrows(IllegalValueException.class, dataFromFile::toModelType);
}
@Test
- public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE,
+ public void toModelType_duplicateStudents_throwsIllegalValueException() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_STUDENT_FILE,
JsonSerializableAddressBook.class).get();
- assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON,
+ assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_STUDENT,
dataFromFile::toModelType);
}
diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/address/storage/StorageManagerTest.java
index 99a16548970..ad0db49f6d9 100644
--- a/src/test/java/seedu/address/storage/StorageManagerTest.java
+++ b/src/test/java/seedu/address/storage/StorageManagerTest.java
@@ -2,7 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;
import java.nio.file.Path;
diff --git a/src/test/java/seedu/address/testutil/AddTutorialGroupDescriptorBuilder.java b/src/test/java/seedu/address/testutil/AddTutorialGroupDescriptorBuilder.java
new file mode 100644
index 00000000000..1cd9420889f
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/AddTutorialGroupDescriptorBuilder.java
@@ -0,0 +1,76 @@
+package seedu.address.testutil;
+
+import static seedu.address.testutil.TypicalStudents.AMY;
+import static seedu.address.testutil.TypicalStudents.BOB;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddTutorialGroupCommand;
+import seedu.address.logic.commands.AddTutorialGroupCommand.AddTutorialGroupDescriptor;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+public class AddTutorialGroupDescriptorBuilder {
+
+ public static final AddTutorialGroupDescriptor VALID_TUTORIAL_GROUP_DESCRIPTOR_AMY =
+ new AddTutorialGroupDescriptorBuilder(AMY).build();
+ public static final AddTutorialGroupDescriptor VALID_TUTORIAL_GROUP_DESCRIPTOR_BOB =
+ new AddTutorialGroupDescriptorBuilder(BOB).build();
+ private AddTutorialGroupDescriptor descriptor;
+
+ public AddTutorialGroupDescriptorBuilder() {
+ descriptor = new AddTutorialGroupCommand.AddTutorialGroupDescriptor();
+ }
+
+ /**
+ * Builds a AddTutorialGroupDescriptorBuilder based
+ * an existing AddTutorialGroupDescriptor
+ *
+ * @param descriptor to copy
+ */
+ public AddTutorialGroupDescriptorBuilder(AddTutorialGroupCommand.AddTutorialGroupDescriptor descriptor) {
+ this.descriptor = new AddTutorialGroupCommand.AddTutorialGroupDescriptor(descriptor);
+ }
+
+ /**
+ * Builds a AddTutorialGroupDescriptorBuilder based
+ * on the tutorial group input
+ *
+ * @param tg tutorial group(s) to be added
+ */
+ public AddTutorialGroupDescriptorBuilder(Set tg) {
+ this.descriptor = new AddTutorialGroupCommand.AddTutorialGroupDescriptor();
+ descriptor.setTutorialGroups(tg);
+ }
+
+ /**
+ * Builds a AddTutorialGroupDescriptorBuilder based
+ * on an existing Student
+ *
+ * @param student to copy
+ */
+ public AddTutorialGroupDescriptorBuilder(Student student) {
+ descriptor = new AddTutorialGroupCommand.AddTutorialGroupDescriptor();
+ descriptor.setTutorialGroups(student.getTutorialGroups());
+ }
+
+ /**
+ * Parses the {@code tutorialGroups} into a {@code Set} and set it to the
+ * {@code AddTutorialGroupDescriptor} that we are building.
+ */
+ public AddTutorialGroupDescriptorBuilder withTutorialGroup(String... tutorialGroups) {
+ Set tutorialGroupSet = Stream.of(tutorialGroups).map(TutorialGroup::new)
+ .collect(Collectors.toSet());
+ descriptor.setTutorialGroups(tutorialGroupSet);
+ return this;
+ }
+
+ /**
+ * @return the AddTutorialGroupDescriptor built
+ */
+ public AddTutorialGroupCommand.AddTutorialGroupDescriptor build() {
+ return descriptor;
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/AddressBookBuilder.java b/src/test/java/seedu/address/testutil/AddressBookBuilder.java
index d53799fd110..2005c4d3f42 100644
--- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java
+++ b/src/test/java/seedu/address/testutil/AddressBookBuilder.java
@@ -1,12 +1,12 @@
package seedu.address.testutil;
import seedu.address.model.AddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* A utility class to help with building Addressbook objects.
* Example usage:
- * {@code AddressBook ab = new AddressBookBuilder().withPerson("John", "Doe").build();}
+ * {@code AddressBook ab = new AddressBookBuilder().withStudent("John", "Doe").build();}
*/
public class AddressBookBuilder {
@@ -21,10 +21,10 @@ public AddressBookBuilder(AddressBook addressBook) {
}
/**
- * Adds a new {@code Person} to the {@code AddressBook} that we are building.
+ * Adds a new {@code Student} to the {@code AddressBook} that we are building.
*/
- public AddressBookBuilder withPerson(Person person) {
- addressBook.addPerson(person);
+ public AddressBookBuilder withStudent(Student student) {
+ addressBook.addStudent(student);
return this;
}
diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
deleted file mode 100644
index 4584bd5044e..00000000000
--- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package seedu.address.testutil;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * A utility class to help with building EditPersonDescriptor objects.
- */
-public class EditPersonDescriptorBuilder {
-
- private EditPersonDescriptor descriptor;
-
- public EditPersonDescriptorBuilder() {
- descriptor = new EditPersonDescriptor();
- }
-
- public EditPersonDescriptorBuilder(EditPersonDescriptor descriptor) {
- this.descriptor = new EditPersonDescriptor(descriptor);
- }
-
- /**
- * Returns an {@code EditPersonDescriptor} with fields containing {@code person}'s details
- */
- public EditPersonDescriptorBuilder(Person person) {
- descriptor = new EditPersonDescriptor();
- descriptor.setName(person.getName());
- descriptor.setPhone(person.getPhone());
- descriptor.setEmail(person.getEmail());
- descriptor.setAddress(person.getAddress());
- descriptor.setTags(person.getTags());
- }
-
- /**
- * Sets the {@code Name} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withName(String name) {
- descriptor.setName(new Name(name));
- return this;
- }
-
- /**
- * Sets the {@code Phone} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withPhone(String phone) {
- descriptor.setPhone(new Phone(phone));
- return this;
- }
-
- /**
- * Sets the {@code Email} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withEmail(String email) {
- descriptor.setEmail(new Email(email));
- return this;
- }
-
- /**
- * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withAddress(String address) {
- descriptor.setAddress(new Address(address));
- return this;
- }
-
- /**
- * Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor}
- * that we are building.
- */
- public EditPersonDescriptorBuilder withTags(String... tags) {
- Set tagSet = Stream.of(tags).map(Tag::new).collect(Collectors.toSet());
- descriptor.setTags(tagSet);
- return this;
- }
-
- public EditPersonDescriptor build() {
- return descriptor;
- }
-}
diff --git a/src/test/java/seedu/address/testutil/EditStudentDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditStudentDescriptorBuilder.java
new file mode 100644
index 00000000000..2546af9e76d
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/EditStudentDescriptorBuilder.java
@@ -0,0 +1,89 @@
+package seedu.address.testutil;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.EditCommand;
+import seedu.address.logic.commands.EditCommand.EditStudentDescriptor;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * A utility class to help with building EditStudentDescriptor objects.
+ */
+public class EditStudentDescriptorBuilder {
+
+ private EditCommand.EditStudentDescriptor descriptor;
+
+ public EditStudentDescriptorBuilder() {
+ descriptor = new EditStudentDescriptor();
+ }
+
+ public EditStudentDescriptorBuilder(EditCommand.EditStudentDescriptor descriptor) {
+ this.descriptor = new EditCommand.EditStudentDescriptor(descriptor);
+ }
+
+ /**
+ * Returns an {@code EditStudentDescriptor} with fields containing {@code student}'s details
+ */
+ public EditStudentDescriptorBuilder(Student student) {
+ descriptor = new EditCommand.EditStudentDescriptor();
+ descriptor.setName(student.getName());
+ descriptor.setTelegram(student.getTelegram());
+ descriptor.setEmail(student.getEmail());
+ descriptor.setGitHub(student.getGitHub());
+ descriptor.setTutorialGroups(student.getTutorialGroups());
+ }
+
+ /**
+ * Sets the {@code Name} of the {@code EditStudentDescriptor} that we are building.
+ */
+ public EditStudentDescriptorBuilder withName(String name) {
+ descriptor.setName(new Name(name));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Telegram} of the {@code EditStudentDescriptor} that we are building.
+ */
+ public EditStudentDescriptorBuilder withTelegram(String telegram) {
+ descriptor.setTelegram(new Telegram(telegram));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Email} of the {@code EditStudentDescriptor} that we are building.
+ */
+ public EditStudentDescriptorBuilder withEmail(String email) {
+ descriptor.setEmail(new Email(email));
+ return this;
+ }
+
+ /**
+ * Sets the {@code GitHub} of the {@code EditStudentDescriptor} that we are building.
+ */
+ public EditStudentDescriptorBuilder withGitHub(String gitHub) {
+ descriptor.setGitHub(new GitHub(gitHub));
+ return this;
+ }
+
+ /**
+ * Parses the {@code tutorialGroups} into a {@code Set} and set it to the
+ * {@code EditStudentDescriptor} that we are building.
+ */
+ public EditStudentDescriptorBuilder withTutorialGroup(String... tutorialGroups) {
+ Set tutorialGroupSet = Stream.of(tutorialGroups).map(TutorialGroup::new)
+ .collect(Collectors.toSet());
+ descriptor.setTutorialGroups(tutorialGroupSet);
+ return this;
+ }
+
+ public EditStudentDescriptor build() {
+ return descriptor;
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java
deleted file mode 100644
index 6be381d39ba..00000000000
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package seedu.address.testutil;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.model.util.SampleDataUtil;
-
-/**
- * A utility class to help with building Person objects.
- */
-public class PersonBuilder {
-
- public static final String DEFAULT_NAME = "Amy Bee";
- public static final String DEFAULT_PHONE = "85355255";
- public static final String DEFAULT_EMAIL = "amy@gmail.com";
- public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111";
-
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- /**
- * Creates a {@code PersonBuilder} with the default details.
- */
- public PersonBuilder() {
- name = new Name(DEFAULT_NAME);
- phone = new Phone(DEFAULT_PHONE);
- email = new Email(DEFAULT_EMAIL);
- address = new Address(DEFAULT_ADDRESS);
- tags = new HashSet<>();
- }
-
- /**
- * Initializes the PersonBuilder with the data of {@code personToCopy}.
- */
- public PersonBuilder(Person personToCopy) {
- name = personToCopy.getName();
- phone = personToCopy.getPhone();
- email = personToCopy.getEmail();
- address = personToCopy.getAddress();
- tags = new HashSet<>(personToCopy.getTags());
- }
-
- /**
- * Sets the {@code Name} of the {@code Person} that we are building.
- */
- public PersonBuilder withName(String name) {
- this.name = new Name(name);
- return this;
- }
-
- /**
- * Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building.
- */
- public PersonBuilder withTags(String ... tags) {
- this.tags = SampleDataUtil.getTagSet(tags);
- return this;
- }
-
- /**
- * Sets the {@code Address} of the {@code Person} that we are building.
- */
- public PersonBuilder withAddress(String address) {
- this.address = new Address(address);
- return this;
- }
-
- /**
- * Sets the {@code Phone} of the {@code Person} that we are building.
- */
- public PersonBuilder withPhone(String phone) {
- this.phone = new Phone(phone);
- return this;
- }
-
- /**
- * Sets the {@code Email} of the {@code Person} that we are building.
- */
- public PersonBuilder withEmail(String email) {
- this.email = new Email(email);
- return this;
- }
-
- public Person build() {
- return new Person(name, phone, email, address, tags);
- }
-
-}
diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java
deleted file mode 100644
index 90849945183..00000000000
--- a/src/test/java/seedu/address/testutil/PersonUtil.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package seedu.address.testutil;
-
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Person;
-import seedu.address.model.tag.Tag;
-
-/**
- * A utility class for Person.
- */
-public class PersonUtil {
-
- /**
- * Returns an add command string for adding the {@code person}.
- */
- public static String getAddCommand(Person person) {
- return AddCommand.COMMAND_WORD + " " + getPersonDetails(person);
- }
-
- /**
- * Returns the part of command string for the given {@code person}'s details.
- */
- public static String getPersonDetails(Person person) {
- StringBuilder sb = new StringBuilder();
- sb.append(PREFIX_NAME + person.getName().fullName + " ");
- sb.append(PREFIX_PHONE + person.getPhone().value + " ");
- sb.append(PREFIX_EMAIL + person.getEmail().value + " ");
- sb.append(PREFIX_ADDRESS + person.getAddress().value + " ");
- person.getTags().stream().forEach(
- s -> sb.append(PREFIX_TAG + s.tagName + " ")
- );
- return sb.toString();
- }
-
- /**
- * Returns the part of command string for the given {@code EditPersonDescriptor}'s details.
- */
- public static String getEditPersonDescriptorDetails(EditPersonDescriptor descriptor) {
- StringBuilder sb = new StringBuilder();
- descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
- descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" "));
- descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
- descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" "));
- if (descriptor.getTags().isPresent()) {
- Set tags = descriptor.getTags().get();
- if (tags.isEmpty()) {
- sb.append(PREFIX_TAG);
- } else {
- tags.forEach(s -> sb.append(PREFIX_TAG).append(s.tagName).append(" "));
- }
- }
- return sb.toString();
- }
-}
diff --git a/src/test/java/seedu/address/testutil/StudentBuilder.java b/src/test/java/seedu/address/testutil/StudentBuilder.java
new file mode 100644
index 00000000000..b9ab5f8b824
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/StudentBuilder.java
@@ -0,0 +1,99 @@
+package seedu.address.testutil;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import seedu.address.model.student.Email;
+import seedu.address.model.student.GitHub;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.Telegram;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.model.util.SampleDataUtil;
+
+/**
+ * A utility class to help with building Student objects.
+ */
+public class StudentBuilder {
+
+ public static final String DEFAULT_NAME = "Amy Bee";
+ public static final String DEFAULT_TELEGRAM = "@amybeeee14";
+ public static final String DEFAULT_EMAIL = "amy@gmail.com";
+ public static final String DEFAULT_GITHUB = "amy-bee-10";
+ public static final String DEFAULT_TUTORIAL_GROUP = "CS2101 G08";
+
+ private Name name;
+ private Telegram telegram;
+ private Email email;
+ private GitHub gitHub;
+ private Set tutorialGroups;
+
+ /**
+ * Creates a {@code StudentBuilder} with the default details.
+ */
+ public StudentBuilder() {
+ name = new Name(DEFAULT_NAME);
+ telegram = new Telegram(DEFAULT_TELEGRAM);
+ email = new Email(DEFAULT_EMAIL);
+ gitHub = new GitHub(DEFAULT_GITHUB);
+ tutorialGroups = new HashSet<>();
+ tutorialGroups.add(new TutorialGroup(DEFAULT_TUTORIAL_GROUP));
+ }
+
+ /**
+ * Initializes the StudentBuilder with the data of {@code studentToCopy}.
+ */
+ public StudentBuilder(Student studentToCopy) {
+ name = studentToCopy.getName();
+ telegram = studentToCopy.getTelegram();
+ email = studentToCopy.getEmail();
+ gitHub = studentToCopy.getGitHub();
+ tutorialGroups = new HashSet<>(studentToCopy.getTutorialGroups());
+ }
+
+ /**
+ * Sets the {@code Name} of the {@code Student} that we are building.
+ */
+ public StudentBuilder withName(String name) {
+ this.name = new Name(name);
+ return this;
+ }
+
+ /**
+ * Parses the {@code tutorialGroups} into a {@code Set}
+ * and set it to the {@code Student} that we are building.
+ */
+ public StudentBuilder withTutorialGroup(String ... tutorialGroups) {
+ this.tutorialGroups = SampleDataUtil.getTutorialGroupSet(tutorialGroups);
+ return this;
+ }
+
+ /**
+ * Sets the {@code GitHub} of the {@code Student} that we are building.
+ */
+ public StudentBuilder withGitHub(String gitHub) {
+ this.gitHub = new GitHub(gitHub);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Telegram} of the {@code Student} that we are building.
+ */
+ public StudentBuilder withTelegram(String telegram) {
+ this.telegram = new Telegram(telegram);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Email} of the {@code Student} that we are building.
+ */
+ public StudentBuilder withEmail(String email) {
+ this.email = new Email(email);
+ return this;
+ }
+
+ public Student build() {
+ return new Student(name, telegram, email, gitHub, tutorialGroups);
+ }
+
+}
diff --git a/src/test/java/seedu/address/testutil/StudentUtil.java b/src/test/java/seedu/address/testutil/StudentUtil.java
new file mode 100644
index 00000000000..0896e80307a
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/StudentUtil.java
@@ -0,0 +1,63 @@
+package seedu.address.testutil;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIAL_GROUP;
+
+import java.util.Set;
+
+import seedu.address.logic.commands.AddStudentCommand;
+import seedu.address.logic.commands.EditCommand;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * A utility class for Student.
+ */
+public class StudentUtil {
+
+ /**
+ * Returns an add command string for adding the {@code student}.
+ */
+ public static String getAddStudentCommand(Student student) {
+ return AddStudentCommand.COMMAND_WORD + " " + getStudentDetails(student);
+ }
+
+ /**
+ * Returns the part of command string for the given {@code student}'s details.
+ */
+ public static String getStudentDetails(Student student) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(PREFIX_NAME + student.getName().fullName + " ");
+ sb.append(PREFIX_TELEGRAM + student.getTelegram().value + " ");
+ sb.append(PREFIX_EMAIL + student.getEmail().value + " ");
+ sb.append(PREFIX_GITHUB + student.getGitHub().value + " ");
+ student.getTutorialGroups().stream().forEach(
+ s -> sb.append(PREFIX_TUTORIAL_GROUP + s.tutorialGroupName + " ")
+ );
+ return sb.toString();
+ }
+
+ /**
+ * Returns the part of command string for the given {@code EditStudentDescriptor}'s details.
+ */
+ public static String getEditStudentDescriptorDetails(EditCommand.EditStudentDescriptor descriptor) {
+ StringBuilder sb = new StringBuilder();
+ descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
+ descriptor.getTelegram().ifPresent(phone -> sb.append(PREFIX_TELEGRAM).append(phone.value).append(" "));
+ descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
+ descriptor.getGitHub().ifPresent(address -> sb.append(PREFIX_GITHUB).append(address.value).append(" "));
+ if (descriptor.getTutorialGroups().isPresent()) {
+ Set tutorialGroups = descriptor.getTutorialGroups().get();
+ if (tutorialGroups.isEmpty()) {
+ sb.append(PREFIX_TUTORIAL_GROUP);
+ } else {
+ tutorialGroups.forEach(s -> sb.append(PREFIX_TUTORIAL_GROUP).append(s.tutorialGroupName).append(" "));
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/address/testutil/TestUtil.java
index 896d103eb0b..d9aac87d8c6 100644
--- a/src/test/java/seedu/address/testutil/TestUtil.java
+++ b/src/test/java/seedu/address/testutil/TestUtil.java
@@ -7,7 +7,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
/**
* A utility class for test cases.
@@ -33,23 +33,23 @@ public static Path getFilePathInSandboxFolder(String fileName) {
}
/**
- * Returns the middle index of the person in the {@code model}'s person list.
+ * Returns the middle index of the student in the {@code model}'s student list.
*/
public static Index getMidIndex(Model model) {
- return Index.fromOneBased(model.getFilteredPersonList().size() / 2);
+ return Index.fromOneBased(model.getFilteredStudentList().size() / 2);
}
/**
- * Returns the last index of the person in the {@code model}'s person list.
+ * Returns the last index of the student in the {@code model}'s student list.
*/
public static Index getLastIndex(Model model) {
- return Index.fromOneBased(model.getFilteredPersonList().size());
+ return Index.fromOneBased(model.getFilteredStudentList().size());
}
/**
- * Returns the person in the {@code model}'s person list at {@code index}.
+ * Returns the student in the {@code model}'s student list at {@code index}.
*/
- public static Person getPerson(Model model, Index index) {
- return model.getFilteredPersonList().get(index.getZeroBased());
+ public static Student getStudent(Model model, Index index) {
+ return model.getFilteredStudentList().get(index.getZeroBased());
}
}
diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/seedu/address/testutil/TypicalIndexes.java
index 1e613937657..210a3f69c36 100644
--- a/src/test/java/seedu/address/testutil/TypicalIndexes.java
+++ b/src/test/java/seedu/address/testutil/TypicalIndexes.java
@@ -6,7 +6,11 @@
* A utility class containing a list of {@code Index} objects to be used in tests.
*/
public class TypicalIndexes {
- public static final Index INDEX_FIRST_PERSON = Index.fromOneBased(1);
- public static final Index INDEX_SECOND_PERSON = Index.fromOneBased(2);
- public static final Index INDEX_THIRD_PERSON = Index.fromOneBased(3);
+ public static final Index INDEX_FIRST_STUDENT = Index.fromOneBased(1);
+ public static final Index INDEX_SECOND_STUDENT = Index.fromOneBased(2);
+ public static final Index INDEX_THIRD_STUDENT = Index.fromOneBased(3);
+ public static final Index INDEX_FOURTH_STUDENT = Index.fromOneBased(4);
+ public static final Index INDEX_FIFTH_STUDENT = Index.fromOneBased(5);
+ public static final Index INDEX_SIXTH_STUDENT = Index.fromOneBased(6);
+ public static final Index INDEX_SEVENTH_STUDENT = Index.fromOneBased(7);
}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
deleted file mode 100644
index fec76fb7129..00000000000
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package seedu.address.testutil;
-
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * A utility class containing a list of {@code Person} objects to be used in tests.
- */
-public class TypicalPersons {
-
- public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
- .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
- .withPhone("94351253")
- .withTags("friends").build();
- public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
- .withAddress("311, Clementi Ave 2, #02-25")
- .withEmail("johnd@example.com").withPhone("98765432")
- .withTags("owesMoney", "friends").build();
- public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
- .withEmail("heinz@example.com").withAddress("wall street").build();
- public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
- .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build();
- public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
- .withEmail("werner@example.com").withAddress("michegan ave").build();
- public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
- .withEmail("lydia@example.com").withAddress("little tokyo").build();
- public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
- .withEmail("anna@example.com").withAddress("4th street").build();
-
- // Manually added
- public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
- .withEmail("stefan@example.com").withAddress("little india").build();
- public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("8482131")
- .withEmail("hans@example.com").withAddress("chicago ave").build();
-
- // Manually added - Person's details found in {@code CommandTestUtil}
- public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
- .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
- public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
- .build();
-
- public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
-
- private TypicalPersons() {} // prevents instantiation
-
- /**
- * Returns an {@code AddressBook} with all the typical persons.
- */
- public static AddressBook getTypicalAddressBook() {
- AddressBook ab = new AddressBook();
- for (Person person : getTypicalPersons()) {
- ab.addPerson(person);
- }
- return ab;
- }
-
- public static List getTypicalPersons() {
- return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
- }
-}
diff --git a/src/test/java/seedu/address/testutil/TypicalStudents.java b/src/test/java/seedu/address/testutil/TypicalStudents.java
new file mode 100644
index 00000000000..4ab7499079b
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/TypicalStudents.java
@@ -0,0 +1,80 @@
+package seedu.address.testutil;
+
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GITHUB_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TELEGRAM_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2101_G08;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_GROUP_CS2103T_W15_3;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import seedu.address.model.AddressBook;
+import seedu.address.model.student.Student;
+
+/**
+ * A utility class containing a list of {@code Student} objects to be used in tests.
+ */
+public class TypicalStudents {
+
+ public static final Student ALICE = new StudentBuilder().withName("Alice Pauline")
+ .withGitHub(null).withEmail("alice@u.nus.edu")
+ .withTelegram("@APauline")
+ .withTutorialGroup("CS2103 W13-2").build();
+ public static final Student BENSON = new StudentBuilder().withName("Benson Meier")
+ .withGitHub("bensonguy")
+ .withEmail("johnd@u.nus.edu").withTelegram(null)
+ .withTutorialGroup("CS2106 T02", "CS2103 W13-2").build();
+ public static final Student CARL = new StudentBuilder().withName("Carl Kurz Meier").withTelegram("@CarlJr")
+ .withEmail("heinz@u.nus.edu").withGitHub("JrCarl").withTutorialGroup("CS2106 T02").build();
+ public static final Student DANIEL = new StudentBuilder().withName("Daniel Carl Meier")
+ .withTelegram("@DanieltheName").withEmail("cornelia@u.nus.edu")
+ .withGitHub("Dan-iel").withTutorialGroup("CS2103 W13-2").build();
+ public static final Student ELLE = new StudentBuilder().withName("Elle Meyer").withTelegram("@Elle20")
+ .withEmail("werner@u.nus.edu").withGitHub("ELLE")
+ .withTutorialGroup("CS2106 T02", "CS2103 W13-2", "CS2101 G08").build();
+ public static final Student FIONA = new StudentBuilder().withName("Fiona Kunz").withTelegram("@Fiona14")
+ .withEmail("lydia@u.nus.edu").withGitHub("Fiona-14")
+ .withTutorialGroup("CS2106 T02", "CS2103T W15-3").build();
+ public static final Student GEORGE = new StudentBuilder().withName("George Fiona Kun").withTelegram("@George11")
+ .withEmail("anna@u.nus.edu").withGitHub("George-Not-Bush").withTutorialGroup("CS2106 T02").build();
+
+ // Manually added
+ public static final Student HOON = new StudentBuilder().withName("Hoon Meier").withTelegram("@Hooooon")
+ .withEmail("stefan@u.nus.edu").withGitHub("hoon-meier-14").withTutorialGroup("CS2106 T02").build();
+ public static final Student IDA = new StudentBuilder().withName("Ida Mueller").withTelegram("@idaida10")
+ .withEmail("hans@u.nus.edu").withGitHub("mueller-ida-20").withTutorialGroup("CS2103 W13-2").build();
+
+ // Manually added - Student's details found in {@code CommandTestUtil}
+ public static final Student AMY = new StudentBuilder().withName(VALID_NAME_AMY).withTelegram(VALID_TELEGRAM_AMY)
+ .withEmail(VALID_EMAIL_AMY).withGitHub(VALID_GITHUB_AMY)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2101_G08).build();
+ public static final Student BOB = new StudentBuilder().withName(VALID_NAME_BOB).withTelegram(VALID_TELEGRAM_BOB)
+ .withEmail(VALID_EMAIL_BOB).withGitHub(VALID_GITHUB_BOB)
+ .withTutorialGroup(VALID_TUTORIAL_GROUP_CS2103T_W15_3, VALID_TUTORIAL_GROUP_CS2101_G08).build();
+
+ public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
+
+ private TypicalStudents() {} // prevents instantiation
+
+ /**
+ * Returns an {@code AddressBook} with all the typical persons.
+ */
+ public static AddressBook getTypicalAddressBook() {
+ AddressBook ab = new AddressBook();
+ for (Student student : getTypicalStudents()) {
+ ab.addStudent(student);
+ }
+ return ab;
+ }
+
+ public static List getTypicalStudents() {
+ return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
+ }
+}