diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 81267b247eb..05b9d7d0a6f 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -23,7 +23,7 @@ jobs: - name: Run repository-wide tests if: runner.os == 'Linux' - working-directory: ${{ github.workspace }}/.github + working-directory: ${{ github.workspace }}/.github run: ./run-checks.sh - name: Validate Gradle Wrapper @@ -32,13 +32,14 @@ jobs: - name: Setup JDK 11 uses: actions/setup-java@v1 with: - java-version: '11' + java-version: "11" java-package: jdk+fx - name: Build and check with Gradle run: ./gradlew check coverage - - uses: codecov/codecov-action@v2 + - name: Codecov + uses: codecov/codecov-action@v3.1.1 if: runner.os == 'Linux' with: directory: ${{ github.workspace }}/build/reports/jacoco/coverage diff --git a/.gitignore b/.gitignore index 71c9194e8bd..d8706331a55 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,11 @@ src/main/resources/docs/ /out/ /*.iml +# VSCode files +.vscode +bin +.jekyll-cache + # Storage/log files /data/ /config.json diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 00000000000..5e378409bca --- /dev/null +++ b/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments=--init-script C\:\\Users\\xuanw\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.16.0\\config_win\\org.eclipse.osgi\\53\\0\\.cp\\gradle\\init\\init.gradle --init-script C\:\\Users\\xuanw\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.16.0\\config_win\\org.eclipse.osgi\\53\\0\\.cp\\gradle\\protobuf\\init.gradle +auto.sync=true +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=C\:/Program Files/Java/jdk-11.0.13 +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/README.md b/README.md index 13f5c77403f..0bda2b1b68a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,57 @@ -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/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. +[![Java CI](https://github.com/AY2223S2-CS2103T-T17-1/tp/actions/workflows/gradle.yml/badge.svg?branch=master)](https://github.com/AY2223S2-CS2103T-T17-1/tp/actions/workflows/gradle.yml) +[![codecov](https://codecov.io/gh/AY2223S2-CS2103T-T17-1/tp/branch/master/graph/badge.svg?token=9DLYEI4IMS)](https://codecov.io/gh/AY2223S2-CS2103T-T17-1/tp)[![pages-build-deployment](https://github.com/AY2223S2-CS2103T-T17-1/tp/actions/workflows/pages/pages-build-deployment/badge.svg?branch=master)](https://github.com/AY2223S2-CS2103T-T17-1/tp/actions/workflows/pages/pages-build-deployment) + + + + +# Team builder + +This is a project by Software Engineering (SE) students of the National University of Singapore (NUS). +It is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org). You can view the NUS source code [here](https://github.com/nus-cs2103-AY2223S2/tp). + +We aim for this project to be able to help Computing Students manage contacts to form teams for hackathons, etc. + + + +* For the detailed documentation of this project, see the **[Team Builder Product Website](https://ay2223s2-cs2103t-t17-1.github.io/tp/)**. +* This project is an implementation of a project that is **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. + +## Installation + +Prerequisite: + +1. Downloaded [Java JDK 11](https://www.oracle.com/sg/java/technologies/javase/jdk11-archive-downloads.html) for your operating system. + +Team Builder Installation: + +1. Download teambuilder.jar from the latest release +2. Run Team Builder using method (A) or (B) + (A) Run teambuilder.jar from the command line using\ + `java -jar teambuilder.jar`\ + (B) Double click onto teambuilder.jar + +## Usage + +> View the full user guide [here](https://ay2223s2-cs2103t-t17-1.github.io/tp/UserGuide.html) + +## Contribution + +> View the full developer guide [here](https://ay2223s2-cs2103t-t17-1.github.io/tp/DeveloperGuide.html) + +If you would like to contribute to our project, there are some items you will need to note: + + 1. All Pull Requests are subjected to a NUS Professor's approval as this project is graded for a module. + 2. Code Reviews, however, are greatly appreciated. + 3. Making an issue for a bug is also greatly appreciated. + +## Authors + +> View our team page [here](https://ay2223s2-cs2103t-t17-1.github.io/tp/AboutUs.html) + +- Joshua Chiang ([@ChickenChiang](https://github.com/ChickenChiang)) +- Chen Jiarui ([@chen-jerry-junior](https://github.com/chen-jerry-junior)) +- See Wei Xun ([@swx0](https://github.com/swx0)) +- William Chau Wei Xuan ([@WillCWX](https://github.com/willcwx)) + +## Other Acknowledgements +- [Fluent UI Icons](https://github.com/microsoft/fluentui-system-icons) ([filled](https://www.svgrepo.com/collection/fluent-ui-icons-filled/), [outlined](https://www.svgrepo.com/collection/fluent-ui-icons-outlined)) are used under the MIT License. diff --git a/build.gradle b/build.gradle index 108397716bd..d2922290107 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id 'jacoco' } -mainClassName = 'seedu.address.Main' +mainClassName = 'teambuilder.Main' sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -20,6 +20,10 @@ checkstyle { toolVersion = '10.2' } +run { + enableAssertions = true +} + test { useJUnitPlatform() finalizedBy jacocoTestReport @@ -61,12 +65,14 @@ dependencies { implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.7.4' testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: jUnitVersion + // for vscode + testImplementation('org.junit.platform:junit-platform-launcher:1.5.2') testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion } shadowJar { - archiveFileName = 'addressbook.jar' + archiveFileName = 'teambuilder.jar' } defaultTasks 'clean', 'test' diff --git a/copyright.txt b/copyright.txt index 93aa2a39ce2..beb11adbd27 100644 --- a/copyright.txt +++ b/copyright.txt @@ -4,6 +4,10 @@ Copyright by Susumu Yoshida - http://www.mcdodesign.com/ - address_book_32.png - AddressApp.ico +Copyright (c) 2020 Microsoft Corporation - https://developer.microsoft.com/en-us/fluentui#/ +- fluent ui outlined icons +- fluent ui filled icons + Copyright by Jan Jan Kovařík - http://glyphicons.com/ - calendar.png - edit.png diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1c9514e966a..9e4f8aba201 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -9,51 +9,40 @@ You can reach us at the email `seer[at]comp.nus.edu.sg` ## Project team -### John Doe +### Chen Jiarui - + -[[homepage](http://www.comp.nus.edu.sg/~damithch)] -[[github](https://github.com/johndoe)] -[[portfolio](team/johndoe.md)] - -* Role: Project Advisor - -### Jane Doe - - - -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/chen-jerry-junior)] [[portfolio](team/chen-jerry-junior.md)] * Role: Team Lead -* Responsibilities: UI +* Responsibilities: Data & UI -### Johnny Doe +### Joshua Chiang - + -[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)] +[[github](http://github.com/chickenchiang)] +[[portfolio](team/chickenchiang.md)] * Role: Developer -* Responsibilities: Data +* Responsibilities: UI -### Jean Doe +### See Wei Xun - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/swx0)] [[portfolio](team/swx0.md)] * Role: Developer -* Responsibilities: Dev Ops + Threading +* Responsibilities: Developer guide, Documentation -### James Doe +### William Chau Wei Xuan - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/willcwx)] +[[portfolio](team/willcwx.md)] * Role: Developer -* Responsibilities: UI +* Responsibilities: Testing, Integration diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 46eae8ee565..d80df3b5b91 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,7 +1,16 @@ --- layout: page title: Developer Guide + --- + + * Table of Contents {:toc} @@ -9,7 +18,8 @@ title: Developer Guide ## **Acknowledgements** -* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} +* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5) +* Icons used: [Fluent UI](https://github.com/microsoft/fluentui-system-icons) -------------------------------------------------------------------------------------------------------------------- @@ -23,7 +33,7 @@ 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/AY2223S2-CS2103T-T17-1/tp/blob/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 @@ -36,7 +46,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/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/Main.java) and [`MainApp`](https://github.com/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/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,13 +79,13 @@ 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/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/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` 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/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/resources/view/MainWindow.fxml) The `UI` component, @@ -86,7 +96,7 @@ The `UI` component, ### 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/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/logic/Logic.java) Here's a (partial) class diagram of the `Logic` component: @@ -94,14 +104,15 @@ 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 result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. +2. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`. +3. The command can communicate with the `Model` when it is executed (e.g. to add a person). +4. 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. - + ![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png) +
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
@@ -114,14 +125,14 @@ How the parsing works: * 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. ### 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/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/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 TeamBuilder data i.e., all `Person` objects (which are contained in a `UniquePersonList` object) and all `Team` objects (which are contained in a `UniqueTeamList` 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 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) @@ -135,18 +146,18 @@ 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/AY2223S2-CS2103T-T17-1/tp/blob/master/src/main/java/teambuilder/storage/Storage.java) The `Storage` component, -* can save both address book data and user preference data in json format, and read them back into corresponding objects. +* can save both TeamBuilder data and user preference data in json format, and read them back into corresponding objects. * inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). * depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) ### Common classes -Classes used by multiple components are in the `seedu.addressbook.commons` package. +Classes used by multiple components are in the `teambuilder.commons` package. -------------------------------------------------------------------------------------------------------------------- @@ -154,89 +165,235 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa This section describes some noteworthy details on how certain features are implemented. -### \[Proposed\] Undo/redo feature +### Add person feature + +The add person feature allows for some fields to be optional. However, the person must have a name, and their name cannot be the same as another existing contact in TeamBuilder. + +The interactions between components for the `add` command is similar to the `delete` command shown [above](#delete). + +Below shows the activity diagram when the user inputs the add command in the command box: + +![Activity Diagram for add person command](images/ActivityDiagram_AddPerson.png){:.center} + +The _rake_ symbol in the `AddCommandParser parses input` actions is used to indicate that the action is describes in another subsidiary activity diagram. The activity diagram is as shown below: + +![Activity Diagram for add person parser](images/ActivityDiagram_AddCommandParser.png){:.center} + +### Create team feature + +The activity diagram when user inputs create command in the command box is similar to the Add person feature shown [above](#add-person-feature), with the difference being that Person objects are swapped with Team objects and error messages. + +The same applies for CreateCommandParser, where the activity diagram is similar to AddCommandParser, with the difference being that the valid prefixes are now `tn/` and `td/` etc. The error messages are also catered towards Team creation, as opposed to Person creation. + + +### Optional Fields feature + +The AB3 implementation made it such that you could not add a contact without having all of their fields present. We felt this to be not user-friendly as for our purposes it is unreasonable for users to have the phone, email, address, and major of the contact they which to add. + +Thus, we have made it such that the only mandatory field is the persons name. + +#### Implementation -#### Proposed Implementation +The implementation for the follow fields: Phone, Email, Major, Address have been made optional. The implementation to achieve this is similar across these fields. We use the Phone class as an example. -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: +```java +private static final Phone NO_PHONE = new Phone(); -* `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. +//... + +private Phone() { + value = ""; +} +``` + +- The private constructor `Phone()` takes in no arguments and returns a phone instance where the value is an empty string. +- The private constructor is then used to create a static final `NO_PHONE` phone instance. This will be used as a placeholder when users does not input a phone field/ phone field is empty. + + +### Undo/Redo feature + +#### Implementation + +The `undo`/`redo` mechanism is based on the memento design pattern. Within the memento design pattern, there are three main classes: + +1. `Originator` - The stateful object that becomes modified and requires to be restored using `undo`/`redo`. +2. `Memento` - The wrapper of a saved state of an `Originator` that is used to restore the `Originator`. +3. `Caretaker` - The aggregator of `Memento` that controls the sequence of `Memento`s for `undo`/`redo`. + +The pattern can be implemented with the `Originator` and `Memento` as an <> to allow for better extension and reduce decoupling. + +![Memento Design Pattern](images/MementoDesignPatternDiagram.png){:.center} + + +While the Memento Design Pattern is mostly used for `undo`, we can extend its functionality to include `redo`. + +Implementing this design pattern results in the following: + +- `Model` inferface extends the `Originator` interface, resulting in a concrete `Originator` in `ModelManger`. +- `TeamBuilderMemento` implements the `Memento` interface and acts as a saved state of `ModelManager` +- `HistoryUtil` replaces the `Caretaker` and tracks the timeline and order of `Memento` +- Any modifying `Command` will call `HistoryUtil#storePast` with `Model#save()` and their `COMMAND_WORD` or a description of what changed.\ +(`AddCommand` is given as an example.) + +![Implemented Memento Design](images/ImplementedMementoDesignDiagram.png){:.center} + +As we want `undo`/`redo` to provide feedback to the user, the `Commands` must provide context to `HistoryUtil` -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. -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. +**Step 1.** +The user launches the application for the first time. The `HistoryUtil` will be initialized with two empty `Memento` arrays, one for `undo` and another for `redo`. The `currentNum`, an array index, will be `-1` indicating totally empty arrays. -![UndoRedoState0](images/UndoRedoState0.png) +![UndoRedoState0](images/NewUndoRedoState0.png){:.center} -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. +**Step 2.** +The user executes `delete 5` command to delete the 5th person in the team builder. The `delete` command calls `Model#save()` before any actions, causing the initial state of the team builder to be saved as a `Memento`. The `delete` command provides the resutling `Memeto` and the context of the change (deleting 5) to `HistoryUtil#storePast`. The `Memento` is saved in `undoHistory` and the `currentNum`, the array index, increases to `0`. -![UndoRedoState1](images/UndoRedoState1.png) +![UndoRedoState1](images/NewUndoRedoState1.png){:.center} -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`. +**Step 3.** +The user executes `add n/David …​` to add a new person. The `add` command also calls `Model#save()` before any actions, saving another `Memento`. The `Memento` and description (add n/david ...) is stored through `HistoryUtil#storePast`. The `Memento` is saved in `undoHistory` and the `currentNum` increases to `1`. -![UndoRedoState2](images/UndoRedoState2.png) +![UndoRedoState2](images/NewUndoRedoState2.png){:.center} -
: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`. +
:information_source:**Note:** If a command fails its execution, it will not call `Model#save()`, so the `Memento` is not stored in `HistoryUtil`.
-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. +**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 `HistoryUtil#undo`. + +`HistoryUtil#undo` will then operate as follows: +1. `Memento#getUpdatedMemo` is called on `undoHistory[currentNum]`, generating a `Memento` of the current state. +2. The resulting `Memento` is saved into `redoFuture[currentNum]`. +3. Then, `Memento#restore` is called on `undoHistory[currentNum]` +4. An `Optional description` is returned + +The `undo` command then feedbacks to the user that the undo has occured successfully along with a description if any. + -![UndoRedoState3](images/UndoRedoState3.png) -
: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. +![UndoRedoState3](images/NewUndoRedoState3.png){:.center} + +
:information_source: **Note:** If the `currentNum` is at index -1, then there are no previous TeamBuilder states to restore. In this case, `HistoryUtil#undo` returns `Optional.empty()`. +As `undo` command uses `Optional::isPresent` to check if undo is successful, it will then return an error message to the user.
The following sequence diagram shows how the undo operation works: -![UndoSequenceDiagram](images/UndoSequenceDiagram.png) +![UndoSequenceDiagram](images/NewUndoSequenceDiagram.png){:.center} -
: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. +
: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.
-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. +The `redo` command does the opposite — it calls `HistoryUtil#redo()`, which checks the `redoFuture` for any `Memento` to restore at `counterNum`. If present, the `Memento` is restored and a `Optional` containing the description of the `Memento` is given to the `redo` command. The restored `Memento` is moved to `undoHistory` and removed from `redoFuture`. The `redo` command feedbacks the output to the user. -
: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. +
:information_source: **Note:** If the `counterNum` is at an index where `redoFuture` is null, then there are no undone `Memento` to restore. The `redo` command uses the `Optional` output `Optional::isPresent` to check if this is the case. If so, it will return an error message the user.
-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. +**Step 5.** +The user then decides to execute the command `list`. Commands that do not modify the TeamBuilder, such as `list`, will usually not call `Model#Save()`, `HistroyUtil#storePast` , `HistroyUtil#undo`, `HistoryUtil#redo`. Thus, the `Model` remains unchanged. + +![UndoRedoState4](images/NewUndoRedoState4.png){:.center} -![UndoRedoState4](images/UndoRedoState4.png) +**Step 6.** +The user executes `clear`, which calls `Model#Save` and stores the resulting `Memento` and description (clear) into `HistoryUtil#storePast`. Since there is a new `Memento` for `undoHistory` that is not from `redoFuture`, all `Memento` in `redoFuture` are purged. -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. +**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) +![UndoRedoState5](images/NewUndoRedoState5.png){:.center} The following activity diagram summarizes what happens when a user executes a new command: - + #### Design considerations: **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. +* **Alternative 1 (current choice):** Saves the state of the team builder found in ModelManager (Current choice). + * Pros: Easy to implement, easy to extend, easy to modify what "state" is saved and restored. + * Cons: May have performance issues in terms of memory usage if state saved is too large. * **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. +* **Alternative 3:** Save the entire team builder inside VersionedTeamBuilder, replacing TeamBuilder (Original AB-3 Choice) + * Pros: Easy to implement. + * Cons: Difficult to extend. Performance issues in terms of memory usage. Undo/Redo timeline tied to TeamBuilder. No user feedback on what command was undone/redone. + + +### Sort feature + +Both fields for sorting persons are compulsory, namely the order of sorting and the sort by criteria. The order and +sort by criteria that are available are listed in the User Guide. + +Below shows the activity diagram when the user inputs the sort command in the command box: + +![Activity Diagram for sort command](images/sortcommand-activity.png){:.center} + +The subsidiary diagram, for SortCommandParser, is as shown below: + +![Activity Diagram for sort command parser](images/newsortcommandparser.png){:.center} + +#### Implementation + +The `filteredPersons` variable in the ModelManager.java is defined by passing in the `getPersonList()` from `addressBook` +into a `FilteredList` object. However, `sortedPersons` variable in the ModelManager.java is instead defined by passing +in `filteredPersons` into a `SortedList` object. + +This ensures that modifications (deletes/edits) to the persons after a `list` or `sort` command will be consistent. + +#### Design considerations: + +The `parse` function in SortCommandParser.java is used to trim and process the arguments before instantiating +SortCommand object. The `execute` function in SortCommand is used to identify the order and sort by to be used by the +comparator and to run the sort with the comparator. This ensures that subsequent additions to sort by, such as sort by +name etc, would only require to edit the `execute` function. + +The `SortBy` Enum ensures that new sorting options can be extended in future iterations. A new switch case can be added +to the `SortCommand` to perform an `updateSort()` for the `Model` object, with the corresponding comparator. -_{more aspects and alternatives to be added}_ +### Show Team feature -### \[Proposed\] Data archiving +The field for show team is compulsory. The current implementation requires user to input names of the targeted teams. -_{Explain here how the data archiving feature will be implemented}_ +Below shows the activity diagram when the user inputs the show command in the command box: + +![Activity Diagram for show command](images/ActivityDiagram_ShowCommand.png){:.center} + +Below shows the activity diagram for the details of parsing show command: + +![Activity Diagram for show command parser](images/ActivityDiagram_ShowCommandParser.png){:.center} + +Below shows the activity diagram about the predicate processing of show command: + +![Activity Diagram for show command parser](images/ActivityDiagram_TeamContainsKeywordsPredicate.png){:.center} + +#### Implementation + +Show command utilizes the `updateFilterPersonList()` method implemented in ModelManager.java to filter the +`filteredPersons` list variable in ModelManager with the given predicate `TeamContainsKeywordsPredicate`. + +The `TeamContainsKeywordsPredicate` object takes in a `List` from `ShowCommandParser`, and make use of the +`containsWordIgnoreCase()` from `StringUtil` to conduct matching between the user input and the `tagName` of each +the `teams` of each `Person` object. + +#### Design considerations: + +The `parse` function in ShowCommandParser.java will trim the arguments and create a predicate object with the input +after the command prefix. This predicate is passed to ShowCommand as a parameter. This ensured that this feature can +take other predicate in future iterations. Currently, there is only one predicate that search the keywords among team +names. When there are demands such as searching keywords among team requirements, new predicates can be created and +ShowCommand can easily adapt to new iterations. + +TeamContainsKeywordsPredicate.java is created to facilitate the comparison between keywords and `tagName` of team. -------------------------------------------------------------------------------------------------------------------- @@ -257,42 +414,92 @@ _{Explain here how the data archiving feature will be implemented}_ **Target user profile**: -* has a need to manage a significant number of contacts +* looking to form teams for hackathons/competitions/projects * 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**: group based on expertise/competence/availability/goals to find better teammates ### 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 | +| Priority | As a …​ | I want to …​ | So that I can…​ | +|----------|-----------------|-----------------------------------------------------|-----------------------------------------------------------------------| +| `* * *` | new user | delete the sample contacts | start finding actual teammates | +| `* * *` | new user | delete a contact | remove contact deemed unsuitable for any team | +| `* * *` | normal user | add a contact | find their info for later use | +| `* * *` | normal user | add tags to contacts | see what their proficiencies are and what they are look to accomplish | +| `* * *` | normal user | edit a contact | rectify changes or mistakes | +| `* * *` | normal user | view contact list | see all my contacts | +| `* *` | first time user | see some sample contacts when I open the app | easily try out its features without needing to add my data first | +| `* *` | first time user | see a help message explaining features to try first | start by trying features that are more suited for new users | +| `* *` | forgetful user | have a clear contact list for my social hub | Have quick access to my contact lists to find the target person | *{More to be added}* ### 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 `TeamBuilder` and the **Actor** is the `user`, unless specified otherwise) + +**Use case: Add a contact** + +**MSS** + +1. User enters add command followed by input fields. +2. TeamBuilder parses input with AddCommandParser. +3. TeamBuilder creates AddCommand. +4. TeamBuilder executes AddCommand. +5. TeamBuilder saves person in model and storage. + + Use case ends. + +**Extensions** +- 2a. Inputs for command invalid. + - 2a1. TeamBuilder displays error caused by invalid field/ missing field. + - 2a2. TeamBuilder displays valid format for add command. + + Use case ends. +- 4a. User inputs name which already exists in TeamBuilder. + - 4a1. TeamBuilder displays error message indicating duplicate name. + + Use case ends + + +**Use case: Delete a contact** + +**MSS** + +1. User requests to list contacts. +2. TeamBuilder shows a list of contacts. +3. User requests to delete a specific contact in the list. +4. TeamBuilder deletes the person. + + Use case ends. + +**Extensions** + +* 2a. The list is empty. + + Use case ends. + +* 3a. The given index is invalid. -**Use case: Delete a person** + * 3a1. TeamBuilder shows an error message. + + Use case resumes at step 2. + +**Use case: List all contact** **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. User requests to list contacts. +2. TeamBuilder shows a list of contacts. +3. User requests to edit a specific contact in the list. +4. TeamBuilder edit the person. Use case ends. @@ -304,7 +511,7 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli * 3a. The given index is invalid. - * 3a1. AddressBook shows an error message. + * 3a1. TeamBuilder shows an error message. Use case resumes at step 2. @@ -316,12 +523,22 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli 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. + *{More to be added}* ### Glossary +* **Actor**: In the context of use cases, the actor is a role that a person play when using the system. +* **API**: (Application Programming Interface) How separate components of the program communicate with each other. +* **Architecture**: Referring to software architecture, showing overall organization of the system. +* **Framework**: A set of pre-written code containing predefined classes and functions that helps developers build a software. +* **GUI**: (Graphical User Interface) A Ui using icons, menu, and mouse to interact with the system. +* **JavaFX**: A framework used to create user interfaces in java. * **Mainstream OS**: Windows, Linux, Unix, OS-X +* **Parsing**: In the context of our program, parsing is to transform a piece of user input into something that can be run by our program * **Private contact detail**: A contact detail that is not meant to be shared with others +* **Sequence Diagrams**: User to model the interactions between entities in a system within a specific scenario. +* **UI**: (User Interface) Where the human interacts with the program. -------------------------------------------------------------------------------------------------------------------- @@ -330,7 +547,7 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli Given below are instructions to test the app manually.
:information_source: **Note:** These instructions only provide a starting point for testers to work on; -testers are expected to do more *exploratory* testing. +testers can do more *exploratory* testing.
@@ -368,10 +585,135 @@ testers are expected to do more *exploratory* testing. 1. _{ more test cases …​ }_ -### Saving data +### Creating a team -1. Dealing with missing/corrupted data files +1. Creating a team - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ + 1. Test case: `create tn/Team A td/Team for upcoming hackathon t/Python t/ReactNative`
+ Expected: Team A is created in the team panel on the right. Team name is shown in the status message. -1. _{ more test cases …​ }_ + 1. Test case: `create tn/Team B t/Python t/ReactNative`
+ Expected: No team is created (no team description in command). Error details shown in the status message. + + 1. Other incorrect create commands to try: `create`, `create td/Team for upcoming hackathon t/Python t/ReactNative`, `...`
+ Expected: Similar to previous. + +### Show teams + +1. Show all members under certain teams + + 1. Prerequisites: Create two teams with command `create`. Multiple persons in the list. Add person one in team one with command `edit`. Add person two in team one and team two. Add person three in team two. + + 1. Test case: `show Name_of_Team_One`
+ Expected: Person one and person two are listed in the person panel on the left. Other people are filtered out. + + 1. Test case: `show Name_of_Team_Two`
+ Expected: Person two and person three are listed in the person panel on the left. Other people are filtered out. + + 1. Test case: `show Name_of_Team_One Name_of_Team_Two`
+ Expected: Person one, two, three are listed in the person panel on the left. Other people are filtered out. + + 1. Other incorrect show commands to try: `show`, `show Name_of_Not_Created_Team`, `...`
+ Expected: Error details shown in the status message. + +### Sorting persons + +1. Sorting persons + + 1. Test case: `sort desc tcount`
+ Expected: Sort persons by tag count in descending order. 'Sorted all persons.' is shown in the status message. + + 1. Test case: `sort tcount`
+ Expected: No sorting occurs (no order in command). Error details shown in the status message. + + 1. Other incorrect sort commands to try: `sort`, `sort desc`, `...`
+ Expected: Similar to previous. + +### Undo/Redo + +1. Undoing a clear while some contacts are being shown + + 1. Prerequisites: Find some contacts using the `find` command. Some but not all contacts in the list. Then use `clear` resulting in an empty Team Builder. + + 2. Test case: `undo`
+ Expected: The Team Builder is restored and no longer empty. Some but not all contacts are in the list, as `find` was used. Using `list` then should show the entire contact list still present. + + + +## **Appendix: Planned Enhancements** + + +### Adding and removing tags from persons +Currently, to add a Tag to a contact, one has to use the `edit` command to add a tag to the contact. There are main drawback is that the user has to input all the tags the person already has, as the `edit` command will remove all tags and only assign tags given in the command. + +Similarly, to remove a Tag, the user has to use the `edit` command and type all the tags the person has and omit the ones that the user wishes to remove. + +This is rather tedious for the user and negatively affects user experience. + +#### Enhancement: +Allow users to add and remove tags specifically, users only need to input the tags they wish to add/remove. + +#### Suggested implementation: +Create two commands, `add-tag` and `remove_tag` with the following input format: + +```add_tag t/ [t/ ...]``` + +```remove_tag t/ [t/ ...]``` + +- `` is the index of the person shown on the person list of the Ui. If there is no person at the given index, the command will throw an error. This field is required. +- `` is the name of the tag the user wishes to add to a person. If the command is `remove_tag` and the tag is not found in the contact, an error will be thrown. This field is required. +- `[t/ ...]` is/are additional tags users wish to add/remove from the person at the same time. If the comamnd is `remove_tag` and the tag(s) are not found in the contact, and error will be thrown. This field is optional. + +### Adding/removing persons to/from teams +Currently, to add a person to a team, one has to use the `edit` command to add a team tag to the contact. There are significant drawbacks to this: +1. User has to type out the entire team name in the team tag. +2. User has to input all the teams that the person is already in, else the edit command will remove those tags from the person. + +This negatively impacts user experience as the process of adding and removing persons from teams becomes time-consuming and prone to typos. + +#### Enhancement: +Instead of using the team names, users will be able to add and remove persons using the team index on the team list. + +#### Suggested implementation: +Create two new commands, `add_to_team` and `remove_from_team`, both of which will have the following format: + +```add_to_team [ ...]``` + +```remove_from_team [ ...]``` + +- `` is the index of the person shown on the person list of the Ui. If there is no person at the given index, the command will throw an error. This field is required. +- `` is the index of a team shown on the team list of the Ui. If there is no team at the given index, the command will throw an error. This field is required. +- `[ ...]` is/are additional teams that the user wants to add/remove a person to/from. For example, user can input `remove_from_team 1 1 2 3`, and this will remove the person at index 1 from the teams at index 1, 2, and 3. The additional team(s) are optional. + + +### Long Fields support + +#### Person fields and team fields +Fields that are too long and are cut off by the Ui are to be truncated and indicated with ellipses. + +- _E.g._ if a person name is "Salvador Felipe Jacinto Dalí y Domenech" and cannot be displayed fully, the Ui should replace it with "Salvador Felipe Jac...", with the ellipses ending at the cut-off. +- Users should also be able to view the full length of the field by hovering their mouse over that particular field. +- Same goes for tags, if the tags of a contact/team takes up more than two rows, the remained will be hidden, and an indicator will appear to show how many tags are hidden +- _E.g._ A contact with 230 tags may only have 14 tags shown on the Ui, and at the end of the displayed tag a text `"... +216"` will indicate that they have 216 more tags that are hidden. + +#### Tags (Skill tags, team tags, person tags) +Tags that are longer than 20 characters to be truncated on the Ui. Users can then hover their mouse over it to see the full tag. + +- _E.g._ The Tag "Grandmaster in Witchcraft and Wizardry" will appear as "Grandmaster in Witch..." on the Ui. + + +## _Appendix:_ Effort + +TeamBuilder is a brownfield project which builds upon the existing features of AB3. Our vision for TeamBuilder, although simple conceptually, proved to be challenging to implement due to AB3's pre-existing architecture. + +### Challenges with dependencies between Teams and Persons +The ability to create teams and add persons into TeamBuilder is the highlight of our project. It proved to be monstrous task, requiring thorough changes in every component of the AB3 Architecture. + +- While AB3 only has Contacts, we wanted TeamBuilder to also have Teams, which is another entity. Teams and Persons are both dependent on each other, as a person cannot be part of a non-existent team, and a Team cannot have a non-existent person. +- Deleting person and teams proved to be a huge challenge for TeamBuilder, as when a team is deleted, any person that is part of the team has to be updated such that they no longer have that team tag. Similarly, when a person is deleted, Teams have to be updated such that that person is also removed from the team. +- Additionally, this same issue caused problems for the Storage component. Should the storage contain a person that is part of a Team that does not exist, or a Team contain a person that does not exist, TeamBuilder has to be able to catch these errors and act appropriately. + +The large degree of inter-dependencies made implementing a relatively 'simple' feature such as adding a person or deleting a team to require much time and effort in understanding AB3's implementation, as well as coming up with solutions to achieve our goal. + +### High effort required for test cases. +TeamBuilder differs greatly from AB3 as all persons' fields are optional except for their name, and TeamBuilder has Teams as well as persons. As a result, sizeable chunks of tests from AB3 are not relevant, and the Team had to reformat most of the tests, as well as generate and create new Sample data to test. diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 72767f00fd9..6c05accd779 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -242,6 +242,7 @@ GEM tzinfo (1.2.10) thread_safe (~> 0.1) unicode-display_width (1.8.0) + wdm (0.1.1) zeitwerk (2.6.1) PLATFORMS @@ -251,6 +252,7 @@ PLATFORMS DEPENDENCIES github-pages jekyll + wdm (~> 0.1.0) BUNDLED WITH 2.1.4 diff --git a/docs/SettingUp.md b/docs/SettingUp.md index 275445bd551..fbdc062cd61 100644 --- a/docs/SettingUp.md +++ b/docs/SettingUp.md @@ -23,8 +23,8 @@ If you plan to use Intellij IDEA (highly recommended): 1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
:exclamation: Note: Importing a Gradle project is slightly different from importing a normal Java project. 1. **Verify the setup**: - 1. Run the `seedu.address.Main` and try a few commands. - 1. [Run the tests](Testing.md) to ensure they all pass. + 1. Run the `teambuilder.Main` and try a few commands. + 2. [Run the tests](Testing.md) to ensure they all pass. -------------------------------------------------------------------------------------------------------------------- diff --git a/docs/Testing.md b/docs/Testing.md index 8a99e82438a..7cfa89c1067 100644 --- a/docs/Testing.md +++ b/docs/Testing.md @@ -29,8 +29,8 @@ There are two ways to run tests. This project has three types of tests: 1. *Unit tests* targeting the lowest level methods/classes.
- e.g. `seedu.address.commons.StringUtilTest` + e.g. `teambuilder.commons.StringUtilTest` 1. *Integration tests* that are checking the integration of multiple code units (those code units are assumed to be working).
- e.g. `seedu.address.storage.StorageManagerTest` + e.g. `teambuilder.storage.StorageManagerTest` 1. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
- e.g. `seedu.address.logic.LogicManagerTest` + e.g. `teambuilder.logic.LogicManagerTest` diff --git a/docs/UserGuide.md b/docs/UserGuide.md index e7df68b01ea..d041ad26c9a 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,119 +3,385 @@ 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. + -* Table of Contents -{:toc} --------------------------------------------------------------------------------------------------------------------- +
+:information_source: **Preface:** -## Quick start +* This guide is on the **usage** of Team Builder. +* For a guide on **developing** Team Builder with us, see our [developer guide](DeveloperGuide.html). +* We are **still working** on making our user guide as user friendly as possible. You can help us by providing feedback [here](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/new) +
-1. Ensure you have Java `11` or above installed in your Computer. +**Team Builder (TB)** is a desktop app primarily for cross-faculty students to manage their contacts and build a multidisciplinary team based on soft skills and technical skills. -1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases). +It is 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, TB can help you build your team through your contacts much faster than traditional GUI apps. -1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook. +# About this guide -1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png) +Labelled App Window -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: +Welcome to Team Builder, we hope that this product will allow you +to manage your contacts to build fantastic teams for your events/competitions. - * `list` : Lists all contacts. +This guide is designed for users with and without technical experience and is to be followed narratively from top to bottom. However, if you are an experienced user, feel free to skip the Example context. If you are looking for a specific command, you can view the [table of commands here](#full-table-of-commands). - * `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: **What do the symbols and formatting mean?:** - * `delete 3` : Deletes the 3rd contact shown in the current list. +* :information_source: - are important specific information to note - * `clear` : Deletes all contacts. +* :bulb: - are usage tips/shortcuts - * `exit` : Exits the app. +* :exclamation: - are some warnings about certain actions + +* [links](#about-this-guide) - these blue words are links and can be clicked on +
+ +## This guide is split into 6 sections: -1. Refer to the [Features](#features) below for details of each command. +1. [Full Table of Commands](#full-table-of-commands) +2. [Quick Start](#quick-start) +3. [Managing Contacts](#managing-contacts) +4. [Making a Team](#making-a-team) +5. [Extra Team Builder Features](#extra-team-builder-features) +6. [FAQ](#faq) + +Sections 3,4,5 contain descriptions and instructions for the main features of Team Builder. + +Below is the full table of contents, in case you are looking for something very specific. + +
+:information_source: **Full Table of Content:** + +- [Full Table of Commands](#full-table-of-commands) +- [Quick start](#quick-start) +- [Managing Contacts](#managing-contacts) + - [Adding a new contact : `add`](#adding-a-new-contact--add) + - [Updating a contact : `edit`](#updating-a-contact--edit) + - [Deleting a contact : `delete`](#deleting-a-contact--delete) +- [Making a Team](#making-a-team) + - [Creating a team: `create`](#creating-a-team-create) + - [Finding the right teammate I : `find`](#finding-the-right-teammate-i--find) + - [Finding the right teammate II : `list`](#finding-the-right-teammate-ii--list) + - [Finding the right teammate III : `sort`](#finding-the-right-teammate-iii--sort) + - [Add a person to a team : `edit`](#add-a-person-to-a-team--edit) + - [Listing all teammates in a team : `show`](#listing-all-teammates-in-a-team--show) + - [Removing a teammate from a team : `edit`](#removing-a-teammate-from-a-team--edit) + - [Removing a team : `remove`](#removing-a-team--remove) +- [Extra Team Builder Features](#extra-team-builder-features) + - [Clearing all entries : `clear`](#clearing-all-entries--clear) + - [Undoing a command : `undo`](#undoing-a-command--undo) + - [Redoing an undo command : `redo`](#redoing-an-undo-command--redo) + - [Exiting the program : `exit`](#exiting-the-program--exit) + - [Saving the data](#saving-the-data) + - [Editing the data file](#editing-the-data-file) +- [FAQ](#faq) +- [Future features](#future-features) + - [Support for long tags](#support-for-long-tags) + - [Phone number limit](#phone-number-limit) + +
+ +
+:bulb: **Tip:** +Access this guide quickly through the `help` command or by clicking the **help** menu icon. +
+help message +
-------------------------------------------------------------------------------------------------------------------- -## Features +# Full Table of Commands
+:information_source: **Notes about the command format:** + +* `command` - are the command words. **They are case-sensitive!** -**:information_source: Notes about the command format:**
+* `UPPER_CASE` - are the input data fields to be supplied by the user.
+ e.g. in `add n/NAME`, `NAME` is an input data field which can be used as `add n/John Doe`. -* 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`. +* `[]` - are optional input data fields.
+ e.g. `[e/EMAIL]` can be used like ` ` (i.e. not used) or `e/lmao@lmao.com` -* 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`. +* `[]...` - are input data fields that can be supplied any number of times including zero times.
+ e.g. `[t/TAG]...` can be used like ` ` (i.e. 0 times), `t/React`, `t/React t/AWS` etc. -* 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.
+Command | Type |Format, Examples +:--------:|:----------------------:|:--------: +[**add**](#adding-a-new-contact--add) | Modifying |`add n/NAME [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [m/MAJOR] [t/TAG]... [T/TEAM_NAME]...` +[**clear**](#clearing-all-entries--clear) | Modifying |`clear` +[**delete**](#deleting-a-contact--delete) | Modifying |`delete INDEX`
e.g., `delete 3` +[**edit**](#updating-a-contact--edit) | Modifying |`edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]... [T/TEAM_NAME]... ​` +[**find**](#finding-the-right-teammate-i--find) | Listing | `find NAME/MAJOR/TAG [MORE_KEYWORDS]`
e.g., `find James Jake` +[**sort**](#finding-the-right-teammate-iii--sort) | Listing |`sort ORDER SORT_BY`
e.g., `sort desc tcount` +[**create**](#creating-a-team-create) | Modifying |`create tn/TEAM_NAME td/TEAM_DESC [t/TAG]`
e.g., `create tn/TeamA td/2103T_tP t/Java` +[**show**](#listing-all-teammates-in-a-team--show) | Listing |`show TEAM_NAME [OTHER_TEAM_NAME]...` +[**list**](#finding-the-right-teammate-ii--list) | Listing |`list` +[**remove**](#removing-a-team--remove) | Modifying |`remove TEAM_NAME` +[**undo**](#undoing-a-command--undo) | Special
Modifying | `undo` +[**redo**](#redoing-an-undo-command--redo) | Modifying |`redo` +[**help**](#help-command) | Window |`help` + +
+:bulb: **Tips on command behaviour:** + +* You can place input data fields in any order.
e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. -* 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.
+* If a input data is expected only once in the command but you specified it multiple times, only the last occurrence of the input data 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.
+* If you enter extraneous input fields for commands with no input data fields (such as `help`, `list`, `exit` and `clear`), the command will execute as per normal while ignoring the fields.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
-### Viewing help : `help` +-------------------------------------------------------------------------------------------------------------------- + +# Quick start + +Prerequisite: + +1. Downloaded [Java JDK 11](https://www.oracle.com/sg/java/technologies/javase/jdk11-archive-downloads.html) for your operating system. + +Team Builder Installation: + +1. Open a command terminal + +2. Ensure you have **Java 11** or above installed in your Computer by typing `java --version` in the command terminal. +Information on the Java version installed should appear in the command terminal. Otherwise, [click here to troubleshoot](https://www.java.com/download/help/troubleshoot_java.html#:~:text=Temporarily%20turn%20off%20firewall%20or,successfully%20completed%20the%20Java%20install.). + +3. Download the latest **teambuilder.jar** from [here](https://github.com/AY2223S2-CS2103T-T17-1/tp/releases). + +4. Copy the file to the folder you want to use as the _home folder_ for your Team Builder. + +5. In the command terminal, `cd` into the folder you put the jar file in, and use the `java -jar teambuilder.jar` command to run the application.
+ A window (seen below without the labels) should appear in a few seconds. Note how the app contains some sample data.
+
+ As you can see there are two main panels. The left panels shows your contacts, and the right panel shows the teams that you have in Team Builder.
+ + - The _blue_ tags are the **skill tags** of a person, to denote the skills or specialisation of the person. + - The _red_ tags are the **team tags**, which tell you which team a person is in + - The _yellow-orange_ tags are the **members** of a team, which tells you the names of the team members in a team + - The _green_ tags are the **skill tags** of a team, which are the skills that you think this team needs. + + You will find more details below the tags of the respective person/team, such as the team description or the contact's phone number. + + + +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: + + * `list` : Lists all contacts. + + * `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 m/computer science` : Adds a contact named `John Doe` to the Team Builder. + + * `delete 3` : Deletes the 3rd contact shown in the current list. + + * `clear` : Deletes all contacts. + + * `exit` : Exits the app. + +2. Refer to the [Full Table of Commands](UserGuide.html#full-table-of-commands) above for details of each command. + +
+ +-------------------------------------------------------------------------------------------------------------------- + +# Managing Contacts + +Team Builder allows you to easily manage contacts of individuals that you would want to be teammates with. + +Your contacts can be managed in these ways: +1. Adding new potential teammates as a contact. +2. Updating any existing contact's information and tags. +3. Deleting contacts that you no longer want to be teammates with or have lost contact. + +## Adding a new contact : `add` + +Format: `add n/NAME [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [m/MAJOR] [t/TAG]... [T/TEAM_NAME]...​` + + +**Example context**: -Shows a message explaning how to access the help page. +**John Pic** -![help message](images/helpMessage.png) +You have exchanged contacts with a person named **John** at a Computer Science Event. +He seems like a nice guy that you might want to do projects with. You note that he is a business major with **great presentations skills**. -Format: `help` +Let's add his contacts to Team Builder as a new potential teammate for future events and projects! +**What to type**: -### Adding a person: `add` +`add n/John p/98765432 m/Business t/Good Presentor` -Adds a person to the address book. +**Result**: -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​` +Image of John added + +
+:information_source: **Note:** +The order of persons added in the list may not be in chronological order. +
+ +
:exclamation: **Caution:** +You can only add a team tag to a person if the team has been created beforehand! +
:bulb: **Tip:** -A person can have any number of tags (including 0) +A contact can have any number of tags (including 0). Tags are especially useful for keeping track of skills and traits! +A contact must have a name, other features are optional.
-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` +## Updating a contact : `edit` -### Listing all persons : `list` +Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [m/MAJOR] [t/TAG]… [T/TEAM_NAME]​` -Shows a list of all persons in the address book. +**Example context**: -Format: `list` +**BACK OF JOHN'S CARD** + +It seems that we forgot to add some information about **John**. +We missed out the back of his card that has his **email**. +Let's use the `edit` command to update his information. -### Editing a person : `edit` +John at index 1 +

We see John is index 1 in our display.

-Edits an existing person in the address book. +**What to type**: -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…​` +`edit 1 e/john@example.com` + +**Result**: +John with email added +

John's email is now reflected on our contact list.

+ + +
+**:information_source: Notes about the edit command:**
* 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. +* When editing tags and teams, the existing tags and teams of the person will be removed i.e adding of tags and teams is not cumulative. +* You can remove all the person’s tags or teams by respectively typing `t/` or `T/` without + specifying any after it. +
+ +## Deleting a contact : `delete` + +Format: `delete INDEX` + +**Example context**: + +You hear from your friends that **John** is actually a **snake*** :snake: and we do not want a snake as a teammate. + +Let's delete him from our Team Builder. + +Again, we see **John** is index 1 in our display. + +**What to type**: + +`delete 1 ` + +**Result**: + +John deleted + +

John is no longer in your Team Builder contact list!

+

* snake refers to a backstabber.

+ +
+ +# Making a Team + +Team Builder helps you to make a team easily and keep in mind any skills that are required. + +Our current team management features include: +1. Creating a team +2. Finding the right teammate using `find`, `list` and `sort` +3. Adding a person to a team +4. Listing all teammates in a team +5. Removing a person from a team +6. Removing a team entirely -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. +## Creating a team: `create` -### Locating persons by name: `find` +Format: `create tn/TEAM_NAME td/TEAM_DESC [t/TAG]...` -Finds persons whose names contain any of the given keywords. +**Example context**: -Format: `find KEYWORD [MORE_KEYWORDS]` +You have decided to participate in NUS Hack&Roll hackathon. Let's create a team called "NUSMeets"! Since your idea involves creating +a web application, you will need someone with technical experience in React and AWS. You would also prefer to have a UI +person to make your web app presentable. As this hackathon involves a tight timeline, proper project management skills +are required too. + +**What to type**: + +`create tn/NUSMeets td/A multidisciplinary team for upcoming HacknRoll in mid Jan. t/JavaScript t/React t/AWS t/Project Management t/UI Design` + +**Result**: + +result for 'create team' + +## Finding the right teammate I : `find` + + Format: `find NAME/MAJOR/TAG [MORE_KEYWORDS]...` + +**Example context 1**: + +You recall that two of your tutorial classmate named Alex and David are good at UI Design and you want to invite them +to your team, but you have forgotten their full name and contact numbers. + +**What to type**: + +`find alex david` + +**Result**: + +result for 'find alex david' + +**Example context 2**: + +You still feel your team needs more people, and you decide to find someone who majored in computer science. + +**What to type**: + +`find computer science` + +**Result**: + +result for 'find computer science' + +**Example context 3**: + +Now your team is almost formed, but you still need a person who mastered JavaScript. + +**What to type**: + +`find javascript` + +**Result**: + +result for 'find javascript' + +
+:information_source: **Specificity of `find`**: * 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` @@ -124,70 +390,273 @@ Format: `find KEYWORD [MORE_KEYWORDS]` * Persons matching at least one keyword will be returned (i.e. `OR` search). e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` -Examples: -* `find John` returns `john` and `John Doe` -* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png) -### Deleting a person : `delete` +
-Deletes the specified person from the address book. -Format: `delete INDEX` +## Finding the right teammate II : `list` -* 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, …​ +Format: `list` + +**Example context**: + +You feel that you have narrowed down to too little people. Let's display our whole contact list again. + +**What to type**: + +`list` + +If you have accidentally added extra input fields after `list`, the command would be accepted as anything after `list` is discarded. + + +## Finding the right teammate III : `sort` + + Format: `sort ORDER SORT_BY` + +**Example context**: + +Perhaps you are not too sure which skills are required in your team, so you want to list persons who know a wide range +of skills first. + +**What to type**: + +`sort desc tcount` + +**Result**: + +result for 'create team' + +
+ +:information_source: **Specificity of `sort`**: + +* The ORDER and SORT_BY are case-insensitive. e.g `tcount` will match `tCount` +* The ORDER can only be either ascending (`asc`) or descending (`desc`) +* The following SORT_BY are available: +* `tcount` Sorts by person's tag count (this applies to the **blue skill tags** only, not including team tags) +
+ +
+:information_source: **Note:** +Sort would be performed on the current list of persons displayed on the UI. If you are looking to sort all persons after +performing a `find` command etc., remember to use `list` command before using `sort`. +
+ +## Add a person to a team : `edit` + +Format: `edit INDEX [T/TEAM_NAME]...` + +**Example context**: + +You recall participating in a Hackathon previously with Alex Yeoh and knows he is familiar with React. You decide to +reach out to him to form your team for Hack&Roll. + +**What to type**: + +`edit 1 T/NUSMeets` + +**Result**: + + +result for 'edit 1' + + +
+:information_source: **Note:** +`edit` command is used here as adding a person to a team is equivalent to editing the team tags of a person. +
+ +
:exclamation: **Caution:** + +* You can only add a person to the team if the team has been created beforehand!
+ +* If you are adding a team to a person with existing teams, you need to type out their other team names as well. e.g. `edit 1 T/Old Team T/New Team` +
+ +## Listing all teammates in a team : `show` + +Format: `show TEAM_NAME [OTHER_TEAM_NAME]...` + +**Example context**: + +The Hack&Roll announced that there is a limit on team size. You want to list all people who are currently added to your +NUSMeets team. + +**What to type**: + +`show NUSMeets` + +**Result**: + +result for 'show' + +## Removing a teammate from a team : `edit` + +Format: `edit INDEX [T/TEAM_NAME]` + +**Example context**: + +Alex reached out to you later that he is now unable to attend Hack&Roll due to some personal circumstances. +We have no choice but to remove Alex from our team. + + +**What to type**: + +`edit 1 T/` + +**Result**: + +result for 'edit 1' +

We see that Alex's team tag is removed and the team no longer has Alex as a member

-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. +
+:information_source: **Note:** +`edit` command is used here as removing a person to a team is equivalent to editing the team tags of a person. +
+ +
:exclamation: **Caution:** +If you are removing just one team from a person with multiple teams, you need to type out their other team names to keep them on their other teams.
+(e.g. John is in Team1 and Team2 but he will be removed from Team2, `edit 1 T/Team1`) +
+ +## Removing a team : `remove` + +Format: `remove TEAM_NAME` + +**Example context**: -### Clearing all entries : `clear` +Oh no, you realised that you have a number of deadlines during the period of time Hack&Roll would run. +Taking into account Alex's absence as well, You decide to not participate in it anymore. + +**What to type**: + +`remove NUSMeets` + +**Result**: + +NUSMeets will be removed from the team list panel. + +
+:information_source: **Note:** +The `remove` command will also remove the team tags for people who were in the team. +
-Clears all entries from the address book. + +# Extra Team Builder Features + +Team Builder has some quality of life features that may help you in many different ways. + +This includes: +1. Clearing all entries +2. Undoing a command +3. Redoing an undo command +4. Exiting the program +5. Saving data +6. Editing the data file + +## Clearing all entries : `clear` Format: `clear` -### Exiting the program : `exit` +Clears all entries from the Team Builder, instead of manually removing teams and persons. -Exits the program. +**What to type**: -Format: `exit` +`clear` + +## Undoing a command : `undo` -### Saving the data +Format: `undo` -AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. +**Example context**: -### Editing the data file +Oops! It looks like we accidentally used the `clear` command to remove all our contacts. -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. +Let's use the `undo` command to revert our Team Builder back to before we typed the `clear` command. + +**What to type**: + +`undo` + +
+:exclamation: **Caution:** + +* You can only `undo` up to 10 times in a row! After the 10th `undo`, no more `undo` is possible. + +* You can only `undo` [modifying commands](#full-table-of-commands). + +* You may also undo into a state where `find` was called and so your contact list is not shown fully. +Simply use `list` to view the full contact list again. + +
+ +## Redoing an undo command : `redo` + +Format: `redo` + +**Example context**: + +Perhaps we want to `clear` the example contacts after all. + +Let's use the `redo` command to revert our Team Builder back to before we typed the `undo` command. + +**What you can type**: + +`redo`, `redo 123`, `redo ada adw v zklw`, etc. + +These are all acceptable as anything after `redo` is discarded.
: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. +Typing any [modifying command](#full-table-of-commands) (other than an undo) after an `undo` makes it impossible to `redo` that `undo` command!
-### Archiving data files `[coming in v2.0]` +## Exiting the program : `exit` + +Format: `exit` + +Exits the program. + -_Details coming soon ..._ +## Saving the data + +Team Builder data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. + +## Editing the data file + +Team Builder 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. + + +
:exclamation: **Caution:** +If your changes to the data file makes its format invalid, Team Builder will discard all data and start with an empty data file at the next run. +
-------------------------------------------------------------------------------------------------------------------- -## FAQ +# 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 Team Builder home folder. + +**Q**: Why is my command text in red and not working?
+**A**: You might have input an invalid command. Either the command word doesn't exist or the parameters entered are invalid. -------------------------------------------------------------------------------------------------------------------- -## 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` +# Future features + +These are features that will improve your experience using Team Builder, to be added in the future. Look forward to them! + +## Support for long tags + +Currently, whether it is a skill tag or a team tag, Team Builder will try to display the whole tag regardless of how long it is, causing it to overflow out of the window and be un-readable. +Future changes: +- Tags that exceed a character count of 20 characters will be truncated and have a "..." after it. +- Users will be able to view the full tag by hovering their cursor over the tag. +- This will not change the behaviour of the `add`, `edit`, or `find` commands. + +## Phone number limit + +Currently, there is no limit to the length of a contacts phone number. +Future changes: +- Phone number will have a maximum length of 15 digits, as that is the longest viable phone number. + diff --git a/docs/_config.yml b/docs/_config.yml index 6bd245d8f4e..75e6d7ebd08 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,4 +1,4 @@ -title: "AB-3" +title: "Team Builder" theme: minima header_pages: @@ -8,7 +8,7 @@ header_pages: markdown: kramdown -repository: "se-edu/addressbook-level3" +repository: "AY2223S2-CS2103T-T17-1/tp" github_icon: "images/github-icon.png" plugins: diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss index 0d3f6e80ced..7a8039d9db4 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: "Team Builder"; font-size: 32px; } } diff --git a/docs/diagrams/ActivityDiagram_AddCommandParser-Activity b/docs/diagrams/ActivityDiagram_AddCommandParser-Activity new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/diagrams/ActivityDiagram_AddCommandParser.puml b/docs/diagrams/ActivityDiagram_AddCommandParser.puml new file mode 100644 index 00000000000..58f85b63e70 --- /dev/null +++ b/docs/diagrams/ActivityDiagram_AddCommandParser.puml @@ -0,0 +1,21 @@ +@startuml +start +title Activity: AddCommandParser parses input +:Tokenize prefixes in input; +:Map prefix token to input; +repeat +:Check next prefix-input pair; + if () then ([Valid prefix-input pair]) + :Create respective class instance of input; + :Save instance + as argument for person creation; + else ([Invalid Input | Missing input]) + : Throw error with + appropriate error message; + stop +endif +repeat while () is ([Has unchecked prefix]) not ([All inputs are valid]) +:Pass all arguments into Person constructor; +:Return person created; +stop +@enduml diff --git a/docs/diagrams/ActivityDiagram_AddPerson.puml b/docs/diagrams/ActivityDiagram_AddPerson.puml new file mode 100644 index 00000000000..bda1bbd10ca --- /dev/null +++ b/docs/diagrams/ActivityDiagram_AddPerson.puml @@ -0,0 +1,25 @@ +@startuml +sprite $rake [16x16/8] { +0000000000000000 +0000000jj0000000 +0000000jj0000000 +0005555jj5555000 +000jjeejjeejj000 +000jj00jj00jj000 +000jj00jj00jj000 +0000000000000000 +} +start +:User enters add command input; +:AddCommandParser parses input <$rake>; + +if () then ([Parser returns AddCommand]) + :Execute add command; + :Add person to TeamBuilder; + :Person stored in storage; + :PersonCard of newly added person displayed in Ui; +else ([Parser throws exception]) + :Display error message; +endif +stop +@enduml diff --git a/docs/diagrams/ActivityDiagram_ShowCommand.puml b/docs/diagrams/ActivityDiagram_ShowCommand.puml new file mode 100644 index 00000000000..bb1ee2b0f21 --- /dev/null +++ b/docs/diagrams/ActivityDiagram_ShowCommand.puml @@ -0,0 +1,25 @@ +@startuml +sprite $rake [16x16/8] { +0000000000000000 +0000000jj0000000 +0000000jj0000000 +0005555jj5555000 +000jjeejjeejj000 +000jj00jj00jj000 +000jj00jj00jj000 +0000000000000000 +} +start +title Activity: User input ShowCommand +:User enters show command input; +:ShowCommandParser parses input <$rake>; +if () then ([Parser returns ShowCommand]) + :Execute show command; + :Set predicate for filteredPersons; + :update filteredPersons in ModelManager; + :PersonCard of all filtered people displayed in Ui; +else ([Parser throws exception]) + :Display error message; +endif +stop +@enduml diff --git a/docs/diagrams/ActivityDiagram_ShowCommandParser.puml b/docs/diagrams/ActivityDiagram_ShowCommandParser.puml new file mode 100644 index 00000000000..9e5dd0af8cd --- /dev/null +++ b/docs/diagrams/ActivityDiagram_ShowCommandParser.puml @@ -0,0 +1,14 @@ +@startuml +start +title Activity: ShowCommandParser parses input +:Trim argument; +if () then ([Argument is empty]) + :Display error message; +else ([else]) + :Split the argument with spaces; + :Create a list using the split argument; + :Create a TeamContainsKeywordsPredicate with the list as parameter; + :Return a ShowCommand object with the predicate as parameter; +endif +stop +@enduml diff --git a/docs/diagrams/ActivityDiagram_TeamContainsKeywordsPredicate.puml b/docs/diagrams/ActivityDiagram_TeamContainsKeywordsPredicate.puml new file mode 100644 index 00000000000..48c3ce077e1 --- /dev/null +++ b/docs/diagrams/ActivityDiagram_TeamContainsKeywordsPredicate.puml @@ -0,0 +1,14 @@ +@startuml +start +title Activity: Filter filteredPersons with TeamContainsKeywordsPredicate +:TeamContainsKeywordsPredicate takes in a Keyword list; +:Create a stream with the Keyword list; +:filteredPersons set TeamContainsKeywordsPredicate as its predicate; +:Apply the predicate test function to each person stored; +repeat +:Create a stream with the Team set from the person; +:Compare each element in the keyword stream with the name of that of the team stream; +repeat while () is ([Has untested person]) not ([All person tested]) +:Update filteredPersons; +stop +@enduml diff --git a/docs/diagrams/AddCommandClassDiagram.puml b/docs/diagrams/AddCommandClassDiagram.puml new file mode 100644 index 00000000000..4924cb7f10a --- /dev/null +++ b/docs/diagrams/AddCommandClassDiagram.puml @@ -0,0 +1,13 @@ +@startuml +!include style.puml + +'!include style.puml +' +'class State1 as "__:ArgMultiMap__" +'class State2 as "__:AddCommandParser__" +'class State3 as "__ab2:AddressBook__" +actor User as Foo1 +participant Ui as Foo2 UI_COLOR +participant as Foo3 LOGIC_COLOR +participant +@endum diff --git a/docs/diagrams/CommandModelHistoryDiagram.puml b/docs/diagrams/CommandModelHistoryDiagram.puml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml index 6a6b23a006f..db247c0eebc 100644 --- a/docs/diagrams/CommitActivityDiagram.puml +++ b/docs/diagrams/CommitActivityDiagram.puml @@ -5,10 +5,10 @@ start 'Since the beta syntax does not support placing the condition outside the 'diamond we place it as the true branch instead. -if () then ([command commits AddressBook]) - :Purge redundant states; - :Save AddressBook to - addressBookStateList; +if () then ([command commits TeamBuilder]) + :New Memento produced by Model; + :Memento stored with context in HistoryUtil; + :HistoryUtil purges redundant Mementos; else ([else]) endif stop diff --git a/docs/diagrams/ImplementedMementoDesignDiagram.puml b/docs/diagrams/ImplementedMementoDesignDiagram.puml new file mode 100644 index 00000000000..9e97d952a80 --- /dev/null +++ b/docs/diagrams/ImplementedMementoDesignDiagram.puml @@ -0,0 +1,58 @@ +@startuml ImplementedMementoDesignDiagram +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 +skinparam classAttributeIconSize 0 + +class "<>\nMemento" as Memento +show Memento method +Memento : +restore() +Memento : +getUpdatedMemo() + +class "HistoryUtil" as Caretaker +show Caretaker members +Caretaker : -undoHistory: Memento[] +Caretaker : -redoFuture: Memento[] +Caretaker : +storePast(Memento, String) +Caretaker : +undo() +Caretaker : +redo() + +note bottom : calls Memento#restore() +Caretaker -left-o Memento + +class "<>\nOriginator" as Originator +show Originator method +Originator : +save() + +Memento <.left. Originator + +class "<>\nModel" as Model +Model -up-|> Originator + +class "ModelManager" as CO +show CO method +CO : +save() +CO : +setState() + +CO -up.|> Model + +Class "TeamBuilderMemento" as CM +show CM members +CM : -state +CM : -originator +CM : +restore() +CM : +getUpdatedMemo() +note bottom : Restore calls Originator#setState(state) \ngetUpdatedMemo calls Originator#save() + + +CM -up.|> Memento +CO <-> CM + +Class "AddCommand" as ADC +show ADC members +ADC : {static} COMMAND_WORD +ADC : execute(model) +note bottom : calls HistoryUtil#storePast with \nModel#save() and COMMAND_WORD + +ADC .left.> Model +ADC -up--> Caretaker diff --git a/docs/diagrams/MementoDesignPatternDiagram.puml b/docs/diagrams/MementoDesignPatternDiagram.puml new file mode 100644 index 00000000000..800f86090b2 --- /dev/null +++ b/docs/diagrams/MementoDesignPatternDiagram.puml @@ -0,0 +1,39 @@ +@startuml MementoDesignPatternDiagram +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 +skinparam classAttributeIconSize 0 + +class "<>\nMemento" as Memento +show Memento method +Memento : +restore() + +class "Caretaker" as Caretaker +show Caretaker members +Caretaker : -undoHistory: Memento[] +Caretaker : +undo() +note bottom : calls Memento#restore() +Caretaker -left-o Memento + +class "<>\nOriginator" as Originator +show Originator method +Originator : +save() + +Memento <.left. Originator + +class "ConcreteOriginator" as CO +show CO method +CO : +save() +CO : +setState() + +CO -up.|> Originator + +Class "ConcreteMemento" as CM +show CM members +CM : -state +CM : -originator +CM : +restore() +note bottom : calls Originator#setState(state) + +CM -up.|> Memento +CO <-> CM diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index 4439108973a..0f74bbdb379 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -7,44 +7,38 @@ skinparam classBackgroundColor MODEL_COLOR Package Model <>{ Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs -Class "<>\nModel" as Model +Class "<>\nModel" as ModelI Class AddressBook Class ModelManager Class UserPrefs Class UniquePersonList +Class UniqueTeamList Class Person -Class Address -Class Email -Class Name -Class Phone -Class Tag +Class Team + } Class HiddenOutside #FFFFFF -HiddenOutside ..> Model +HiddenOutside ..> ModelI AddressBook .up.|> ReadOnlyAddressBook -ModelManager .up.|> Model -Model .right.> ReadOnlyUserPrefs -Model .left.> ReadOnlyAddressBook +ModelManager .up.|> ModelI +ModelI .right.> ReadOnlyUserPrefs +ModelI .left.> ReadOnlyAddressBook 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 - -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email +AddressBook *-left-> "1" UniqueTeamList +UniquePersonList -left-> "~* all" Person + +UniqueTeamList --> "~* all" Team + + ModelManager -->"~* filtered" Person @enduml diff --git a/docs/diagrams/NewUndoRedoState1.puml b/docs/diagrams/NewUndoRedoState1.puml new file mode 100644 index 00000000000..58d3566aed6 --- /dev/null +++ b/docs/diagrams/NewUndoRedoState1.puml @@ -0,0 +1,26 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "delete 5" + +package undoHistory { + class State1 as "__m0:Memento__" + class State2 as "__null:Memento__" + class State3 as "__null:Memento__" +} +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 + +package redoFuture { + class State5 as "__null:Memento__" + class State6 as "__null:Memento__" + class State7 as "__null:Memento__" +} +State5 -[hidden]right-> State6 +State6 -[hidden]right-> State7 + +class Pointer as "currentNum" +Pointer -up-> State1 +Pointer -[hidden]down->State5 diff --git a/docs/diagrams/NewUndoRedoState2.puml b/docs/diagrams/NewUndoRedoState2.puml new file mode 100644 index 00000000000..13acb404b1c --- /dev/null +++ b/docs/diagrams/NewUndoRedoState2.puml @@ -0,0 +1,26 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "add n/David" + +package undoHistory { + class State1 as "__m0:Memento__" + class State2 as "__m1:Memento__" + class State3 as "__null:Memento__" +} +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 + +package redoFuture { + class State5 as "__null:Memento__" + class State6 as "__null:Memento__" + class State7 as "__null:Memento__" +} +State5 -[hidden]right-> State6 +State6 -[hidden]right-> State7 + +class Pointer as "currentNum" +Pointer -up-> State2 +Pointer -[hidden]down->State6 diff --git a/docs/diagrams/NewUndoRedoState3.puml b/docs/diagrams/NewUndoRedoState3.puml new file mode 100644 index 00000000000..16a4e48bc89 --- /dev/null +++ b/docs/diagrams/NewUndoRedoState3.puml @@ -0,0 +1,27 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "undo" + +package undoHistory { + class State1 as "__m0:Memento__" + class State2 as "__null:Memento__" + class State3 as "__null:Memento__" +} + +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 + +package redoFuture { + class State5 as "__null:Memento__" + class State6 as "__m2:Memento__" + class State7 as "__null:Memento__" +} +State5 -[hidden]right-> State6 +State6 -[hidden]right-> State7 + +class Pointer as "currentNum" +Pointer -up-> State1 +Pointer -[hidden]down->State5 diff --git a/docs/diagrams/NewUndoRedoState4.puml b/docs/diagrams/NewUndoRedoState4.puml new file mode 100644 index 00000000000..383b7d65599 --- /dev/null +++ b/docs/diagrams/NewUndoRedoState4.puml @@ -0,0 +1,27 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "list" + +package undoHistory { + class State1 as "__m0:Memento__" + class State2 as "__null:Memento__" + class State3 as "__null:Memento__" +} + +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 + +package redoFuture { + class State5 as "__null:Memento__" + class State6 as "__m2:Memento__" + class State7 as "__null:Memento__" +} +State5 -[hidden]right-> State6 +State6 -[hidden]right-> State7 + +class Pointer as "currentNum" +Pointer -up-> State1 +Pointer -[hidden]down->State5 diff --git a/docs/diagrams/NewUndoRedoState5.puml b/docs/diagrams/NewUndoRedoState5.puml new file mode 100644 index 00000000000..83e313ea2bd --- /dev/null +++ b/docs/diagrams/NewUndoRedoState5.puml @@ -0,0 +1,27 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title title After command "clear" + +package undoHistory { + class State1 as "__m0:Memento__" + class State2 as "__m3:Memento__" + class State3 as "__null:Memento__" +} + +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 + +package redoFuture { + class State5 as "__null:Memento__" + class State6 as "__null:Memento__" + class State7 as "__null:Memento__" +} +State5 -[hidden]right-> State6 +State6 -[hidden]right-> State7 + +class Pointer as "currentNum" +Pointer -up-> State2 +Pointer -[hidden]down->State6 diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml index 96e30744d24..fff0bd01ae4 100644 --- a/docs/diagrams/UndoRedoState0.puml +++ b/docs/diagrams/UndoRedoState0.puml @@ -3,18 +3,29 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title Initial state +title Initial State of HistoryUtil -package States { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" +class State0 as "Out of bounds" +package undoHistory { + class State1 as "__null:Memento__" + class State2 as "__null:Memento__" + class State3 as "__null:Memento__" } +State0 -[hidden]right-> State1 State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -hide State2 -hide State3 -class Pointer as "Current State" #FFFFF -Pointer -up-> State1 -@end +class State4 as "Out of bounds" +hide State4 +package redoFuture { + class State5 as "__null:Memento__" + class State6 as "__null:Memento__" + class State7 as "__null:Memento__" +} +State4 -[hidden]right-> State5 +State5 -[hidden]right-> State6 +State6 -[hidden]right-> State7 + +class Pointer as "currentNum" +Pointer -up-> State0 +Pointer -[hidden]down-> State4 diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml index bccc230a5d1..4a1a16b1813 100644 --- a/docs/diagrams/UndoRedoState2.puml +++ b/docs/diagrams/UndoRedoState2.puml @@ -14,7 +14,7 @@ package States <> { State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" #FFF Pointer -up-> State3 @end diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml index 1b784cece80..6edbdd692d4 100644 --- a/docs/diagrams/UndoRedoState4.puml +++ b/docs/diagrams/UndoRedoState4.puml @@ -14,7 +14,7 @@ package States <> { State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" #FFF Pointer -up-> State2 @end diff --git a/docs/diagrams/UndoSequenceDiagram copy.puml b/docs/diagrams/UndoSequenceDiagram copy.puml new file mode 100644 index 00000000000..b8e68560c52 --- /dev/null +++ b/docs/diagrams/UndoSequenceDiagram copy.puml @@ -0,0 +1,73 @@ +@startuml NewUndoSequenceDiagram +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":TeamBuilderParser" as TeamBuilderParser LOGIC_COLOR +participant "u:UndoCommand" as UndoCommand LOGIC_COLOR +end box + +box Common.Util +skinparam ParticipantFontColor black +participant ":HistroyUtil" as HistoryUtil +end box + +box Model MODEL_COLOR_T1 +skinparam ParticipantFontColor white +participant "current:Memento" as Memento MODEL_COLOR +participant ":Originator" as Originator MODEL_COLOR +end box +[-> LogicManager : execute(undo) +activate LogicManager + +LogicManager -> TeamBuilderParser : parseCommand(undo) +activate TeamBuilderParser + +create UndoCommand +TeamBuilderParser -> UndoCommand +activate UndoCommand + +UndoCommand --> TeamBuilderParser +deactivate UndoCommand + +TeamBuilderParser --> LogicManager : u +deactivate TeamBuilderParser + +LogicManager -> UndoCommand : execute() +activate UndoCommand + +UndoCommand -> HistoryUtil : undo() +activate HistoryUtil + +HistoryUtil -> Memento : getUpdatedMemo() +activate Memento + +Memento -> Originator : save() +activate Originator + +Originator --> Memento + +Memento --> HistoryUtil + +HistoryUtil -> Memento : restore() + + +Memento -> Originator : setState(state) + +Originator --> Memento +deactivate Originator + +Memento --> HistoryUtil +deactivate Memento + +HistoryUtil --> UndoCommand +deactivate HistoryUtil + +UndoCommand --> LogicManager : result +deactivate UndoCommand +UndoCommand -[hidden]-> LogicManager : result +destroy UndoCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/plantuml/AbeforeC.png b/docs/diagrams/plantuml/AbeforeC.png new file mode 100644 index 00000000000..a52cd2cc281 Binary files /dev/null and b/docs/diagrams/plantuml/AbeforeC.png differ diff --git a/docs/diagrams/plantuml/AllDown.png b/docs/diagrams/plantuml/AllDown.png new file mode 100644 index 00000000000..edc380b60b1 Binary files /dev/null and b/docs/diagrams/plantuml/AllDown.png differ diff --git a/docs/diagrams/plantuml/ArrowLength.png b/docs/diagrams/plantuml/ArrowLength.png new file mode 100644 index 00000000000..8929ceb3ee8 Binary files /dev/null and b/docs/diagrams/plantuml/ArrowLength.png differ diff --git a/docs/diagrams/plantuml/CbeforeA.png b/docs/diagrams/plantuml/CbeforeA.png new file mode 100644 index 00000000000..820c7fe9e81 Binary files /dev/null and b/docs/diagrams/plantuml/CbeforeA.png differ diff --git a/docs/diagrams/plantuml/HiddenArrows.png b/docs/diagrams/plantuml/HiddenArrows.png new file mode 100644 index 00000000000..e9d03eb0231 Binary files /dev/null and b/docs/diagrams/plantuml/HiddenArrows.png differ diff --git a/docs/diagrams/plantuml/PackagesAndConsistency.png b/docs/diagrams/plantuml/PackagesAndConsistency.png new file mode 100644 index 00000000000..3f857513f4e Binary files /dev/null and b/docs/diagrams/plantuml/PackagesAndConsistency.png differ diff --git a/docs/diagrams/plantuml/UpAndDown.png b/docs/diagrams/plantuml/UpAndDown.png new file mode 100644 index 00000000000..d69cc603399 Binary files /dev/null and b/docs/diagrams/plantuml/UpAndDown.png differ diff --git a/docs/images/ActivityDiagram_AddCommandParser.png b/docs/images/ActivityDiagram_AddCommandParser.png new file mode 100644 index 00000000000..f8010263008 Binary files /dev/null and b/docs/images/ActivityDiagram_AddCommandParser.png differ diff --git a/docs/images/ActivityDiagram_AddPerson.png b/docs/images/ActivityDiagram_AddPerson.png new file mode 100644 index 00000000000..d73230b14f9 Binary files /dev/null and b/docs/images/ActivityDiagram_AddPerson.png differ diff --git a/docs/images/ActivityDiagram_ShowCommand.png b/docs/images/ActivityDiagram_ShowCommand.png new file mode 100644 index 00000000000..e57d967462c Binary files /dev/null and b/docs/images/ActivityDiagram_ShowCommand.png differ diff --git a/docs/images/ActivityDiagram_ShowCommandParser.png b/docs/images/ActivityDiagram_ShowCommandParser.png new file mode 100644 index 00000000000..920dff4d7c8 Binary files /dev/null and b/docs/images/ActivityDiagram_ShowCommandParser.png differ diff --git a/docs/images/ActivityDiagram_TeamContainsKeywordsPredicate.png b/docs/images/ActivityDiagram_TeamContainsKeywordsPredicate.png new file mode 100644 index 00000000000..16894b183e5 Binary files /dev/null and b/docs/images/ActivityDiagram_TeamContainsKeywordsPredicate.png differ diff --git a/docs/images/AddCommandClassDiagram.png b/docs/images/AddCommandClassDiagram.png new file mode 100644 index 00000000000..7e897cd1bbc Binary files /dev/null and b/docs/images/AddCommandClassDiagram.png differ diff --git a/docs/images/AddResult.png b/docs/images/AddResult.png new file mode 100644 index 00000000000..915120af05d Binary files /dev/null and b/docs/images/AddResult.png differ diff --git a/docs/images/AlexRemoveFromTeam.png b/docs/images/AlexRemoveFromTeam.png new file mode 100644 index 00000000000..834808a3599 Binary files /dev/null and b/docs/images/AlexRemoveFromTeam.png differ diff --git a/docs/images/Alex_NUSMeets.png b/docs/images/Alex_NUSMeets.png new file mode 100644 index 00000000000..410767c197d Binary files /dev/null and b/docs/images/Alex_NUSMeets.png differ diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png index c08c13f5c8b..737851c2f77 100644 Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ diff --git a/docs/images/CreateTeam.png b/docs/images/CreateTeam.png new file mode 100644 index 00000000000..cdfdca52894 Binary files /dev/null and b/docs/images/CreateTeam.png differ diff --git a/docs/images/FindComputerScience.png b/docs/images/FindComputerScience.png new file mode 100644 index 00000000000..b4287fb6d11 Binary files /dev/null and b/docs/images/FindComputerScience.png differ diff --git a/docs/images/FindJavascript.png b/docs/images/FindJavascript.png new file mode 100644 index 00000000000..8cbe404beee Binary files /dev/null and b/docs/images/FindJavascript.png differ diff --git a/docs/images/FindReact.png b/docs/images/FindReact.png new file mode 100644 index 00000000000..01fd365ffb7 Binary files /dev/null and b/docs/images/FindReact.png differ diff --git a/docs/images/ImplementedMementoDesignDiagram.png b/docs/images/ImplementedMementoDesignDiagram.png new file mode 100644 index 00000000000..2a1b495910b Binary files /dev/null and b/docs/images/ImplementedMementoDesignDiagram.png differ diff --git a/docs/images/JohnAdded.png b/docs/images/JohnAdded.png new file mode 100644 index 00000000000..b6de643f78f Binary files /dev/null and b/docs/images/JohnAdded.png differ diff --git a/docs/images/JohnContactCardBack.jpg b/docs/images/JohnContactCardBack.jpg new file mode 100644 index 00000000000..5e55eda3a5b Binary files /dev/null and b/docs/images/JohnContactCardBack.jpg differ diff --git a/docs/images/JohnContactCardFront.png b/docs/images/JohnContactCardFront.png new file mode 100644 index 00000000000..6c944533bd1 Binary files /dev/null and b/docs/images/JohnContactCardFront.png differ diff --git a/docs/images/JohnDeleted.png b/docs/images/JohnDeleted.png new file mode 100644 index 00000000000..0df47ad1cb2 Binary files /dev/null and b/docs/images/JohnDeleted.png differ diff --git a/docs/images/JohnFullContact.png b/docs/images/JohnFullContact.png new file mode 100644 index 00000000000..c7eae4d2ac7 Binary files /dev/null and b/docs/images/JohnFullContact.png differ diff --git a/docs/images/JohnIndex.png b/docs/images/JohnIndex.png new file mode 100644 index 00000000000..5afa34db059 Binary files /dev/null and b/docs/images/JohnIndex.png differ diff --git a/docs/images/LabelledAppWindow.png b/docs/images/LabelledAppWindow.png new file mode 100644 index 00000000000..d48a6f1b302 Binary files /dev/null and b/docs/images/LabelledAppWindow.png differ diff --git a/docs/images/MementoDesignPatternDiagram.png b/docs/images/MementoDesignPatternDiagram.png new file mode 100644 index 00000000000..f3c44f5256f Binary files /dev/null and b/docs/images/MementoDesignPatternDiagram.png differ diff --git a/docs/images/ModelClassDiagram2.png b/docs/images/ModelClassDiagram2.png new file mode 100644 index 00000000000..eb0e7b4918d Binary files /dev/null and b/docs/images/ModelClassDiagram2.png differ diff --git a/docs/images/NewUndoRedoState0.png b/docs/images/NewUndoRedoState0.png new file mode 100644 index 00000000000..e004ee350b1 Binary files /dev/null and b/docs/images/NewUndoRedoState0.png differ diff --git a/docs/images/NewUndoRedoState1.png b/docs/images/NewUndoRedoState1.png new file mode 100644 index 00000000000..551889128bb Binary files /dev/null and b/docs/images/NewUndoRedoState1.png differ diff --git a/docs/images/NewUndoRedoState2.png b/docs/images/NewUndoRedoState2.png new file mode 100644 index 00000000000..07c25891bfb Binary files /dev/null and b/docs/images/NewUndoRedoState2.png differ diff --git a/docs/images/NewUndoRedoState3.png b/docs/images/NewUndoRedoState3.png new file mode 100644 index 00000000000..ae6ef193bca Binary files /dev/null and b/docs/images/NewUndoRedoState3.png differ diff --git a/docs/images/NewUndoRedoState4.png b/docs/images/NewUndoRedoState4.png new file mode 100644 index 00000000000..ae20a42bb56 Binary files /dev/null and b/docs/images/NewUndoRedoState4.png differ diff --git a/docs/images/NewUndoRedoState5.png b/docs/images/NewUndoRedoState5.png new file mode 100644 index 00000000000..b8e09f5752d Binary files /dev/null and b/docs/images/NewUndoRedoState5.png differ diff --git a/docs/images/NewUndoSequenceDiagram.png b/docs/images/NewUndoSequenceDiagram.png new file mode 100644 index 00000000000..232b09600af Binary files /dev/null and b/docs/images/NewUndoSequenceDiagram.png differ diff --git a/docs/images/ShowNUSMeets.png b/docs/images/ShowNUSMeets.png new file mode 100644 index 00000000000..e58514d7f77 Binary files /dev/null and b/docs/images/ShowNUSMeets.png differ diff --git a/docs/images/TeamBuilderUi.png b/docs/images/TeamBuilderUi.png new file mode 100644 index 00000000000..5f2d7056dce Binary files /dev/null and b/docs/images/TeamBuilderUi.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..f27a5d0da6d 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/UpdateModelClassDiagram.png b/docs/images/UpdateModelClassDiagram.png new file mode 100644 index 00000000000..b3f45923f19 Binary files /dev/null and b/docs/images/UpdateModelClassDiagram.png differ diff --git a/docs/images/chen-jerry-junior.png b/docs/images/chen-jerry-junior.png new file mode 100644 index 00000000000..6340bddbefc Binary files /dev/null and b/docs/images/chen-jerry-junior.png differ diff --git a/docs/images/chickenchiang.png b/docs/images/chickenchiang.png new file mode 100644 index 00000000000..8d4e7e5cf17 Binary files /dev/null and b/docs/images/chickenchiang.png differ diff --git a/docs/images/findAlexDavid.png b/docs/images/findAlexDavid.png new file mode 100644 index 00000000000..62845a763ea Binary files /dev/null and b/docs/images/findAlexDavid.png differ diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png index b1f70470137..9377822079e 100644 Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ diff --git a/docs/images/newsortcommandparser.png b/docs/images/newsortcommandparser.png new file mode 100644 index 00000000000..8541204b1c2 Binary files /dev/null and b/docs/images/newsortcommandparser.png differ diff --git a/docs/images/sortDesc.png b/docs/images/sortDesc.png new file mode 100644 index 00000000000..a40f01b90dc Binary files /dev/null and b/docs/images/sortDesc.png differ diff --git a/docs/images/sortcommand-activity.png b/docs/images/sortcommand-activity.png new file mode 100644 index 00000000000..023b34a274e Binary files /dev/null and b/docs/images/sortcommand-activity.png differ diff --git a/docs/images/swx0.png b/docs/images/swx0.png new file mode 100644 index 00000000000..847cb8befbb Binary files /dev/null and b/docs/images/swx0.png differ diff --git a/docs/images/ui_startup.png b/docs/images/ui_startup.png new file mode 100644 index 00000000000..55876ff2e9d Binary files /dev/null and b/docs/images/ui_startup.png differ diff --git a/docs/images/willcwx.png b/docs/images/willcwx.png new file mode 100644 index 00000000000..fd0164c348a Binary files /dev/null and b/docs/images/willcwx.png differ diff --git a/docs/index.md b/docs/index.md index 7601dbaad0d..9ab9d1a2189 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,19 +1,20 @@ --- layout: page -title: AddressBook Level-3 +title: Team Builder --- [![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) -![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). +**TeamBuilder 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). -* 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 TeamBuilder, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). +* If you are interested about developing TeamBuilder, 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) +* Icons used: [Fluent UI](https://github.com/microsoft/fluentui-system-icons) diff --git a/docs/team/chen-jerry-junior.md b/docs/team/chen-jerry-junior.md new file mode 100644 index 00000000000..ac8f6a40868 --- /dev/null +++ b/docs/team/chen-jerry-junior.md @@ -0,0 +1,59 @@ +--- +layout: page +title: Chen Jiarui's Project Portfolio Page +--- + +### Project: Team Builder + +Team Builder is a desktop personal contacts book application used by the user to form a team for any event. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java. + +Given below are my contributions to the project. + +* **New Feature**: Show + * What it does: allows the user to list all people under certain specified teams. + * Justification: Users might want to list all people under a certain team they created. Rather than checking everyone's person card, they can just use `show` followed by the target team name. This is especially useful when users want to compare a team's skill requirements with skills possessed by the members. + * Highlights: Able to show all members who belong to multiple teams, use `show` followed by names of multiple teams that are separated by spaces. + +* **New Feature**: Major + * What it does: allows the user to add a person with a given major. + * Justification: This is useful when a user want to create a team of students with specified major. A major field also help the user to create cross-disciplinary teams. + * Highlights: This enhancement affects existing commands such as `find` `add` and `edit`. + +* **New Feature**: GUI for Team List + * What it does: adds a TeamListPanel and a TeamCard to allow the user to navigate through the existing teams. + * Justification: This feature improves the product significantly because it is necessary for a user to see the existing teams to use our product. + * Highlights: This feature allows the team list to automatically update regarding the command `create` and `remove` for teams and `edit` for adding people into teams. + +* **Enhancements to existing features**: + * Update `find` command so that the user can use `find` to search for people by their names, skills (tags), and major. + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=chen-jerry-junior&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17) + +* **Testing**: + * Add TeamBuilder to facilitate testing of Team + * Update PersonUtil, EditPersonDescriptorBuilder, TypicalPersons, PersonBuilder to facilitate testing for Major and TeamTag + * Add unit tests for ShowCommandTest, ShowCommandParserTest + * Add unit tests for RemoveCommandTest, RemoveCommandParserTest + * Add unit tests for TeamTest, TeamContainKeywordsPredicateTest + * Add new unit tests for FindCommandTest, FindCommandParserTest + * Add new unit tests for AddCommandTest, AddCommandParserTest + +* **Bug Fixing**: + * Modified the error message of command `add` `edit` `remove` `show` `sort` to consist with the description in the UserGuide. + * Import prefix of TeamTag in add command parser and added comparison of TeamTag in edit command to enable `add` and `edit` on TeamTags. + +* **Project management**: + * Managed TeamBuilder releases for [v1.3.1](https://github.com/AY2223S2-CS2103T-T17-1/tp/releases/tag/v1.3.1) on GitHub. + +* **Documentation**: + * User Guide: + * Added documentation for the feature `show` + * Updated documentation for the feature `find` + * Replaced all "address book" with "TeamBuilder" + * Developer Guide: + * Added implementation details of the `show` feature. + * Added activity diagram for show command and show command parser + * Added manual testing of `show` and `find` + +* **Community**: + * Reported bugs and suggestions for other teams in the class (for PE-D: [17 issues](https://github.com/chen-jerry-junior/ped/issues)) diff --git a/docs/team/chickenchiang.md b/docs/team/chickenchiang.md new file mode 100644 index 00000000000..bd19d41047a --- /dev/null +++ b/docs/team/chickenchiang.md @@ -0,0 +1,59 @@ +--- +layout: page +title: Joshua Chiang's Project Portfolio Page +--- + +### Project: Team Builder + +Team Builder is a desktop personal contacts book application used by the user to form a team for any event. 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**: TeamTags + * What it does: TeamTags allow for users to add a person to a team. It also allows you to see the teams a contact is in at a glance. + * Justification: This is directly in line with our product description. + * Highlights: This feature is not implemented optimally for user experience. Currently, in order to add a person to the team, the user has to edit a contact and type in full team names manually. Additionally, adding a person to a team requires the user to enter all the teams the person already belong to, on top of the new team we wish to add them in. + * Credits: TeamTags takes inspiration for the Tags class from AB3 and heavily mirrors the methods it uses there. + +* **New Feature**: JsonAdaptedTeams and JsonAdaptedNames + * What it does: For TeamBuilder to both read and store Teams and their respective members from/into the data file in JsonFormat. + * Justification: This feature is necessary for TeamBuilder to reach a minimum viable product stage, as teams will not be lost after users exit the program. + * Credits: This feature heavily references the JsonAdaptedPerson class provided by AB3. + +* **New Feature**: UniqueTeamList + * What it does: Allows for TeamBuilder's model component to hold a list of Teams. + * Justification: This feature is necessary for TeamBuilder to function and store teams created by the user. + * Credits: This feature heavily reference the UniquePersonsList from AB3. + +* **New Feature**: Allow contacts to have optional fields + * What it does: Allows for users to add or edit a contact such that certain fields are empty, e.g. address, phone number. + * Justification: TeamBuilder is meant for students primarily. Outside a corporate context, it is unlikely that our users will have/require all details regarding a contact. + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=T17-1&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17) + +* **Project management**: + * Managed TeamBuilder releases for [v1.2](https://github.com/AY2223S2-CS2103T-T17-1/tp/releases/tag/v1.2), [v1.2.1](https://github.com/AY2223S2-CS2103T-T17-1/tp/releases/tag/v1.2.1), and [v1.3](https://github.com/AY2223S2-CS2103T-T17-1/tp/releases/tag/v1.3) on Github. + * Creation of milestones for workflow control. + +* **Enhancements to existing features**: + * Updated GUI for tags, team tags, skill tags, and member tags. + * Changed GUI such that person empty person fields are hidden and take up no space. + +* **Documentation**: + * User Guide: + * Added future features section. + * Added sample screen shot of Ui as well as description for users to understand what they are looking at. + * Developer Guide: + * Documented AddCommand implementation and created an activity diagram to aid understanding. + * Added Future Enhancement section. + * Added documentation for how optional fields are achieved for person class. + +* **Bug fixes**: + * Fixed Ui issue where the TeamList Ui is cutoff when the TeamBuilder window is resized too small. + * Fixed bug where the wrong error is displayed when an invalid index is passed as an argument. + +* **Community**: + * Contributed to forum discussions (examples: [#232](https://github.com/nus-cs2103-AY2223S2/forum/issues/232), [#239](https://github.com/nus-cs2103-AY2223S2/forum/issues/239), [#286](https://github.com/nus-cs2103-AY2223S2/forum/issues/286)) + * Reported bugs and suggestions for other teams in the class (examples: To be added) + + 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/swx0.md b/docs/team/swx0.md new file mode 100644 index 00000000000..595589bdf95 --- /dev/null +++ b/docs/team/swx0.md @@ -0,0 +1,77 @@ +--- +layout: page +title: See Wei Xun's Project Portfolio Page +--- + +### Project: Team Builder + +Team Builder is a desktop app primarily for cross-faculty students to manage their contacts and build a multidisciplinary team based on soft skills and technical skills. 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**: Sort Person's list + * Justification: + * Useful for users to organize their unordered contact list, makes selecting team members easier + * Allows users to find who has the most or least number of skill tags easily + + * Highlights: + * Able to sort Person's list using `sort` command + * Implemented sorting by Person's number of tags using `tcount` as the parameter to `sort` command + * Able to sort in both orders, descending (`desc` as parameter) or ascending (`asc` as parameter) + +* **New Feature**: Create/Remove Team and TeamList + * Justification: + * For users to create/remove team and assign team members. + * TeamList for users to track the status/description of all teams created + + * Highlights: + * Allows users to specify Team's name, description and skill requirements (as tags) + * Able to create teams using `create` command and remove teams using `remove` command + * After a new team is added in TeamList, users are able to add members to team (by attach corresponding team tag to the Person) + * Credits: + * The implementation for Team and TeamList is adapted from the implementation for Person and PersonList respectively + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=swx0&breakdown=true) + +* **Testing**: + * Add unit tests for CreateCommandTest, CreateCommandParserTest + * Add new unit tests for ParserUtilTest, TeamBuilderParserTest + * Add unit tests for SortCommandTest, UniqueTeamListTest + +* **Bug Fixing**: + * Added exception handling for sort command parameters + * Added a note in User Guide under the sort command section to specify the need to execute `list` before `sort` if a `find` command was performed before + * Add clarifying note in User Guide to specify which SORT_BY could be used + * Add clarifying note in User Guide to specify that the Add Command may not add persons in chronological order. + +* **Project management**: + * Generate PE-D bugs report + * Added labels to Pull Requests and Issues and create v1.4 milestone + +* **Team based tasks**: + * Brainstorming of target users, user stories, features to implement + * Update post-mortem v1.2 + +* **Enhancements to existing features**: + * Existing `edit` and `delete` commands + * Edit person's team tags / Delete person would cascade changes to TeamList + * Existing `add` and `edit` commands + * Add / Edit person with Team tags only if teams created beforehand + +* **Documentation**: + * User Guide: + * Add sort command section (command format, examples) + * Add 'Create team', 'Remove a team' and 'Add a person to a team' sections (command format, examples) + * Add screenshots for Find, Show and Create commands + * Developer Guide: + * Update target user profile, value proposition, user stories, use cases + * Add implementation and design considerations for sort function + * Add activity diagram for sort command and sort command parser + * Update Model component diagram to add Team and TeamList, update attributes of Person + * Add description for create team feature + * Remove data archiving section + * Add 'Sorting Persons' and 'Creating a team' in Instructions for manual testing + +* **Community**: + * Contributed to forum discussions ([\#303](https://github.com/nus-cs2103-AY2223S2/forum/issues/303)) + * Reported bugs and suggestions for other teams in the class (for PE-D: [\#1](https://github.com/swx0/ped/issues/1) [\#2](https://github.com/swx0/ped/issues/2) [\#3](https://github.com/swx0/ped/issues/3) [\#4](https://github.com/swx0/ped/issues/4) [\#5](https://github.com/swx0/ped/issues/5) [\#6](https://github.com/swx0/ped/issues/6)) diff --git a/docs/team/willcwx.md b/docs/team/willcwx.md new file mode 100644 index 00000000000..d95e837c24e --- /dev/null +++ b/docs/team/willcwx.md @@ -0,0 +1,98 @@ +--- +layout: page +title: William's Project Portfolio Page +--- + +### Project: Team Builder + +Team Builder is a desktop personal contacts book application used by the user to form a team for any event. The user interacts with it using a CLI, and it has a GUI created with JavaFX. + +Given below are my contributions to the project. + +* **Undo functionality**: + * Justification: + * Careless Users might want to undo their last command. + * Rather than finding the reversing action, they can just use `undo`. + * This is especially useful for users that accidentally use the `clear` command and would like to recover their contact list. + + * Highlights: + * Able to undo up to 10 last commands. + * Able to undo: `add, edit, delete, clear` + + * Credits: + * Momento Design Pattern + +* **Redo functionality**: + * Justification: + * Careless Users might want to redo their last undo. + * Rather than finding the reversing action, they can just use `redo`. + * This is especially useful for users that accidentally use the `undo` command after adding someone important and would like to recover their last contact. + + * Highlights: + * Able to redo up to 10 last commands. + + * Credits: + * Momento Design Pattern + +* **Testing**: + * Created tests for all new features implemented above. + +{::comment} + +* **New Feature**: `to be added soon` + * Justification: `to be added soon` + * Highlights: `to be added soon` + * Credits: `to be added soon` *{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}* + +{:/comment} + +* **Code contributed**: + * [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=WillCWX&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByNone&breakdown=true&since=2023-02-17&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&tabAuthor=WillCWX&tabRepo=AY2223S2-CS2103T-T17-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) + * ~2697 lines + +* **Project management**: + * Created issues: [\#26](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/26), [\#51](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/51), [\#54](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/54), [\#55](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/55), [\#56](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/56), [\#103](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/103), [\#104](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/104), [\#105](https://github.com/AY2223S2-CS2103T-T17-1/tp/issues/105) + * Created Demo v1.3 and v1.2 + +* **Documentation**: + * README: + * Added Badges and new UI.png + * Removed all references to AB-3 for TeamBuilder + * Added Acknowledgements for NUS AB-3 source code and + for the SE-EDU initiative. + * Added Installation guide + * Linked User guide + * Linked Developer guide and added contribution guidelines + * Added Authors and linked to their github + * Added futher acknowledgements for Microsoft Fluent-UI freeuse. + + * User Guide: + * Removed all references to AB-3 for TeamBuilder + * Added the sections `Undoing a command` and `Redoing an undo command` + * Created and implemented a narrative style from `About this guide` to `Deleting a contact` and also in `Undoing a command` and `Redoing an undo command`. + * Added multiple photos, some css stylings + * Added multiple `information`,`caution` and `tip` divisions for better style + + * Developer Guide: + * Created the entire implementation detail for `Undo/Redo feature` + * Mutiple UML models used, including class diagrams, sequence diagrams and an activity diagram. + * Added to the manual testing appendix + * Fixed links that were previously pointing to seedu + +* **Tools**: + * Integrated an existing plugin fully (CodeCov) on team fork + +{::comment} + +* **Community**: + * PRs reviewed (with non-trivial review comments): `to be added soon` *{[\#12](), [\#32](), [\#19](), [\#42]()}* + * Contributed to forum discussions (examples: `to be added soon`) + * Reported bugs and suggestions for other teams in the class (examples: `to be added soon`) + * Some parts of the history feature I added was adopted by several other class mates `to be added soon` + + * Integrated a third party library (Natty) to the project `to be added soon` + * Integrated a new Github plugin (CircleCI) to the team repo `to be added soon` + +_{you can add/remove categories in the list above}_ + +{:/comment} diff --git a/docs/tutorials/AboutUs.md b/docs/tutorials/AboutUs.md new file mode 100644 index 00000000000..7ba21dc3535 --- /dev/null +++ b/docs/tutorials/AboutUs.md @@ -0,0 +1,68 @@ +--- +layout: page +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` + +## Project team + +### John Doe + + + +[[homepage](http://www.comp.nus.edu.sg/~damithch)] +[[github](https://github.com/johndoe)] +[[portfolio](team/johndoe.md)] + +* Role: Project Advisor + +### Joshua Chiang + + + +[[github](http://github.com/ChickenChiang)] +[[portfolio](team/ChickenChiang.md)] + +* Role: Team Lead, Developer +* Responsibilities: UI + +### See Wei Xun + + + +[[github](http://github.com/swx0)] [[portfolio](team/swx0.md)] + +* Role: Developer +* Responsibilities: Data + +### Chen Jiarui + + + +[[github](http://github.com/chen-jerry-junior)] [[portfolio](team/chen-jerry-junior.md)] + +* Role: Developer +* Responsibilities: Data + +### Jean Doe + + + +[[github](http://github.com/johndoe)] +[[portfolio](team/johndoe.md)] + +* Role: Developer +* Responsibilities: Dev Ops + Threading + +### William Chau Wei Xuan + + + +[[github](http://github.com/willcwx)] +[[portfolio](team/willcwx.md)] + +* Role: Developer +* Responsibilities: Testing, Integration diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md index 880c701042f..d1060f6ab04 100644 --- a/docs/tutorials/AddRemark.md +++ b/docs/tutorials/AddRemark.md @@ -5,7 +5,7 @@ title: "Tutorial: Adding a command" Let's walk you through the implementation of a new command — `remark`. -This command allows users of the AddressBook application to add optional remarks to people in their address book and edit it if required. The command should have the following format: +This command allows users of the AddressBook application to add optional remarks to people in their TeamBuilder and edit it if required. The command should have the following format: `remark INDEX r/REMARK` (e.g., `remark 2 r/Likes baseball`) @@ -28,7 +28,7 @@ package seedu.address.logic.commands; import seedu.address.model.Model; /** - * Changes the remark of an existing person in the address book. + * Changes the remark of an existing person in the TeamBuilder. */ public class RemarkCommand extends Command { @@ -295,7 +295,7 @@ While the changes to code may be minimal, the test data will have to be updated
-:exclamation: You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause AddressBook to default to an empty address book! +:exclamation: You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause TeamBuilder to default to an empty TeamBuilder!
diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md index 4fb62a83ef6..767cdf46b6e 100644 --- a/docs/tutorials/TracingCode.md +++ b/docs/tutorials/TracingCode.md @@ -39,7 +39,7 @@ In our case, we would want to begin the tracing at the very point where the App -According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `seedu.address.logic.Logic`. +According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `teambuilder.logic.Logic`. @@ -48,7 +48,7 @@ According to the sequence diagram you saw earlier (and repeated above for refere :bulb: **Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
-A quick look at the `seedu.address.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for. +A quick look at the `teambuilder.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for. ```java public interface Logic { @@ -292,10 +292,10 @@ Here are some quick questions you can try to answer based on your execution path 2. Allow `delete` to remove more than one index at a time - 3. Save the address book in the CSV format instead + 3. Save the TeamBuilder in the CSV format instead 4. Add a new command 5. Add a new field to `Person` - 6. Add a new entity to the address book + 6. Add a new entity to the TeamBuilder 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/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java deleted file mode 100644 index 9c86b1fa6e4..00000000000 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ /dev/null @@ -1,23 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; - -import seedu.address.model.AddressBook; -import seedu.address.model.Model; - -/** - * Clears the address book. - */ -public class ClearCommand extends Command { - - public static final String COMMAND_WORD = "clear"; - public static final String MESSAGE_SUCCESS = "Address book has been cleared!"; - - - @Override - public CommandResult execute(Model model) { - requireNonNull(model); - model.setAddressBook(new AddressBook()); - 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/model/Model.java b/src/main/java/seedu/address/model/Model.java deleted file mode 100644 index d54df471c1f..00000000000 --- a/src/main/java/seedu/address/model/Model.java +++ /dev/null @@ -1,87 +0,0 @@ -package seedu.address.model; - -import java.nio.file.Path; -import java.util.function.Predicate; - -import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.model.person.Person; - -/** - * The API of the Model component. - */ -public interface Model { - /** {@code Predicate} that always evaluate to true */ - Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true; - - /** - * Replaces user prefs data with the data in {@code userPrefs}. - */ - void setUserPrefs(ReadOnlyUserPrefs userPrefs); - - /** - * Returns the user prefs. - */ - ReadOnlyUserPrefs getUserPrefs(); - - /** - * Returns the user prefs' GUI settings. - */ - GuiSettings getGuiSettings(); - - /** - * Sets the user prefs' GUI settings. - */ - void setGuiSettings(GuiSettings guiSettings); - - /** - * Returns the user prefs' address book file path. - */ - Path getAddressBookFilePath(); - - /** - * Sets the user prefs' address book file path. - */ - void setAddressBookFilePath(Path addressBookFilePath); - - /** - * Replaces address book data with the data in {@code addressBook}. - */ - void setAddressBook(ReadOnlyAddressBook addressBook); - - /** Returns the AddressBook */ - ReadOnlyAddressBook getAddressBook(); - - /** - * Returns true if a person with the same identity as {@code person} exists in the address book. - */ - boolean hasPerson(Person person); - - /** - * Deletes the given person. - * The person must exist in the address book. - */ - void deletePerson(Person target); - - /** - * Adds the given person. - * {@code person} must not already exist in the address book. - */ - void addPerson(Person person); - - /** - * Replaces the given person {@code target} with {@code editedPerson}. - * {@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. - */ - void setPerson(Person target, Person editedPerson); - - /** Returns an unmodifiable view of the filtered person list */ - ObservableList getFilteredPersonList(); - - /** - * Updates the filter of the filtered person list to filter by the given {@code predicate}. - * @throws NullPointerException if {@code predicate} is null. - */ - void updateFilteredPersonList(Predicate predicate); -} diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java deleted file mode 100644 index 86c1df298d7..00000000000 --- a/src/main/java/seedu/address/model/ModelManager.java +++ /dev/null @@ -1,150 +0,0 @@ -package seedu.address.model; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; - -import java.nio.file.Path; -import java.util.function.Predicate; -import java.util.logging.Logger; - -import javafx.collections.ObservableList; -import javafx.collections.transformation.FilteredList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; - -/** - * Represents the in-memory model of the address book data. - */ -public class ModelManager implements Model { - private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - - private final AddressBook addressBook; - private final UserPrefs userPrefs; - private final FilteredList filteredPersons; - - /** - * Initializes a ModelManager with the given addressBook and userPrefs. - */ - public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) { - requireAllNonNull(addressBook, userPrefs); - - logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs); - - this.addressBook = new AddressBook(addressBook); - this.userPrefs = new UserPrefs(userPrefs); - filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); - } - - public ModelManager() { - this(new AddressBook(), new UserPrefs()); - } - - //=========== UserPrefs ================================================================================== - - @Override - public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { - requireNonNull(userPrefs); - this.userPrefs.resetData(userPrefs); - } - - @Override - public ReadOnlyUserPrefs getUserPrefs() { - return userPrefs; - } - - @Override - public GuiSettings getGuiSettings() { - return userPrefs.getGuiSettings(); - } - - @Override - public void setGuiSettings(GuiSettings guiSettings) { - requireNonNull(guiSettings); - userPrefs.setGuiSettings(guiSettings); - } - - @Override - public Path getAddressBookFilePath() { - return userPrefs.getAddressBookFilePath(); - } - - @Override - public void setAddressBookFilePath(Path addressBookFilePath) { - requireNonNull(addressBookFilePath); - userPrefs.setAddressBookFilePath(addressBookFilePath); - } - - //=========== AddressBook ================================================================================ - - @Override - public void setAddressBook(ReadOnlyAddressBook addressBook) { - this.addressBook.resetData(addressBook); - } - - @Override - public ReadOnlyAddressBook getAddressBook() { - return addressBook; - } - - @Override - public boolean hasPerson(Person person) { - requireNonNull(person); - return addressBook.hasPerson(person); - } - - @Override - public void deletePerson(Person target) { - addressBook.removePerson(target); - } - - @Override - public void addPerson(Person person) { - addressBook.addPerson(person); - updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - } - - @Override - public void setPerson(Person target, Person editedPerson) { - requireAllNonNull(target, editedPerson); - - addressBook.setPerson(target, editedPerson); - } - - //=========== Filtered Person List Accessors ============================================================= - - /** - * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of - * {@code versionedAddressBook} - */ - @Override - public ObservableList getFilteredPersonList() { - return filteredPersons; - } - - @Override - public void updateFilteredPersonList(Predicate predicate) { - requireNonNull(predicate); - filteredPersons.setPredicate(predicate); - } - - @Override - public boolean equals(Object obj) { - // short circuit if same object - if (obj == this) { - return true; - } - - // instanceof handles nulls - if (!(obj instanceof ModelManager)) { - return false; - } - - // state check - ModelManager other = (ModelManager) obj; - return addressBook.equals(other.addressBook) - && userPrefs.equals(other.userPrefs) - && filteredPersons.equals(other.filteredPersons); - } - -} diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java deleted file mode 100644 index 6ddc2cd9a29..00000000000 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ /dev/null @@ -1,17 +0,0 @@ -package seedu.address.model; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; - -/** - * Unmodifiable view of an address book - */ -public interface ReadOnlyAddressBook { - - /** - * Returns an unmodifiable view of the persons list. - * This list will not contain any duplicate persons. - */ - ObservableList getPersonList(); - -} diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java deleted file mode 100644 index c9b5868427c..00000000000 --- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java +++ /dev/null @@ -1,31 +0,0 @@ -package seedu.address.model.person; - -import java.util.List; -import java.util.function.Predicate; - -import seedu.address.commons.util.StringUtil; - -/** - * Tests that a {@code Person}'s {@code Name} matches any of the keywords given. - */ -public class NameContainsKeywordsPredicate implements Predicate { - private final List keywords; - - public NameContainsKeywordsPredicate(List keywords) { - this.keywords = keywords; - } - - @Override - public boolean test(Person person) { - return keywords.stream() - .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls - && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check - } - -} 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/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java deleted file mode 100644 index 1806da4facf..00000000000 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.model.util; - -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - -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; - -/** - * 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 ReadOnlyAddressBook getSampleAddressBook() { - AddressBook sampleAb = new AddressBook(); - for (Person samplePerson : getSamplePersons()) { - sampleAb.addPerson(samplePerson); - } - return sampleAb; - } - - /** - * Returns a tag set containing the list of strings given. - */ - public static Set getTagSet(String... strings) { - return Arrays.stream(strings) - .map(Tag::new) - .collect(Collectors.toSet()); - } - -} diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java deleted file mode 100644 index 5efd834091d..00000000000 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.storage; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonRootName; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; - -/** - * An Immutable AddressBook that is serializable to JSON format. - */ -@JsonRootName(value = "addressbook") -class JsonSerializableAddressBook { - - public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; - - private final List persons = new ArrayList<>(); - - /** - * Constructs a {@code JsonSerializableAddressBook} with the given persons. - */ - @JsonCreator - public JsonSerializableAddressBook(@JsonProperty("persons") List persons) { - this.persons.addAll(persons); - } - - /** - * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use. - * - * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}. - */ - public JsonSerializableAddressBook(ReadOnlyAddressBook source) { - persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList())); - } - - /** - * Converts this address book into the model's {@code AddressBook} object. - * - * @throws IllegalValueException if there were any data constraints violated. - */ - public AddressBook toModelType() throws IllegalValueException { - AddressBook addressBook = new AddressBook(); - for (JsonAdaptedPerson jsonAdaptedPerson : persons) { - Person person = jsonAdaptedPerson.toModelType(); - if (addressBook.hasPerson(person)) { - throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON); - } - addressBook.addPerson(person); - } - return addressBook; - } - -} diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/teambuilder/AppParameters.java similarity index 93% rename from src/main/java/seedu/address/AppParameters.java rename to src/main/java/teambuilder/AppParameters.java index ab552c398f3..e4f250da65d 100644 --- a/src/main/java/seedu/address/AppParameters.java +++ b/src/main/java/teambuilder/AppParameters.java @@ -1,4 +1,4 @@ -package seedu.address; +package teambuilder; import java.nio.file.Path; import java.nio.file.Paths; @@ -7,8 +7,8 @@ import java.util.logging.Logger; import javafx.application.Application; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.util.FileUtil; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.util.FileUtil; /** * Represents the parsed command-line parameters given to the application. diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/teambuilder/Main.java similarity index 97% rename from src/main/java/seedu/address/Main.java rename to src/main/java/teambuilder/Main.java index 052a5068631..a8dff40d2ba 100644 --- a/src/main/java/seedu/address/Main.java +++ b/src/main/java/teambuilder/Main.java @@ -1,4 +1,4 @@ -package seedu.address; +package teambuilder; import javafx.application.Application; diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/teambuilder/MainApp.java similarity index 75% rename from src/main/java/seedu/address/MainApp.java rename to src/main/java/teambuilder/MainApp.java index 4133aaa0151..7682edc0996 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/teambuilder/MainApp.java @@ -1,4 +1,4 @@ -package seedu.address; +package teambuilder; import java.io.IOException; import java.nio.file.Path; @@ -7,36 +7,36 @@ import javafx.application.Application; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.Version; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.ConfigUtil; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; -import seedu.address.logic.LogicManager; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; -import seedu.address.model.util.SampleDataUtil; -import seedu.address.storage.AddressBookStorage; -import seedu.address.storage.JsonAddressBookStorage; -import seedu.address.storage.JsonUserPrefsStorage; -import seedu.address.storage.Storage; -import seedu.address.storage.StorageManager; -import seedu.address.storage.UserPrefsStorage; -import seedu.address.ui.Ui; -import seedu.address.ui.UiManager; +import teambuilder.commons.core.Config; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.core.Version; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.commons.util.ConfigUtil; +import teambuilder.commons.util.StringUtil; +import teambuilder.logic.Logic; +import teambuilder.logic.LogicManager; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.TeamBuilder; +import teambuilder.model.UserPrefs; +import teambuilder.model.util.SampleDataUtil; +import teambuilder.storage.JsonTeamBuilderStorage; +import teambuilder.storage.JsonUserPrefsStorage; +import teambuilder.storage.Storage; +import teambuilder.storage.StorageManager; +import teambuilder.storage.TeamBuilderStorage; +import teambuilder.storage.UserPrefsStorage; +import teambuilder.ui.Ui; +import teambuilder.ui.UiManager; /** * Runs the application. */ public class MainApp extends Application { - public static final Version VERSION = new Version(0, 2, 0, true); + public static final Version VERSION = new Version(1, 3, 0, true); private static final Logger logger = LogsCenter.getLogger(MainApp.class); @@ -56,7 +56,7 @@ public void init() throws Exception { UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath()); UserPrefs userPrefs = initPrefs(userPrefsStorage); - AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath()); + TeamBuilderStorage addressBookStorage = new JsonTeamBuilderStorage(userPrefs.getAddressBookFilePath()); storage = new StorageManager(addressBookStorage, userPrefsStorage); initLogging(config); @@ -69,13 +69,13 @@ public void init() throws Exception { } /** - * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found, - * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book. + * Returns a {@code ModelManager} with the data from {@code storage}'s TeamBuilder and {@code userPrefs}.
+ * The data from the sample TeamBuilder will be used instead if {@code storage}'s TeamBuilder is not found, + * or an empty TeamBuilder will be used instead if errors occur when reading {@code storage}'s TeamBuilder. */ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { - Optional addressBookOptional; - ReadOnlyAddressBook initialData; + Optional addressBookOptional; + ReadOnlyTeamBuilder initialData; try { addressBookOptional = storage.readAddressBook(); if (!addressBookOptional.isPresent()) { @@ -84,10 +84,10 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook); } catch (DataConversionException e) { logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + initialData = new TeamBuilder(); } catch (IOException e) { logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + initialData = new TeamBuilder(); } return new ModelManager(initialData, userPrefs); @@ -173,7 +173,7 @@ public void start(Stage primaryStage) { @Override public void stop() { - logger.info("============================ [ Stopping Address Book ] ============================="); + logger.info("============================ [ Stopping TeamBuilder ] ============================="); try { storage.saveUserPrefs(model.getUserPrefs()); } catch (IOException e) { diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/teambuilder/commons/core/Config.java similarity index 97% rename from src/main/java/seedu/address/commons/core/Config.java rename to src/main/java/teambuilder/commons/core/Config.java index 91145745521..ee99dee641d 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/teambuilder/commons/core/Config.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/teambuilder/commons/core/GuiSettings.java similarity index 98% rename from src/main/java/seedu/address/commons/core/GuiSettings.java rename to src/main/java/teambuilder/commons/core/GuiSettings.java index ba33653be67..b01d7e4dd8b 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/teambuilder/commons/core/GuiSettings.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; import java.awt.Point; import java.io.Serializable; diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/teambuilder/commons/core/LogsCenter.java similarity index 99% rename from src/main/java/seedu/address/commons/core/LogsCenter.java rename to src/main/java/teambuilder/commons/core/LogsCenter.java index 431e7185e76..524f651f741 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/teambuilder/commons/core/LogsCenter.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; import java.io.IOException; import java.util.Arrays; diff --git a/src/main/java/teambuilder/commons/core/Memento.java b/src/main/java/teambuilder/commons/core/Memento.java new file mode 100644 index 00000000000..0706ea7af8d --- /dev/null +++ b/src/main/java/teambuilder/commons/core/Memento.java @@ -0,0 +1,20 @@ +package teambuilder.commons.core; + +/** + * Represents a previous state of an originator + */ +public interface Memento { + /** + * Restores the state of the Originator to this memento's state. + * + * @return true if successful, false otherwise + */ + public boolean restore(); + + /** + * Retrieves the latest memento of this memento's originator + * + * @return The latest memento of this memento's originator. + */ + public Memento getUpdatedMemento(); +} diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/teambuilder/commons/core/Messages.java similarity index 58% rename from src/main/java/seedu/address/commons/core/Messages.java rename to src/main/java/teambuilder/commons/core/Messages.java index 1deb3a1e469..e9ee9edbbfa 100644 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/teambuilder/commons/core/Messages.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; /** * Container for user visible messages. @@ -9,5 +9,8 @@ public class Messages { 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_SORTING_ORDER = "Invalid sorting order, input \"desc\" or \"asc\""; + public static final String MESSAGE_INVALID_TEAM = "The team name provided is invalid"; + public static final String MESSAGE_INVALID_SORT_BY = "Invalid sort by"; } diff --git a/src/main/java/teambuilder/commons/core/Originator.java b/src/main/java/teambuilder/commons/core/Originator.java new file mode 100644 index 00000000000..c716950a929 --- /dev/null +++ b/src/main/java/teambuilder/commons/core/Originator.java @@ -0,0 +1,13 @@ +package teambuilder.commons.core; + +/** + * Represents a class with multiple possible states. + */ +public interface Originator { + /** + * Creates a momento with the current originator. + * + * @return The Momento containing the current originator and the desired state. + */ + public Memento save(); +} diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/teambuilder/commons/core/Version.java similarity index 98% rename from src/main/java/seedu/address/commons/core/Version.java rename to src/main/java/teambuilder/commons/core/Version.java index 12142ec1e32..f9c92d97af7 100644 --- a/src/main/java/seedu/address/commons/core/Version.java +++ b/src/main/java/teambuilder/commons/core/Version.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/teambuilder/commons/core/index/Index.java similarity index 97% rename from src/main/java/seedu/address/commons/core/index/Index.java rename to src/main/java/teambuilder/commons/core/index/Index.java index 19536439c09..2d478ea6e40 100644 --- a/src/main/java/seedu/address/commons/core/index/Index.java +++ b/src/main/java/teambuilder/commons/core/index/Index.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core.index; +package teambuilder.commons.core.index; /** * Represents a zero-based or one-based index. diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/teambuilder/commons/exceptions/DataConversionException.java similarity index 84% rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java rename to src/main/java/teambuilder/commons/exceptions/DataConversionException.java index 1f689bd8e3f..258302cd64a 100644 --- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java +++ b/src/main/java/teambuilder/commons/exceptions/DataConversionException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package teambuilder.commons.exceptions; /** * Represents an error during conversion of data from one format to another diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/teambuilder/commons/exceptions/IllegalValueException.java similarity index 93% rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java rename to src/main/java/teambuilder/commons/exceptions/IllegalValueException.java index 19124db485c..af2d03e6687 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/teambuilder/commons/exceptions/IllegalValueException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package teambuilder.commons.exceptions; /** * Signals that some given data does not fulfill some constraints. diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/teambuilder/commons/util/AppUtil.java similarity index 94% rename from src/main/java/seedu/address/commons/util/AppUtil.java rename to src/main/java/teambuilder/commons/util/AppUtil.java index 87aa89c0326..c16aaf3c467 100644 --- a/src/main/java/seedu/address/commons/util/AppUtil.java +++ b/src/main/java/teambuilder/commons/util/AppUtil.java @@ -1,9 +1,9 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static java.util.Objects.requireNonNull; import javafx.scene.image.Image; -import seedu.address.MainApp; +import teambuilder.MainApp; /** * A container for App specific utility functions diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/teambuilder/commons/util/CollectionUtil.java similarity index 96% rename from src/main/java/seedu/address/commons/util/CollectionUtil.java rename to src/main/java/teambuilder/commons/util/CollectionUtil.java index eafe4dfd681..1c4dcd16c8e 100644 --- a/src/main/java/seedu/address/commons/util/CollectionUtil.java +++ b/src/main/java/teambuilder/commons/util/CollectionUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/teambuilder/commons/util/ConfigUtil.java similarity index 77% rename from src/main/java/seedu/address/commons/util/ConfigUtil.java rename to src/main/java/teambuilder/commons/util/ConfigUtil.java index f7f8a2bd44c..00ab3cae982 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/teambuilder/commons/util/ConfigUtil.java @@ -1,11 +1,11 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.core.Config; -import seedu.address.commons.exceptions.DataConversionException; +import teambuilder.commons.core.Config; +import teambuilder.commons.exceptions.DataConversionException; /** * A class for accessing the Config File. diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/teambuilder/commons/util/FileUtil.java similarity index 98% rename from src/main/java/seedu/address/commons/util/FileUtil.java rename to src/main/java/teambuilder/commons/util/FileUtil.java index b1e2767cdd9..284437cca8c 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/teambuilder/commons/util/FileUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import java.io.IOException; import java.nio.file.Files; diff --git a/src/main/java/teambuilder/commons/util/HistoryUtil.java b/src/main/java/teambuilder/commons/util/HistoryUtil.java new file mode 100644 index 00000000000..ff3208c8fec --- /dev/null +++ b/src/main/java/teambuilder/commons/util/HistoryUtil.java @@ -0,0 +1,140 @@ +package teambuilder.commons.util; + +import static java.util.Objects.requireNonNull; + +import java.util.Optional; + +import teambuilder.commons.core.Memento; + +/** + * Represents the history of states in the app. + */ +public class HistoryUtil { + private static HistoryUtil singleton = new HistoryUtil(); + private static final int MAX_STATE = 10; + + private DescribedMemento[] undoHistory; + private DescribedMemento[] redoFuture; + private int currentNum = -1; + + private HistoryUtil() { + undoHistory = new DescribedMemento[MAX_STATE]; + redoFuture = new DescribedMemento[MAX_STATE]; + } + + private void incrementCurrentNum() { + currentNum = currentNum + 1 >= MAX_STATE ? 0 : currentNum + 1; + } + + private void decreaseCurrentNum() { + if (currentNum <= -1) { + currentNum = -1; + return; + } + // check wrap around + if (currentNum - 1 < 0 && undoHistory[MAX_STATE - 1] != null) { + currentNum = MAX_STATE - 1; + return; + } + + currentNum = currentNum - 1; + } + + /** + * Gives the single instance of HistoryUtil. + * + * @return The only instance of HistoryUtil. + */ + public static HistoryUtil getInstance() { + return singleton; + } + + /** + * Stores a past memento of the app and a description of the memento. + * Maximumn of 10 stored momentos at any time. + * + * @param memo The memento to be stored. + * @param desc The description of the memo. + */ + public void storePast(Memento memo, String desc) { + requireNonNull(memo); + requireNonNull(desc); + + DescribedMemento memoWithDesc = new DescribedMemento(memo, desc); + incrementCurrentNum(); + undoHistory[currentNum] = memoWithDesc; + redoFuture = new DescribedMemento[MAX_STATE]; + } + + /** + * Restores the app to its previous state. + * + * @return An Optional containing a string of the description of the state restored if successful, + * contains null otherwise. + */ + public Optional undo() { + if (currentNum <= -1) { + return Optional.ofNullable(null); + } + if (undoHistory[currentNum] == null) { + currentNum = -1; + return Optional.ofNullable(null); + } + + DescribedMemento mementoForUndo = undoHistory[currentNum]; + DescribedMemento mementoForRedo = mementoForUndo.getUpdatedMemento(); + boolean isSuccessful = mementoForUndo.restore(); + String descriptionUndo = mementoForUndo.desc; + undoHistory[currentNum] = null; + redoFuture[currentNum] = mementoForRedo; + + decreaseCurrentNum(); + return isSuccessful ? Optional.of(descriptionUndo) : Optional.ofNullable(null); + } + + /** + * Restores the app to its state before an undo. + * + * @return An Optional containing a string of the description of the state restored if successful, + * contains null otherwise. + */ + public Optional redo() { + incrementCurrentNum(); + + if (redoFuture[currentNum] == null) { + decreaseCurrentNum(); + return Optional.ofNullable(null); + } + + DescribedMemento mementoForRedo = redoFuture[currentNum]; + DescribedMemento mementoForUndo = mementoForRedo.getUpdatedMemento(); + boolean isSuccessful = mementoForRedo.restore(); + String descriptionRedo = mementoForRedo.desc; + undoHistory[currentNum] = mementoForUndo; + redoFuture[currentNum] = null; + + return isSuccessful ? Optional.of(descriptionRedo) : Optional.ofNullable(null); + } + + /** + * Wrapper class for a Memento and its description. + */ + private class DescribedMemento { + private Memento memento; + private String desc; + + private DescribedMemento(Memento memento, String desc) { + this.memento = memento; + this.desc = desc; + } + + private boolean restore() { + return memento.restore(); + } + + private DescribedMemento getUpdatedMemento() { + return new DescribedMemento(memento.getUpdatedMemento(), desc); + } + + } +} diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/teambuilder/commons/util/JsonUtil.java similarity index 97% rename from src/main/java/seedu/address/commons/util/JsonUtil.java rename to src/main/java/teambuilder/commons/util/JsonUtil.java index 8ef609f055d..f600e30bca5 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/teambuilder/commons/util/JsonUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static java.util.Objects.requireNonNull; @@ -20,8 +20,8 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.exceptions.DataConversionException; /** * Converts a Java object instance to JSON and vice versa diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/teambuilder/commons/util/StringUtil.java similarity index 95% rename from src/main/java/seedu/address/commons/util/StringUtil.java rename to src/main/java/teambuilder/commons/util/StringUtil.java index 61cc8c9a1cb..014bbee507f 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/teambuilder/commons/util/StringUtil.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static teambuilder.commons.util.AppUtil.checkArgument; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/teambuilder/logic/Logic.java similarity index 63% rename from src/main/java/seedu/address/logic/Logic.java rename to src/main/java/teambuilder/logic/Logic.java index 92cd8fa605a..f61d3abbe0e 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/teambuilder/logic/Logic.java @@ -1,14 +1,15 @@ -package seedu.address.logic; +package teambuilder.logic; import java.nio.file.Path; import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.logic.commands.CommandResult; -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 teambuilder.commons.core.GuiSettings; +import teambuilder.logic.commands.CommandResult; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; /** * API of the Logic component @@ -26,15 +27,15 @@ public interface Logic { /** * Returns the AddressBook. * - * @see seedu.address.model.Model#getAddressBook() + * @see teambuilder.model.Model#getTeamBuilder() */ - ReadOnlyAddressBook getAddressBook(); + ReadOnlyTeamBuilder getAddressBook(); /** Returns an unmodifiable view of the filtered list of persons */ ObservableList getFilteredPersonList(); /** - * Returns the user prefs' address book file path. + * Returns the user prefs' TeamBuilder file path. */ Path getAddressBookFilePath(); @@ -47,4 +48,7 @@ public interface Logic { * Set the user prefs' GUI settings. */ void setGuiSettings(GuiSettings guiSettings); + + ObservableList getFilteredTeamList(); + } diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/teambuilder/logic/LogicManager.java similarity index 62% rename from src/main/java/seedu/address/logic/LogicManager.java rename to src/main/java/teambuilder/logic/LogicManager.java index 9d9c6d15bdc..16324980ad5 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/teambuilder/logic/LogicManager.java @@ -1,21 +1,22 @@ -package seedu.address.logic; +package teambuilder.logic; import java.io.IOException; import java.nio.file.Path; import java.util.logging.Logger; import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.core.LogsCenter; -import seedu.address.logic.commands.Command; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.AddressBookParser; -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.storage.Storage; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.core.LogsCenter; +import teambuilder.logic.commands.Command; +import teambuilder.logic.commands.CommandResult; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.logic.parser.TeamBuilderParser; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.Model; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; +import teambuilder.storage.Storage; /** * The main LogicManager of the app. @@ -26,7 +27,7 @@ public class LogicManager implements Logic { private final Model model; private final Storage storage; - private final AddressBookParser addressBookParser; + private final TeamBuilderParser addressBookParser; /** * Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}. @@ -34,7 +35,7 @@ public class LogicManager implements Logic { public LogicManager(Model model, Storage storage) { this.model = model; this.storage = storage; - addressBookParser = new AddressBookParser(); + addressBookParser = new TeamBuilderParser(); } @Override @@ -46,7 +47,7 @@ public CommandResult execute(String commandText) throws CommandException, ParseE commandResult = command.execute(model); try { - storage.saveAddressBook(model.getAddressBook()); + storage.saveAddressBook(model.getTeamBuilder()); } catch (IOException ioe) { throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); } @@ -55,13 +56,13 @@ public CommandResult execute(String commandText) throws CommandException, ParseE } @Override - public ReadOnlyAddressBook getAddressBook() { - return model.getAddressBook(); + public ReadOnlyTeamBuilder getAddressBook() { + return model.getTeamBuilder(); } @Override public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); + return model.getSortedPersonList(); } @Override @@ -78,4 +79,9 @@ public GuiSettings getGuiSettings() { public void setGuiSettings(GuiSettings guiSettings) { model.setGuiSettings(guiSettings); } + + @Override + public ObservableList getFilteredTeamList() { + return model.getSortedTeamList(); + } } diff --git a/src/main/java/teambuilder/logic/commands/AddCommand.java b/src/main/java/teambuilder/logic/commands/AddCommand.java new file mode 100644 index 00000000000..63d527c8585 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/AddCommand.java @@ -0,0 +1,103 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; +import static teambuilder.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_EMAIL; +import static teambuilder.logic.parser.CliSyntax.PREFIX_MAJOR; +import static teambuilder.logic.parser.CliSyntax.PREFIX_NAME; +import static teambuilder.logic.parser.CliSyntax.PREFIX_PHONE; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.List; + +import teambuilder.commons.core.Memento; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.person.Person; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Team; + +/** + * Adds a person to the TeamBuilder. + */ +public class AddCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + // @formatter:off + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the TeamBuilder. " + + "Parameters: " + + PREFIX_NAME + "NAME " + + "[" + PREFIX_PHONE + "PHONE] " + + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_ADDRESS + "ADDRESS] " + + "[" + PREFIX_MAJOR + "MAJOR] " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example 1 : " + COMMAND_WORD + " " + + PREFIX_NAME + "John Doe\n" + + "Example 2 : " + COMMAND_WORD + " " + + PREFIX_NAME + "John Doe " + + PREFIX_PHONE + "98765432 " + + PREFIX_EMAIL + "johnd@example.com " + + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + + PREFIX_MAJOR + "Computer Science " + + PREFIX_TAG + "undergrad " + + PREFIX_TAG + "Java"; + + public static final String MESSAGE_SUCCESS = "New person added: %1$s"; + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the TeamBuilder"; + public static final String MESSAGE_TEAM_NOT_FOUND = "The team does not exist in the TeamBuilder"; + + 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); + } + + // throw exception if team tags not from existing teams + // TODO: fix teams checking. toAdd.getTeams() returns a list of teams + List teamList = model.getTeamList(); + Tag[] teamTags = new Tag[toAdd.getTeams().size()]; + toAdd.getTeams().toArray(teamTags); + for (Tag tag : teamTags) { + boolean isPresent = false; + for (Team team : teamList) { + if (tag.getName().equals(team.toString())) { + isPresent = true; + break; + } + } + if (!isPresent) { + throw new CommandException(MESSAGE_TEAM_NOT_FOUND); + } + } + + Memento old = model.save(); + HistoryUtil.getInstance().storePast(old, COMMAND_WORD + " " + toAdd); + + model.addPerson(toAdd); + model.updatePersonInTeams(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/teambuilder/logic/commands/ClearCommand.java b/src/main/java/teambuilder/logic/commands/ClearCommand.java new file mode 100644 index 00000000000..69645da07a8 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/ClearCommand.java @@ -0,0 +1,28 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; + +import teambuilder.commons.core.Memento; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.model.Model; +import teambuilder.model.TeamBuilder; + +/** + * Clears the TeamBuilder. + */ +public class ClearCommand extends Command { + + public static final String COMMAND_WORD = "clear"; + public static final String MESSAGE_SUCCESS = "TeamBuilder has been cleared!"; + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + + Memento old = model.save(); + HistoryUtil.getInstance().storePast(old, COMMAND_WORD); + + model.setTeamBuilder(new TeamBuilder()); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/teambuilder/logic/commands/Command.java similarity index 78% rename from src/main/java/seedu/address/logic/commands/Command.java rename to src/main/java/teambuilder/logic/commands/Command.java index 64f18992160..13e704d2b72 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/teambuilder/logic/commands/Command.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; /** * Represents a command with hidden internal logic and the ability to be executed. diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/teambuilder/logic/commands/CommandResult.java similarity index 97% rename from src/main/java/seedu/address/logic/commands/CommandResult.java rename to src/main/java/teambuilder/logic/commands/CommandResult.java index 92f900b7916..e24d5569c64 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/teambuilder/logic/commands/CommandResult.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/teambuilder/logic/commands/CreateCommand.java b/src/main/java/teambuilder/logic/commands/CreateCommand.java new file mode 100644 index 00000000000..2bf939ea9cf --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/CreateCommand.java @@ -0,0 +1,69 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAMDESC; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAMNAME; + +import teambuilder.commons.core.Memento; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.team.Team; + +/** + * Creates a team for TeamBuilder. + */ +public class CreateCommand extends Command { + + public static final String COMMAND_WORD = "create"; + + // @formatter:off + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Creates a new team. " + + "Parameters: " + + PREFIX_TEAMNAME + "TEAMNAME " + + PREFIX_TEAMDESC + "TEAMDESC " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_TEAMNAME + "Team A " + + PREFIX_TEAMDESC + "Team for upcoming hackathon " + + PREFIX_TAG + "Python " + + PREFIX_TAG + "ReactNative"; + + public static final String MESSAGE_SUCCESS = "New team created: %1$s"; + + public static final String MESSAGE_DUPLICATE_TEAM = "This team already exists in TeamBuilder"; + + private final Team toCreate; + + /** + * Creates an CreateCommand to add the specified + */ + public CreateCommand(Team team) { + requireNonNull(team); + toCreate = team; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasTeam(toCreate)) { + throw new CommandException(MESSAGE_DUPLICATE_TEAM); + } + Memento old = model.save(); + HistoryUtil.getInstance().storePast(old, COMMAND_WORD + " " + toCreate); + + model.addTeam(toCreate); + + return new CommandResult(String.format(MESSAGE_SUCCESS, toCreate)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof CreateCommand // instanceof handles nulls + && toCreate.equals(((CreateCommand) other).toCreate)); + } + +} diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/teambuilder/logic/commands/DeleteCommand.java similarity index 65% rename from src/main/java/seedu/address/logic/commands/DeleteCommand.java rename to src/main/java/teambuilder/logic/commands/DeleteCommand.java index 02fd256acba..f339267f754 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ b/src/main/java/teambuilder/logic/commands/DeleteCommand.java @@ -1,17 +1,19 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; import static java.util.Objects.requireNonNull; import java.util.List; -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.person.Person; +import teambuilder.commons.core.Memento; +import teambuilder.commons.core.Messages; +import teambuilder.commons.core.index.Index; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.person.Person; /** - * Deletes a person identified using it's displayed index from the address book. + * Deletes a person identified using it's displayed index from the TeamBuilder. */ public class DeleteCommand extends Command { @@ -19,8 +21,7 @@ public class DeleteCommand extends Command { public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes the person identified by the index number used in the displayed person list.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; + + "Parameters: INDEX (must be a positive integer)\n" + "Example: " + COMMAND_WORD + " 1"; public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; @@ -33,13 +34,18 @@ public DeleteCommand(Index targetIndex) { @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); + List lastShownList = model.getSortedPersonList(); if (targetIndex.getZeroBased() >= lastShownList.size()) { throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); } Person personToDelete = lastShownList.get(targetIndex.getZeroBased()); + + Memento old = model.save(); + HistoryUtil.getInstance().storePast(old, COMMAND_WORD + " " + personToDelete); + + model.removeFromAllTeams(personToDelete); model.deletePerson(personToDelete); return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); } @@ -48,6 +54,6 @@ public CommandResult execute(Model model) throws CommandException { public boolean equals(Object other) { return other == this // short circuit if same object || (other instanceof DeleteCommand // instanceof handles nulls - && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check + && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check } } diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/teambuilder/logic/commands/EditCommand.java similarity index 52% rename from src/main/java/seedu/address/logic/commands/EditCommand.java rename to src/main/java/teambuilder/logic/commands/EditCommand.java index 7e36114902f..4b906c884b2 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/teambuilder/logic/commands/EditCommand.java @@ -1,12 +1,15 @@ -package seedu.address.logic.commands; +package teambuilder.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 static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_EMAIL; +import static teambuilder.logic.parser.CliSyntax.PREFIX_MAJOR; +import static teambuilder.logic.parser.CliSyntax.PREFIX_NAME; +import static teambuilder.logic.parser.CliSyntax.PREFIX_PHONE; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAM; +import static teambuilder.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static teambuilder.model.Model.PREDICATE_SHOW_ALL_TEAMS; import java.util.Collections; import java.util.HashSet; @@ -14,25 +17,30 @@ 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.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 teambuilder.commons.core.Memento; +import teambuilder.commons.core.Messages; +import teambuilder.commons.core.index.Index; +import teambuilder.commons.util.CollectionUtil; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Team; /** - * Edits the details of an existing person in the address book. + * Edits the details of an existing person in the TeamBuilder. */ public class EditCommand extends Command { public static final String COMMAND_WORD = "edit"; + // @formatter:off 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. " + "Existing values will be overwritten by the input values.\n" @@ -41,14 +49,29 @@ public class EditCommand extends Command { + "[" + PREFIX_PHONE + "PHONE] " + "[" + PREFIX_EMAIL + "EMAIL] " + "[" + PREFIX_ADDRESS + "ADDRESS] " - + "[" + PREFIX_TAG + "TAG]...\n" + + "[" + PREFIX_MAJOR + "MAJOR] " + + "[" + PREFIX_TAG + "TAG] " + + "[" + PREFIX_TEAM + "TEAM]...\n" + "Example: " + COMMAND_WORD + " 1 " + PREFIX_PHONE + "91234567 " + PREFIX_EMAIL + "johndoe@example.com"; + // @formatter:on public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %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_NOT_EDITED = "At least one field to edit must be provided.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_NAME + "NAME] " + + "[" + PREFIX_PHONE + "PHONE] " + + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_ADDRESS + "ADDRESS] " + + "[" + PREFIX_MAJOR + "MAJOR] " + + "[" + PREFIX_TAG + "TAG] " + + "[" + PREFIX_TEAM + "TEAM]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_PHONE + "91234567 " + + PREFIX_EMAIL + "johndoe@example.com"; + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the TeamBuilder."; + public static final String MESSAGE_TEAM_NOT_FOUND = "The team does not exist in the TeamBuilder"; private final Index index; private final EditPersonDescriptor editPersonDescriptor; @@ -68,7 +91,7 @@ public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) { @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); + List lastShownList = model.getSortedPersonList(); if (index.getZeroBased() >= lastShownList.size()) { throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); @@ -81,14 +104,45 @@ public CommandResult execute(Model model) throws CommandException { throw new CommandException(MESSAGE_DUPLICATE_PERSON); } + // throw exception if team tags not from existing teams + List teamList = model.getTeamList(); + Object[] teamTags = editedPerson.getTeams().toArray(); + for (Object tag : teamTags) { + Tag castedTag = (Tag) tag; + boolean isPresent = false; + for (Team team : teamList) { + if (castedTag.getName().equals(team.toString())) { + isPresent = true; + break; + } + } + if (!isPresent) { + throw new CommandException(MESSAGE_TEAM_NOT_FOUND); + } + } + + Memento old = model.save(); + HistoryUtil.getInstance().storePast(old, COMMAND_WORD + " " + editedPerson); + model.setPerson(personToEdit, editedPerson); + if (!personToEdit.getName().equals(editedPerson.getName())) { + Person deletusPerson = createTeamlessPerson(personToEdit); + model.updatePersonInTeams(deletusPerson); + } + model.updatePersonInTeams(editedPerson); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + model.updateFilteredTeamList(PREDICATE_SHOW_ALL_TEAMS); return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); } + private Person createTeamlessPerson(Person personToEdit) { + return new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), + personToEdit.getAddress(), personToEdit.getMajor(), personToEdit.getTags(), new HashSet<>()); + } + /** - * Creates and returns a {@code Person} with the details of {@code personToEdit} - * edited with {@code editPersonDescriptor}. + * Creates and returns a {@code Person} with the details of {@code personToEdit} edited with + * {@code editPersonDescriptor}. */ private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) { assert personToEdit != null; @@ -97,9 +151,12 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); + Major updatedMajor = editPersonDescriptor.getMajor().orElse(personToEdit.getMajor()); Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); + Set updatedTeams = editPersonDescriptor.getTeams().orElse(personToEdit.getTeams()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedMajor, updatedTags, + updatedTeams); } @Override @@ -116,40 +173,43 @@ public boolean equals(Object other) { // state check EditCommand e = (EditCommand) other; - return index.equals(e.index) - && editPersonDescriptor.equals(e.editPersonDescriptor); + return index.equals(e.index) && editPersonDescriptor.equals(e.editPersonDescriptor); } /** - * 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 person with. Each non-empty field value will replace the corresponding field value + * of the person. */ public static class EditPersonDescriptor { private Name name; private Phone phone; private Email email; private Address address; + private Major major; private Set tags; + private Set teams; - public EditPersonDescriptor() {} + public EditPersonDescriptor() { + } /** - * Copy constructor. - * A defensive copy of {@code tags} is used internally. + * Copy constructor. A defensive copy of {@code tags} is used internally. */ public EditPersonDescriptor(EditPersonDescriptor toCopy) { setName(toCopy.name); setPhone(toCopy.phone); setEmail(toCopy.email); setAddress(toCopy.address); + setMajor(toCopy.major); setTags(toCopy.tags); + setTeams(toCopy.teams); } /** * Returns true if at least one field is edited. */ public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); + return CollectionUtil.isAnyNonNull(name, phone, email, address, major, tags, teams); } public void setName(Name name) { @@ -184,23 +244,44 @@ public Optional
getAddress() { return Optional.ofNullable(address); } + public void setMajor(Major major) { + this.major = major; + } + + public Optional getMajor() { + return Optional.ofNullable(major); + } + /** - * Sets {@code tags} to this object's {@code tags}. - * A defensive copy of {@code tags} is used internally. + * Sets {@code tags} to this object's {@code tags}. A defensive copy of {@code tags} is used internally. */ public void setTags(Set tags) { this.tags = (tags != null) ? new HashSet<>(tags) : null; } /** - * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} - * if modification is attempted. - * Returns {@code Optional#empty()} if {@code tags} is null. + * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} if modification is + * attempted. Returns {@code Optional#empty()} if {@code tags} is null. */ public Optional> getTags() { return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); } + /** + * Sets {@code teams} to this object's {@code teams}. A defensive copy of {@code teams} is used internally. + */ + public void setTeams(Set teams) { + this.teams = (teams != null) ? new HashSet<>(teams) : null; + } + + /** + * Returns an unmodifiable team tag set, which throws {@code UnsupportedOperationException} if modification is + * attempted. Returns {@code Optional#empty()} if {@code teams} is null. + */ + public Optional> getTeams() { + return (teams != null) ? Optional.of(Collections.unmodifiableSet(teams)) : Optional.empty(); + } + @Override public boolean equals(Object other) { // short circuit if same object @@ -216,11 +297,15 @@ public boolean equals(Object other) { // state check EditPersonDescriptor e = (EditPersonDescriptor) other; + // @formatter:off return getName().equals(e.getName()) && getPhone().equals(e.getPhone()) && getEmail().equals(e.getEmail()) && getAddress().equals(e.getAddress()) + && getMajor().equals(e.getMajor()) + && getTeams().equals(e.getTeams()) && getTags().equals(e.getTags()); + // @formatter:on } } } diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/teambuilder/logic/commands/ExitCommand.java similarity index 75% rename from src/main/java/seedu/address/logic/commands/ExitCommand.java rename to src/main/java/teambuilder/logic/commands/ExitCommand.java index 3dd85a8ba90..e29267fa454 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/teambuilder/logic/commands/ExitCommand.java @@ -1,6 +1,6 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; -import seedu.address.model.Model; +import teambuilder.model.Model; /** * Terminates the program. @@ -9,7 +9,7 @@ public class ExitCommand extends Command { public static final String COMMAND_WORD = "exit"; - public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ..."; + public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting TeamBuilder as requested ..."; @Override public CommandResult execute(Model model) { diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/teambuilder/logic/commands/FindCommand.java similarity index 54% rename from src/main/java/seedu/address/logic/commands/FindCommand.java rename to src/main/java/teambuilder/logic/commands/FindCommand.java index d6b19b0a0de..ff1347a5562 100644 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ b/src/main/java/teambuilder/logic/commands/FindCommand.java @@ -1,27 +1,29 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; import static java.util.Objects.requireNonNull; -import seedu.address.commons.core.Messages; -import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import teambuilder.commons.core.Messages; +import teambuilder.model.Model; +import teambuilder.model.person.PersonContainsKeywordsPredicate; /** - * Finds and lists all persons in address book whose name contains any of the argument keywords. + * Finds and lists all persons in TeamBuilder whose name contains any of 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 " - + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons with the specified name or " + + "major or tag (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 + " alice\n" + + "Example: " + COMMAND_WORD + " computer science\n" + + "Example: " + COMMAND_WORD + " java"; - private final NameContainsKeywordsPredicate predicate; + private final PersonContainsKeywordsPredicate predicate; - public FindCommand(NameContainsKeywordsPredicate predicate) { + public FindCommand(PersonContainsKeywordsPredicate predicate) { this.predicate = predicate; } @@ -30,7 +32,7 @@ public CommandResult execute(Model model) { requireNonNull(model); model.updateFilteredPersonList(predicate); return new CommandResult( - String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size())); + String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getSortedPersonList().size())); } @Override diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/teambuilder/logic/commands/HelpCommand.java similarity index 88% rename from src/main/java/seedu/address/logic/commands/HelpCommand.java rename to src/main/java/teambuilder/logic/commands/HelpCommand.java index bf824f91bd0..ca1d12f3998 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/teambuilder/logic/commands/HelpCommand.java @@ -1,6 +1,6 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; -import seedu.address.model.Model; +import teambuilder.model.Model; /** * Format full help instructions for every command for display. diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/teambuilder/logic/commands/ListCommand.java similarity index 69% rename from src/main/java/seedu/address/logic/commands/ListCommand.java rename to src/main/java/teambuilder/logic/commands/ListCommand.java index 84be6ad2596..0d9fd9884f7 100644 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ b/src/main/java/teambuilder/logic/commands/ListCommand.java @@ -1,12 +1,12 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static teambuilder.model.Model.PREDICATE_SHOW_ALL_PERSONS; -import seedu.address.model.Model; +import teambuilder.model.Model; /** - * Lists all persons in the address book to the user. + * Lists all persons in the TeamBuilder to the user. */ public class ListCommand extends Command { diff --git a/src/main/java/teambuilder/logic/commands/RedoCommand.java b/src/main/java/teambuilder/logic/commands/RedoCommand.java new file mode 100644 index 00000000000..5da4de97c90 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/RedoCommand.java @@ -0,0 +1,38 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.Optional; + +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; + +/** + * Redoes a command that was undone. + */ +public class RedoCommand extends Command { + + public static final String COMMAND_WORD = "redo"; + public static final String MESSAGE_SUCCESS = "Redone: "; + public static final String MESSAGE_FAILURE = "Unable to redo last command"; + + private final HistoryUtil history = HistoryUtil.getInstance(); + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + Optional description = history.redo(); + if (!description.isPresent()) { + return new CommandResult(MESSAGE_FAILURE); + } + + return new CommandResult(MESSAGE_SUCCESS + description.get()); + } + + @Override + public boolean equals(Object other) { + return other == this; // All undo are different. + } +} diff --git a/src/main/java/teambuilder/logic/commands/RemoveCommand.java b/src/main/java/teambuilder/logic/commands/RemoveCommand.java new file mode 100644 index 00000000000..584dbcf28d3 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/RemoveCommand.java @@ -0,0 +1,106 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; +import static teambuilder.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javafx.collections.ObservableList; +import teambuilder.commons.core.Memento; +import teambuilder.commons.core.Messages; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.person.Person; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +/** + * Removes a team identified using its name from the TeamBuilder. + */ +public class RemoveCommand extends Command { + public static final String COMMAND_WORD = "remove"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Removes the team identified by its name.\n" + + "Parameters: TEAM_NAME\n" + "Example: " + COMMAND_WORD + " TeamA"; + + public static final String MESSAGE_DELETE_TEAM_SUCCESS = "Removed Team: %1$s"; + + private final TeamName targetName; + + public RemoveCommand(TeamName targetName) { + this.targetName = targetName; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getTeamList(); + Team teamToDelete = null; + + for (Team team : lastShownList) { + if (team.getName().equals(targetName)) { + teamToDelete = team; + break; + } + } + + if (teamToDelete == null) { + throw new CommandException(Messages.MESSAGE_INVALID_TEAM); + } + + Memento old = model.save(); + HistoryUtil.getInstance().storePast(old, COMMAND_WORD + " " + teamToDelete); + + Tag teamTag = getTeamTag(teamToDelete); + deleteMembersTeamTag(model, teamTag); + + model.deleteTeam(teamToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_TEAM_SUCCESS, teamToDelete)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof RemoveCommand // instanceof handles nulls + && targetName.equals(((RemoveCommand) other).targetName)); // state check + } + + /** + * Creates and returns a {@code Person} with the details of {@code teamMember} edited with + * {@code the team tag deleted}. + */ + private static Person createEditedPerson(Person teamMember, Tag teamTagToDelete) { + assert teamMember != null; + + Set teamTags = teamMember.getTeams(); + HashSet updatedTeamTag = new HashSet<>(); + updatedTeamTag.addAll(teamTags); + updatedTeamTag.remove(teamTagToDelete); + + return new Person(teamMember.getName(), teamMember.getPhone(), teamMember.getEmail(), teamMember.getAddress(), + teamMember.getMajor(), teamMember.getTags(), updatedTeamTag); + } + + private Tag getTeamTag(Team team) { + return new Tag(team.getName().toString()); + } + + private boolean deleteMembersTeamTag(Model model, Tag teamTag) { + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + ObservableList members = model.getSortedPersonList(); + for (int i = 0; i < members.size(); i++) { + Person member = members.get(i); + + if (member.getTeams().contains(teamTag)) { + Person updatedPerson = createEditedPerson(member, teamTag); + model.setPerson(member, updatedPerson); + } + } + + return true; + } +} diff --git a/src/main/java/teambuilder/logic/commands/ShowCommand.java b/src/main/java/teambuilder/logic/commands/ShowCommand.java new file mode 100644 index 00000000000..404acffffc8 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/ShowCommand.java @@ -0,0 +1,46 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; + +import teambuilder.commons.core.Messages; +import teambuilder.model.Model; +import teambuilder.model.person.TeamContainsKeywordsPredicate; + +/** + * Finds and lists all persons in the personList whose team tag contains any of the argument keywords. + * Keyword matching is case-insensitive. + */ +public class ShowCommand extends Command { + + public static final String COMMAND_WORD = "show"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Show all person who are in the specified team " + + "and displays them as a list with index numbers.\n" + + "Parameters: TEAM_NAME\n" + + "Example: " + COMMAND_WORD + " TeamA"; + + private final TeamContainsKeywordsPredicate predicate; + + /** + * Initializes a ShowCommand with the given predicate. + */ + public ShowCommand(TeamContainsKeywordsPredicate predicate) { + requireNonNull(predicate); + this.predicate = predicate; + } + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredPersonList(predicate); + return new CommandResult( + String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getSortedPersonList().size())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ShowCommand // instanceof handles nulls + && predicate.equals(((ShowCommand) other).predicate)); // state check + } +} diff --git a/src/main/java/teambuilder/logic/commands/SortCommand.java b/src/main/java/teambuilder/logic/commands/SortCommand.java new file mode 100644 index 00000000000..704763958e1 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/SortCommand.java @@ -0,0 +1,101 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.Comparator; + +import teambuilder.commons.core.Messages; +import teambuilder.logic.commands.enums.SortBy; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.person.Person; + +/** + * Sorts all persons in the TeamBuilder. + */ +public class SortCommand extends Command { + public static final String COMMAND_WORD = "sort"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Sorts all persons according to specified order " + + "(ascending or descending) and sort by (both case-insensitive), " + + "displays them as a list with index numbers.\n" + + "Parameters: ORDER SORT_BY\n" + + "Example: " + COMMAND_WORD + " asc tcount\n" + + "Example: " + COMMAND_WORD + " desc tcount\n"; + + public static final String MESSAGE_SUCCESS = "Sorted all persons."; + private final String order; + private final String sortByString; + private SortBy sortBy; + + /** + * Constructor for SortCommand + */ + public SortCommand(String order, String sortByString) { + requireNonNull(order); + requireNonNull(sortByString); + + this.order = order; + this.sortByString = sortByString; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (!checkOrder()) { + throw new CommandException(Messages.MESSAGE_INVALID_SORTING_ORDER); + } + + if (!processSortBy()) { + throw new CommandException(Messages.MESSAGE_INVALID_SORT_BY); + } + + switch (sortBy) { + case TAG_COUNT: + Comparator comparator = Comparator.comparingInt(Person::getNumTags); + + if (order.equals("desc")) { + comparator = comparator.reversed(); + } + + model.updateSortPerson(comparator); + break; + default: + break; + } + + return new CommandResult(MESSAGE_SUCCESS); + } + + /* Helper function to process sort by */ + private boolean processSortBy() { + if (sortByString.equals("tcount")) { + sortBy = SortBy.TAG_COUNT; + return true; + } + return false; + } + + private boolean checkOrder() { + return order.equals("desc") || order.equals("asc"); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof SortCommand)) { + return false; + } + + // state check + SortCommand e = (SortCommand) other; + return order.equals(e.order) + && sortByString.equals(e.sortByString); + } +} diff --git a/src/main/java/teambuilder/logic/commands/UndoCommand.java b/src/main/java/teambuilder/logic/commands/UndoCommand.java new file mode 100644 index 00000000000..99336081380 --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/UndoCommand.java @@ -0,0 +1,37 @@ +package teambuilder.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.Optional; + +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; + +/** + * Undos a previous modifying command that resulted in change. + */ +public class UndoCommand extends Command { + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_SUCCESS = "Undid: "; + public static final String MESSAGE_FAILURE = "Unable to undo last command"; + + private final HistoryUtil history = HistoryUtil.getInstance(); + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + Optional description = history.undo(); + if (!description.isPresent()) { + return new CommandResult(MESSAGE_FAILURE); + } + + return new CommandResult(MESSAGE_SUCCESS + description.get()); + }; + + @Override + public boolean equals(Object other) { + return other == this; // All undo are different. + } +} diff --git a/src/main/java/teambuilder/logic/commands/enums/SortBy.java b/src/main/java/teambuilder/logic/commands/enums/SortBy.java new file mode 100644 index 00000000000..8c24452450b --- /dev/null +++ b/src/main/java/teambuilder/logic/commands/enums/SortBy.java @@ -0,0 +1,8 @@ +package teambuilder.logic.commands.enums; + +/** + * Enum of criteria to sort persons list + */ +public enum SortBy { + TAG_COUNT +} diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/teambuilder/logic/commands/exceptions/CommandException.java similarity index 74% rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java rename to src/main/java/teambuilder/logic/commands/exceptions/CommandException.java index a16bd14f2cd..63531ad6a5a 100644 --- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java +++ b/src/main/java/teambuilder/logic/commands/exceptions/CommandException.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands.exceptions; +package teambuilder.logic.commands.exceptions; /** - * Represents an error which occurs during execution of a {@link Command}. + * Represents an error which occurs during execution of a Command. */ public class CommandException extends Exception { public CommandException(String message) { diff --git a/src/main/java/teambuilder/logic/parser/AddCommandParser.java b/src/main/java/teambuilder/logic/parser/AddCommandParser.java new file mode 100644 index 00000000000..8d7e14cb4ee --- /dev/null +++ b/src/main/java/teambuilder/logic/parser/AddCommandParser.java @@ -0,0 +1,74 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_EMAIL; +import static teambuilder.logic.parser.CliSyntax.PREFIX_MAJOR; +import static teambuilder.logic.parser.CliSyntax.PREFIX_NAME; +import static teambuilder.logic.parser.CliSyntax.PREFIX_PHONE; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAM; + +import java.util.Set; +import java.util.stream.Stream; + +import teambuilder.logic.commands.AddCommand; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.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_MAJOR, PREFIX_TAG, PREFIX_TEAM); + + if (!arePrefixesPresent(argMultimap, PREFIX_NAME) + || !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 = argMultimap.getValue(PREFIX_PHONE).isPresent() + ? ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()) + : Phone.getEmptyPhone(); + Email email = argMultimap.getValue(PREFIX_EMAIL).isPresent() + ? ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()) + : Email.getEmptyEmail(); + Address address = argMultimap.getValue(PREFIX_ADDRESS).isPresent() + ? ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()) + : Address.getEmptyAddress(); + Major major = argMultimap.getValue(PREFIX_MAJOR).isPresent() + ? ParserUtil.parseMajor(argMultimap.getValue(PREFIX_MAJOR).get()) + : Major.getEmptyMajor(); + Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); + Set teamList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TEAM)); + + Person person = new Person(name, phone, email, address, major, tagList, teamList); + + 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/ArgumentMultimap.java b/src/main/java/teambuilder/logic/parser/ArgumentMultimap.java similarity index 98% rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java rename to src/main/java/teambuilder/logic/parser/ArgumentMultimap.java index 954c8e18f8e..41d82cd32b3 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java +++ b/src/main/java/teambuilder/logic/parser/ArgumentMultimap.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/teambuilder/logic/parser/ArgumentTokenizer.java similarity index 99% rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java rename to src/main/java/teambuilder/logic/parser/ArgumentTokenizer.java index 5c9aebfa488..a4c872fd4c3 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java +++ b/src/main/java/teambuilder/logic/parser/ArgumentTokenizer.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/teambuilder/logic/parser/CliSyntax.java similarity index 61% rename from src/main/java/seedu/address/logic/parser/CliSyntax.java rename to src/main/java/teambuilder/logic/parser/CliSyntax.java index 75b1a9bf119..8e63c1cbe06 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/teambuilder/logic/parser/CliSyntax.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; /** * Contains Command Line Interface (CLI) syntax definitions common to multiple commands @@ -10,6 +10,10 @@ public class CliSyntax { public static final Prefix PREFIX_PHONE = new Prefix("p/"); public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); + public static final Prefix PREFIX_MAJOR = new Prefix("m/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); + public static final Prefix PREFIX_TEAM = new Prefix("T/"); + public static final Prefix PREFIX_TEAMNAME = new Prefix("tn/"); + public static final Prefix PREFIX_TEAMDESC = new Prefix("td/"); } diff --git a/src/main/java/teambuilder/logic/parser/CreateCommandParser.java b/src/main/java/teambuilder/logic/parser/CreateCommandParser.java new file mode 100644 index 00000000000..792c420f246 --- /dev/null +++ b/src/main/java/teambuilder/logic/parser/CreateCommandParser.java @@ -0,0 +1,53 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAMDESC; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAMNAME; + +import java.util.Set; +import java.util.stream.Stream; + +import teambuilder.logic.commands.CreateCommand; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +/** + * Parses input arguments and creates a new AddCommand object + */ +public class CreateCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the CreateCommand + * and returns an CreateCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public CreateCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_TEAMNAME, PREFIX_TEAMDESC, PREFIX_TAG); + + if (!arePrefixesPresent(argMultimap, PREFIX_TEAMNAME, PREFIX_TEAMDESC) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CreateCommand.MESSAGE_USAGE)); + } + + TeamName teamName = ParserUtil.parseTeamName(argMultimap.getValue(PREFIX_TEAMNAME).get()); + Desc teamDesc = ParserUtil.parseTeamDesc(argMultimap.getValue(PREFIX_TEAMDESC).get()); + Set skillTags = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); + + Team team = new Team(teamName, teamDesc, skillTags); + + return new CreateCommand(team); + } + + /** + * 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/DeleteCommandParser.java b/src/main/java/teambuilder/logic/parser/DeleteCommandParser.java similarity index 61% rename from src/main/java/seedu/address/logic/parser/DeleteCommandParser.java rename to src/main/java/teambuilder/logic/parser/DeleteCommandParser.java index 522b93081cc..6b682f0ae96 100644 --- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java +++ b/src/main/java/teambuilder/logic/parser/DeleteCommandParser.java @@ -1,10 +1,10 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import seedu.address.commons.core.index.Index; -import seedu.address.logic.commands.DeleteCommand; -import seedu.address.logic.parser.exceptions.ParseException; +import teambuilder.commons.core.index.Index; +import teambuilder.logic.commands.DeleteCommand; +import teambuilder.logic.parser.exceptions.ParseException; /** * Parses input arguments and creates a new DeleteCommand object @@ -22,7 +22,8 @@ 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(pe.getMessage() + "\n" + MESSAGE_INVALID_COMMAND_FORMAT, + DeleteCommand.MESSAGE_USAGE), pe); } } diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/teambuilder/logic/parser/EditCommandParser.java similarity index 66% rename from src/main/java/seedu/address/logic/parser/EditCommandParser.java rename to src/main/java/teambuilder/logic/parser/EditCommandParser.java index 845644b7dea..60df4aea308 100644 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ b/src/main/java/teambuilder/logic/parser/EditCommandParser.java @@ -1,23 +1,25 @@ -package seedu.address.logic.parser; +package teambuilder.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.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 static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_EMAIL; +import static teambuilder.logic.parser.CliSyntax.PREFIX_MAJOR; +import static teambuilder.logic.parser.CliSyntax.PREFIX_NAME; +import static teambuilder.logic.parser.CliSyntax.PREFIX_PHONE; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAM; 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.parser.exceptions.ParseException; -import seedu.address.model.tag.Tag; +import teambuilder.commons.core.index.Index; +import teambuilder.logic.commands.EditCommand; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.tag.Tag; /** * Parses input arguments and creates a new EditCommand object @@ -32,14 +34,16 @@ 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_PHONE, PREFIX_EMAIL, + PREFIX_ADDRESS, PREFIX_MAJOR, PREFIX_TAG, PREFIX_TEAM); 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(pe.getMessage() + "\n" + + MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); } EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor(); @@ -55,7 +59,11 @@ public EditCommand parse(String args) throws ParseException { if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); } + if (argMultimap.getValue(PREFIX_MAJOR).isPresent()) { + editPersonDescriptor.setMajor(ParserUtil.parseMajor(argMultimap.getValue(PREFIX_MAJOR).get())); + } parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); + parseTagsForEdit(argMultimap.getAllValues(PREFIX_TEAM)).ifPresent(editPersonDescriptor::setTeams); if (!editPersonDescriptor.isAnyFieldEdited()) { throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/teambuilder/logic/parser/FindCommandParser.java similarity index 66% rename from src/main/java/seedu/address/logic/parser/FindCommandParser.java rename to src/main/java/teambuilder/logic/parser/FindCommandParser.java index 4fb71f23103..fd556c1b312 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/teambuilder/logic/parser/FindCommandParser.java @@ -1,12 +1,12 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import java.util.Arrays; -import seedu.address.logic.commands.FindCommand; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import teambuilder.logic.commands.FindCommand; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.person.PersonContainsKeywordsPredicate; /** * Parses input arguments and creates a new FindCommand object @@ -27,7 +27,7 @@ public FindCommand parse(String args) throws ParseException { String[] nameKeywords = trimmedArgs.split("\\s+"); - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); + return new FindCommand(new PersonContainsKeywordsPredicate(Arrays.asList(nameKeywords))); } } diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/teambuilder/logic/parser/Parser.java similarity index 72% rename from src/main/java/seedu/address/logic/parser/Parser.java rename to src/main/java/teambuilder/logic/parser/Parser.java index d6551ad8e3f..10be01551be 100644 --- a/src/main/java/seedu/address/logic/parser/Parser.java +++ b/src/main/java/teambuilder/logic/parser/Parser.java @@ -1,7 +1,7 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; -import seedu.address.logic.commands.Command; -import seedu.address.logic.parser.exceptions.ParseException; +import teambuilder.logic.commands.Command; +import teambuilder.logic.parser.exceptions.ParseException; /** * Represents a Parser that is able to parse user input into a {@code Command} of type {@code T}. diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/teambuilder/logic/parser/ParserUtil.java similarity index 62% rename from src/main/java/seedu/address/logic/parser/ParserUtil.java rename to src/main/java/teambuilder/logic/parser/ParserUtil.java index b117acb9c55..0a40720f94c 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/teambuilder/logic/parser/ParserUtil.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; import static java.util.Objects.requireNonNull; @@ -6,14 +6,18 @@ import java.util.HashSet; import java.util.Set; -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 teambuilder.commons.core.index.Index; +import teambuilder.commons.util.StringUtil; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; /** * Contains utility methods used for parsing strings in the various *Parser classes. @@ -62,7 +66,7 @@ public static Phone parsePhone(String phone) throws ParseException { if (!Phone.isValidPhone(trimmedPhone)) { throw new ParseException(Phone.MESSAGE_CONSTRAINTS); } - return new Phone(trimmedPhone); + return Phone.of(trimmedPhone); } /** @@ -77,7 +81,7 @@ public static Address parseAddress(String address) throws ParseException { if (!Address.isValidAddress(trimmedAddress)) { throw new ParseException(Address.MESSAGE_CONSTRAINTS); } - return new Address(trimmedAddress); + return Address.of(trimmedAddress); } /** @@ -92,7 +96,22 @@ public static Email parseEmail(String email) throws ParseException { if (!Email.isValidEmail(trimmedEmail)) { throw new ParseException(Email.MESSAGE_CONSTRAINTS); } - return new Email(trimmedEmail); + return Email.of(trimmedEmail); + } + + /** + * Parses a {@code String major} into an {@code Major}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code major} is invalid. + */ + public static Major parseMajor(String major) throws ParseException { + requireNonNull(major); + String trimmedMajor = major.trim(); + if (!Major.isValidMajor(trimmedMajor)) { + throw new ParseException(Major.MESSAGE_CONSTRAINTS); + } + return Major.of(trimmedMajor); } /** @@ -121,4 +140,35 @@ public static Set parseTags(Collection tags) throws ParseException } return tagSet; } + + /** + * Parses a {@code String teamName} into a {@code Tag}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code teamName} is invalid. + */ + public static TeamName parseTeamName(String teamName) throws ParseException { + requireNonNull(teamName); + String trimmedTeamName = teamName.trim(); + if (!TeamName.isValidTeamName(trimmedTeamName)) { + throw new ParseException(Team.MESSAGE_CONSTRAINTS); + } + return new TeamName(trimmedTeamName); + } + + /** + * Parses a {@code String teamName} + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code teamName} is invalid. + */ + public static Desc parseTeamDesc(String teamDesc) throws ParseException { + requireNonNull(teamDesc); + String trimmedTeamName = teamDesc.trim(); + if (!Desc.isValidTeamDesc(trimmedTeamName)) { + throw new ParseException(Desc.MESSAGE_CONSTRAINTS); + } + return new Desc(trimmedTeamName); + } + } diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/teambuilder/logic/parser/Prefix.java similarity index 95% rename from src/main/java/seedu/address/logic/parser/Prefix.java rename to src/main/java/teambuilder/logic/parser/Prefix.java index c859d5fa5db..fa3a74cc17e 100644 --- a/src/main/java/seedu/address/logic/parser/Prefix.java +++ b/src/main/java/teambuilder/logic/parser/Prefix.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; /** * A prefix that marks the beginning of an argument in an arguments string. diff --git a/src/main/java/teambuilder/logic/parser/RemoveCommandParser.java b/src/main/java/teambuilder/logic/parser/RemoveCommandParser.java new file mode 100644 index 00000000000..9ab74b83709 --- /dev/null +++ b/src/main/java/teambuilder/logic/parser/RemoveCommandParser.java @@ -0,0 +1,28 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import teambuilder.logic.commands.RemoveCommand; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.team.TeamName; + +/** + * Parses input arguments and creates a new RemoveCommand object + */ +public class RemoveCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the RemoveCommand + * and returns a RemoveCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public RemoveCommand parse(String args) throws ParseException { + try { + TeamName name = ParserUtil.parseTeamName(args); + return new RemoveCommand(name); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, RemoveCommand.MESSAGE_USAGE), pe); + } + } + +} diff --git a/src/main/java/teambuilder/logic/parser/ShowCommandParser.java b/src/main/java/teambuilder/logic/parser/ShowCommandParser.java new file mode 100644 index 00000000000..bca4cce7044 --- /dev/null +++ b/src/main/java/teambuilder/logic/parser/ShowCommandParser.java @@ -0,0 +1,32 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import java.util.Arrays; + +import teambuilder.logic.commands.ShowCommand; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.person.TeamContainsKeywordsPredicate; + +/** + * Parses input arguments and creates a new ShowCommand object + */ +public class ShowCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the FindCommand + * and returns a FindCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public ShowCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, ShowCommand.MESSAGE_USAGE)); + } + + String[] teamKeywords = trimmedArgs.split("\\s+"); + + return new ShowCommand(new TeamContainsKeywordsPredicate(Arrays.asList(teamKeywords))); + } +} diff --git a/src/main/java/teambuilder/logic/parser/SortCommandParser.java b/src/main/java/teambuilder/logic/parser/SortCommandParser.java new file mode 100644 index 00000000000..6d75b0f0934 --- /dev/null +++ b/src/main/java/teambuilder/logic/parser/SortCommandParser.java @@ -0,0 +1,37 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import teambuilder.logic.commands.SortCommand; +import teambuilder.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new SortCommand object + */ +public class SortCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the SortCommand + * and returns a SortCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public SortCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE)); + } + + String[] argsArr = trimmedArgs.split("\\s+"); + if (argsArr.length != 2) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE)); + } else { + String order = argsArr[0].toLowerCase(); + String sortBy = argsArr[1].toLowerCase(); + return new SortCommand(order, sortBy); + } + + } + +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/teambuilder/logic/parser/TeamBuilderParser.java similarity index 54% rename from src/main/java/seedu/address/logic/parser/AddressBookParser.java rename to src/main/java/teambuilder/logic/parser/TeamBuilderParser.java index 1e466792b46..1d3bd0cd637 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/teambuilder/logic/parser/TeamBuilderParser.java @@ -1,26 +1,32 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; import java.util.regex.Matcher; import java.util.regex.Pattern; -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.commands.ClearCommand; -import seedu.address.logic.commands.Command; -import seedu.address.logic.commands.DeleteCommand; -import seedu.address.logic.commands.EditCommand; -import seedu.address.logic.commands.ExitCommand; -import seedu.address.logic.commands.FindCommand; -import seedu.address.logic.commands.HelpCommand; -import seedu.address.logic.commands.ListCommand; -import seedu.address.logic.parser.exceptions.ParseException; +import teambuilder.logic.commands.AddCommand; +import teambuilder.logic.commands.ClearCommand; +import teambuilder.logic.commands.Command; +import teambuilder.logic.commands.CreateCommand; +import teambuilder.logic.commands.DeleteCommand; +import teambuilder.logic.commands.EditCommand; +import teambuilder.logic.commands.ExitCommand; +import teambuilder.logic.commands.FindCommand; +import teambuilder.logic.commands.HelpCommand; +import teambuilder.logic.commands.ListCommand; +import teambuilder.logic.commands.RedoCommand; +import teambuilder.logic.commands.RemoveCommand; +import teambuilder.logic.commands.ShowCommand; +import teambuilder.logic.commands.SortCommand; +import teambuilder.logic.commands.UndoCommand; +import teambuilder.logic.parser.exceptions.ParseException; /** * Parses user input. */ -public class AddressBookParser { +public class TeamBuilderParser { /** * Used for initial separation of command word and args. @@ -68,6 +74,24 @@ public Command parseCommand(String userInput) throws ParseException { case HelpCommand.COMMAND_WORD: return new HelpCommand(); + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + + case SortCommand.COMMAND_WORD: + return new SortCommandParser().parse(arguments); + + case ShowCommand.COMMAND_WORD: + return new ShowCommandParser().parse(arguments); + + case RedoCommand.COMMAND_WORD: + return new RedoCommand(); + + case CreateCommand.COMMAND_WORD: + return new CreateCommandParser().parse(arguments); + + case RemoveCommand.COMMAND_WORD: + return new RemoveCommandParser().parse(arguments); + default: throw new ParseException(MESSAGE_UNKNOWN_COMMAND); } diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/teambuilder/logic/parser/exceptions/ParseException.java similarity index 73% rename from src/main/java/seedu/address/logic/parser/exceptions/ParseException.java rename to src/main/java/teambuilder/logic/parser/exceptions/ParseException.java index 158a1a54c1c..541261af791 100644 --- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java +++ b/src/main/java/teambuilder/logic/parser/exceptions/ParseException.java @@ -1,6 +1,6 @@ -package seedu.address.logic.parser.exceptions; +package teambuilder.logic.parser.exceptions; -import seedu.address.commons.exceptions.IllegalValueException; +import teambuilder.commons.exceptions.IllegalValueException; /** * Represents a parse error encountered by a parser. diff --git a/src/main/java/teambuilder/model/Model.java b/src/main/java/teambuilder/model/Model.java new file mode 100644 index 00000000000..08f8e711fc5 --- /dev/null +++ b/src/main/java/teambuilder/model/Model.java @@ -0,0 +1,134 @@ +package teambuilder.model; + +import java.nio.file.Path; +import java.util.Comparator; +import java.util.function.Predicate; + +import javafx.collections.ObservableList; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.core.Originator; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; + +/** + * The API of the Model component. + */ +public interface Model extends Originator { + /** {@code Predicate} that always evaluate to true */ + Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true; + Predicate PREDICATE_SHOW_ALL_TEAMS = unused -> true; + + /** + * Replaces user prefs data with the data in {@code userPrefs}. + */ + void setUserPrefs(ReadOnlyUserPrefs userPrefs); + + /** + * Returns the user prefs. + */ + ReadOnlyUserPrefs getUserPrefs(); + + /** + * Returns the user prefs' GUI settings. + */ + GuiSettings getGuiSettings(); + + /** + * Sets the user prefs' GUI settings. + */ + void setGuiSettings(GuiSettings guiSettings); + + /** + * Returns the user prefs' TeamBuilder file path. + */ + Path getAddressBookFilePath(); + + /** + * Sets the user prefs' TeamBuilder file path. + */ + void setAddressBookFilePath(Path addressBookFilePath); + + /** + * Replaces TeamBuilder data with the data in {@code addressBook}. + */ + void setTeamBuilder(ReadOnlyTeamBuilder teamBuilder); + + /** Returns the AddressBook */ + ReadOnlyTeamBuilder getTeamBuilder(); + + /** + * Returns true if a person with the same identity as {@code person} exists in the TeamBuilder. + */ + boolean hasPerson(Person person); + + /** + * Deletes the given person. + * The person must exist in the TeamBuilder. + */ + void deletePerson(Person target); + + /** + * Adds the given person. + * {@code person} must not already exist in the TeamBuilder. + */ + void addPerson(Person person); + + /** + * Replaces the given person {@code target} with {@code editedPerson}. + * {@code target} must exist in the TeamBuilder. + * The person identity of {@code editedPerson} must not be the same as another existing person in the TeamBuilder. + */ + void setPerson(Person target, Person editedPerson); + /** + * Returns true if a team with the same identity as {@code team} exists in the TeamBuilder. + */ + boolean hasTeam(Team team); + + void setTeam(Team team, Team editedTeam); + /** + * Deletes the given team. + * The team must exist in the TeamBuilder. + */ + void deleteTeam(Team target); + + /** + * Adds the given team. + * {@code team} must not already exist in the TeamBuilder. + */ + void addTeam(Team team); + + /** + * Adds person to the team, based on its team tags. + */ + void updatePersonInTeams(Person person); + + /** + * Removes person from all teams + */ + void removeFromAllTeams(Person person); + + ObservableList getSortedTeamList(); + + /** Returns an unmodifiable view of the filtered person list */ + ObservableList getSortedPersonList(); + + /** Returns an unmodifiable view of the team list */ + ObservableList getTeamList(); + + /** + * Updates the filter of the filtered person list to filter by the given {@code predicate}. + * @throws NullPointerException if {@code predicate} is null. + */ + void updateFilteredPersonList(Predicate predicate); + + void updateFilteredTeamList(Predicate predicate); + + /** + * Updates the comparator of the sorted person list to sort by the given {@code comparator}. + * @throws NullPointerException if {@code comparator} is null. + */ + void updateSortPerson(Comparator comparator); + + void updateSortTeam(Comparator comparator); + +} diff --git a/src/main/java/teambuilder/model/ModelManager.java b/src/main/java/teambuilder/model/ModelManager.java new file mode 100644 index 00000000000..eff3ad8bffe --- /dev/null +++ b/src/main/java/teambuilder/model/ModelManager.java @@ -0,0 +1,237 @@ +package teambuilder.model; + +import static java.util.Objects.requireNonNull; +import static teambuilder.commons.util.CollectionUtil.requireAllNonNull; + +import java.nio.file.Path; +import java.util.Comparator; +import java.util.function.Predicate; +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; +import javafx.collections.transformation.SortedList; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.core.Memento; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; + +/** + * Represents the in-memory model of the TeamBuilder data. + */ +public class ModelManager implements Model { + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private final TeamBuilder teamBuilder; + private final UserPrefs userPrefs; + private final FilteredList filteredPersons; + private final SortedList sortedPersons; + private final FilteredList filteredTeams; + private final SortedList sortedTeams; + + /** + * Initializes a ModelManager with the given addressBook and userPrefs. + */ + public ModelManager(ReadOnlyTeamBuilder addressBook, ReadOnlyUserPrefs userPrefs) { + requireAllNonNull(addressBook, userPrefs); + + logger.fine("Initializing with TeamBuilder: " + addressBook + " and user prefs " + userPrefs); + + this.teamBuilder = new TeamBuilder(addressBook); + this.userPrefs = new UserPrefs(userPrefs); + filteredPersons = new FilteredList<>(this.teamBuilder.getPersonList()); + sortedPersons = new SortedList<>(filteredPersons); + filteredTeams = new FilteredList<>(this.teamBuilder.getTeamList()); + sortedTeams = new SortedList<>(filteredTeams); + } + + + public ModelManager() { + this(new TeamBuilder(), new UserPrefs()); + } + + //=========== UserPrefs ================================================================================== + + @Override + public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { + requireNonNull(userPrefs); + this.userPrefs.resetData(userPrefs); + } + + @Override + public ReadOnlyUserPrefs getUserPrefs() { + return userPrefs; + } + + @Override + public GuiSettings getGuiSettings() { + return userPrefs.getGuiSettings(); + } + + @Override + public void setGuiSettings(GuiSettings guiSettings) { + requireNonNull(guiSettings); + userPrefs.setGuiSettings(guiSettings); + } + + @Override + public Path getAddressBookFilePath() { + return userPrefs.getAddressBookFilePath(); + } + + @Override + public void setAddressBookFilePath(Path addressBookFilePath) { + requireNonNull(addressBookFilePath); + userPrefs.setAddressBookFilePath(addressBookFilePath); + } + + //=========== AddressBook ================================================================================ + + @Override + public Memento save() { + return new TeamBuilderMemento(new TeamBuilder(teamBuilder), this); + } + + @Override + public void setTeamBuilder(ReadOnlyTeamBuilder teamBuilder) { + this.teamBuilder.resetData(teamBuilder); + } + + @Override + public ReadOnlyTeamBuilder getTeamBuilder() { + return teamBuilder; + } + + @Override + public boolean hasPerson(Person person) { + requireNonNull(person); + return teamBuilder.hasPerson(person); + } + + @Override + public boolean hasTeam(Team team) { + requireNonNull(team); + return teamBuilder.hasTeam(team); + } + + @Override + public void deletePerson(Person target) { + teamBuilder.removePerson(target); + } + + @Override + public void deleteTeam(Team target) { + teamBuilder.removeTeam(target); + } + + @Override + public void addPerson(Person person) { + teamBuilder.addPerson(person); + updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + updateFilteredTeamList(PREDICATE_SHOW_ALL_TEAMS); + } + + @Override + public void addTeam(Team team) { + teamBuilder.addTeam(team); + updateFilteredTeamList(PREDICATE_SHOW_ALL_TEAMS); + } + + @Override + public void setPerson(Person target, Person editedPerson) { + requireAllNonNull(target, editedPerson); + + teamBuilder.setPerson(target, editedPerson); + updateFilteredTeamList(PREDICATE_SHOW_ALL_TEAMS); + } + + @Override + public void setTeam(Team target, Team editedTeam) { + requireAllNonNull(target, editedTeam); + + teamBuilder.setTeam(target, editedTeam); + } + //=========== Filtered Team List Accessors =============================================================== + + /** + * Returns an unmodifiable view of the list of {@code Team} backed by the internal list of + * {@code versionedAddressBook} + */ + @Override + public ObservableList getTeamList() { + return filteredTeams; + } + + //=========== Filtered Person List Accessors ============================================================= + + /** + * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of + * {@code versionedAddressBook} + */ + @Override + public ObservableList getSortedPersonList() { + return sortedPersons; + } + + @Override + public ObservableList getSortedTeamList() { + return sortedTeams; + } + + @Override + public void removeFromAllTeams(Person person) { + teamBuilder.removeFromAllTeams(person); + } + + + @Override + public void updateFilteredPersonList(Predicate predicate) { + requireNonNull(predicate); + filteredPersons.setPredicate(predicate); + } + + @Override + public void updateFilteredTeamList(Predicate predicate) { + requireNonNull(predicate); + filteredTeams.setPredicate(predicate); + } + + @Override + public void updateSortPerson(Comparator comparator) { + requireNonNull(comparator); + sortedPersons.setComparator(comparator); + } + + @Override + public void updateSortTeam(Comparator comparator) { + requireNonNull(comparator); + sortedTeams.setComparator(comparator); + } + + @Override + public void updatePersonInTeams(Person person) { + teamBuilder.updatePersonInTeams(person); + } + + @Override + public boolean equals(Object obj) { + // short circuit if same object + if (obj == this) { + return true; + } + + // instanceof handles nulls + if (!(obj instanceof ModelManager)) { + return false; + } + + // state check + ModelManager other = (ModelManager) obj; + return teamBuilder.equals(other.teamBuilder) + && userPrefs.equals(other.userPrefs) + && filteredPersons.equals(other.filteredPersons) + && filteredTeams.equals(other.filteredTeams); + } + +} diff --git a/src/main/java/teambuilder/model/ReadOnlyTeamBuilder.java b/src/main/java/teambuilder/model/ReadOnlyTeamBuilder.java new file mode 100644 index 00000000000..b37d7fd1d87 --- /dev/null +++ b/src/main/java/teambuilder/model/ReadOnlyTeamBuilder.java @@ -0,0 +1,24 @@ +package teambuilder.model; + +import javafx.collections.ObservableList; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; + +/** + * Unmodifiable view of an TeamBuilder + */ +public interface ReadOnlyTeamBuilder { + + /** + * Returns an unmodifiable view of the persons list. + * This list will not contain any duplicate persons. + */ + ObservableList getPersonList(); + + /** + * Returns an unmodifiable view of the teams list. + * This list will not contain any duplicate teams. + */ + ObservableList getTeamList(); + +} diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/teambuilder/model/ReadOnlyUserPrefs.java similarity index 70% rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java rename to src/main/java/teambuilder/model/ReadOnlyUserPrefs.java index befd58a4c73..95eccb65e49 100644 --- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java +++ b/src/main/java/teambuilder/model/ReadOnlyUserPrefs.java @@ -1,8 +1,8 @@ -package seedu.address.model; +package teambuilder.model; import java.nio.file.Path; -import seedu.address.commons.core.GuiSettings; +import teambuilder.commons.core.GuiSettings; /** * Unmodifiable view of user prefs. diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/teambuilder/model/TeamBuilder.java similarity index 52% rename from src/main/java/seedu/address/model/AddressBook.java rename to src/main/java/teambuilder/model/TeamBuilder.java index 1a943a0781a..7b4a50664de 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/teambuilder/model/TeamBuilder.java @@ -1,20 +1,23 @@ -package seedu.address.model; +package teambuilder.model; import static java.util.Objects.requireNonNull; import java.util.List; import javafx.collections.ObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.UniquePersonList; +import teambuilder.model.person.Person; +import teambuilder.model.person.UniquePersonList; +import teambuilder.model.team.Team; +import teambuilder.model.team.UniqueTeamList; /** * Wraps all data at the address-book level * Duplicates are not allowed (by .isSamePerson comparison) */ -public class AddressBook implements ReadOnlyAddressBook { +public class TeamBuilder implements ReadOnlyTeamBuilder { private final UniquePersonList persons; + private final UniqueTeamList teams; /* * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication @@ -25,14 +28,15 @@ public class AddressBook implements ReadOnlyAddressBook { */ { persons = new UniquePersonList(); + teams = new UniqueTeamList(); } - public AddressBook() {} + public TeamBuilder() {} /** * Creates an AddressBook using the Persons in the {@code toBeCopied} */ - public AddressBook(ReadOnlyAddressBook toBeCopied) { + public TeamBuilder(ReadOnlyTeamBuilder toBeCopied) { this(); resetData(toBeCopied); } @@ -47,19 +51,24 @@ public void setPersons(List persons) { this.persons.setPersons(persons); } + public void setTeams(List teams) { + this.teams.setTeams(teams); + } + /** * Resets the existing data of this {@code AddressBook} with {@code newData}. */ - public void resetData(ReadOnlyAddressBook newData) { + public void resetData(ReadOnlyTeamBuilder newData) { requireNonNull(newData); - + //TODO: setPersons(newData.getPersonList()); + setTeams(newData.getTeamList()); } //// person-level operations /** - * Returns true if a person with the same identity as {@code person} exists in the address book. + * Returns true if a person with the same identity as {@code person} exists in the TeamBuilder. */ public boolean hasPerson(Person person) { requireNonNull(person); @@ -67,8 +76,8 @@ public boolean hasPerson(Person person) { } /** - * Adds a person to the address book. - * The person must not already exist in the address book. + * Adds a person to the TeamBuilder. + * The person must not already exist in the TeamBuilder. */ public void addPerson(Person p) { persons.add(p); @@ -76,23 +85,59 @@ public void addPerson(Person p) { /** * Replaces the given person {@code target} in the list with {@code editedPerson}. - * {@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. + * {@code target} must exist in the TeamBuilder. + * The person identity of {@code editedPerson} must not be the same as another existing person in the TeamBuilder. */ public void setPerson(Person target, Person editedPerson) { requireNonNull(editedPerson); - persons.setPerson(target, editedPerson); } + /** + * Returns true if a team with the same identity as {@code team} exists in the TeamBuilder. + */ + public boolean hasTeam(Team team) { + requireNonNull(team); + return teams.contains(team); + } + + public void setTeam(Team target, Team editedteam) { + requireNonNull(editedteam); + teams.setTeam(target, editedteam); + } + /** * Removes {@code key} from this {@code AddressBook}. - * {@code key} must exist in the address book. + * {@code key} must exist in the TeamBuilder. */ public void removePerson(Person key) { persons.remove(key); } + /** + * Adds a team to the TeamBuilder. + * The person must not already exist in the TeamBuilder. + */ + public void addTeam(Team team) { + teams.add(team); + } + + /** + * Removes {@code key} from this {@code AddressBook}. + * {@code key} must exist in the TeamBuilder. + */ + public void removeTeam(Team key) { + teams.remove(key); + } + + public void updatePersonInTeams(Person person) { + teams.updatePersonInTeams(person); + } + + public void removeFromAllTeams(Person person) { + teams.removeFromAllTeams(person); + } + //// util methods @Override @@ -106,11 +151,23 @@ public ObservableList getPersonList() { return persons.asUnmodifiableObservableList(); } + @Override + public ObservableList getTeamList() { + return teams.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)); + if (other == this) { + return true; + } + if (!(other instanceof TeamBuilder)) { + return false; + } + if (!persons.equals(((TeamBuilder) other).persons)) { + return false; + } + return teams.equals(((TeamBuilder) other).teams); } @Override diff --git a/src/main/java/teambuilder/model/TeamBuilderMemento.java b/src/main/java/teambuilder/model/TeamBuilderMemento.java new file mode 100644 index 00000000000..cfa541f8f9b --- /dev/null +++ b/src/main/java/teambuilder/model/TeamBuilderMemento.java @@ -0,0 +1,38 @@ +package teambuilder.model; + +import static java.util.Objects.requireNonNull; + +import teambuilder.commons.core.Memento; + +/** + * This class stores the state of a TeamBuilder + */ +public class TeamBuilderMemento implements Memento { + private TeamBuilder state; + private ModelManager origin; + + /** + * Constructs a TeamBuilderMemento. + * + * @param state The state of the TeamBuilder to be saved. + * @param origin The Model manager to restore the TeamBuilder from. + */ + public TeamBuilderMemento(TeamBuilder state, ModelManager origin) { + requireNonNull(state); + requireNonNull(origin); + + this.state = state; + this.origin = origin; + } + + @Override + public boolean restore() { + origin.setTeamBuilder(state); + return true; + } + + @Override + public Memento getUpdatedMemento() { + return origin.save(); + } +} diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/teambuilder/model/UserPrefs.java similarity index 96% rename from src/main/java/seedu/address/model/UserPrefs.java rename to src/main/java/teambuilder/model/UserPrefs.java index 25a5fd6eab9..38ff80d4572 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/teambuilder/model/UserPrefs.java @@ -1,4 +1,4 @@ -package seedu.address.model; +package teambuilder.model; import static java.util.Objects.requireNonNull; @@ -6,7 +6,7 @@ import java.nio.file.Paths; import java.util.Objects; -import seedu.address.commons.core.GuiSettings; +import teambuilder.commons.core.GuiSettings; /** * Represents User's preferences. diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/teambuilder/model/person/Address.java similarity index 51% rename from src/main/java/seedu/address/model/person/Address.java rename to src/main/java/teambuilder/model/person/Address.java index 60472ca22a0..abcd12102d2 100644 --- a/src/main/java/seedu/address/model/person/Address.java +++ b/src/main/java/teambuilder/model/person/Address.java @@ -1,35 +1,60 @@ -package seedu.address.model.person; +package teambuilder.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static teambuilder.commons.util.AppUtil.checkArgument; /** - * Represents a Person's address in the address book. + * Represents a Person's address in the TeamBuilder. * 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"; + public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values"; /* * 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 static final String VALIDATION_REGEX = "[^\\s].*|^\\s*$"; - public final String value; + private static final Address EMPTY_ADDRESS = new Address(); + private final String value; /** * Constructs an {@code Address}. * * @param address A valid address. */ - public Address(String address) { + private Address(String address) { requireNonNull(address); checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); value = address; } + private Address() { + value = ""; + } + + /** + * Public method to create addresses. + * Note that empty string or string containing only white spaces will return the default EMPTY_ADDRESS instance. + * + * @param address The address input. + * @return An Address instance with the given input + */ + public static Address of(String address) { + requireNonNull(address); + checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); + if (address.length() == 0) { + return getEmptyAddress(); + } + return new Address(address); + } + + public static Address getEmptyAddress() { + return EMPTY_ADDRESS; + } + /** * Returns true if a given string is a valid email. */ @@ -54,4 +79,7 @@ public int hashCode() { return value.hashCode(); } + public boolean isEmptyAddress() { + return this == EMPTY_ADDRESS; + } } diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/teambuilder/model/person/Email.java similarity index 69% rename from src/main/java/seedu/address/model/person/Email.java rename to src/main/java/teambuilder/model/person/Email.java index f866e7133de..c35a6a5367f 100644 --- a/src/main/java/seedu/address/model/person/Email.java +++ b/src/main/java/teambuilder/model/person/Email.java @@ -1,10 +1,10 @@ -package seedu.address.model.person; +package teambuilder.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static teambuilder.commons.util.AppUtil.checkArgument; /** - * Represents a Person's email in the address book. + * Represents a Person's email in the TeamBuilder. * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)} */ public class Email { @@ -29,21 +29,44 @@ public class Email { + "(-" + 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; - public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" + DOMAIN_REGEX; + public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" + DOMAIN_REGEX + "|\\s*"; - public final String value; + private static final Email EMPTY_EMAIL = new Email(); + + private final String value; /** * Constructs an {@code Email}. * * @param email A valid email address. */ - public Email(String email) { + private Email(String email) { requireNonNull(email); checkArgument(isValidEmail(email), MESSAGE_CONSTRAINTS); value = email; } + private Email() { + value = ""; + } + + /** + * Creates an email based on the given string. + * If the email is not blank, ensure that the email matches the regex pattern. Otherwise, if whitespaces or an emtpy + * string is passed as the argument, return the default NO_EMAIL in the email class. + * + * @param email The email address given by user. + * @return Email based on the input string. + */ + public static Email of(String email) { + requireNonNull(email); + checkArgument(isValidEmail(email), MESSAGE_CONSTRAINTS); + if (email.length() == 0) { + return getEmptyEmail(); + } + return new Email(email); + } + /** * Returns if a given string is a valid email. */ @@ -51,6 +74,10 @@ public static boolean isValidEmail(String test) { return test.matches(VALIDATION_REGEX); } + public static Email getEmptyEmail() { + return EMPTY_EMAIL; + } + @Override public String toString() { return value; @@ -63,6 +90,10 @@ public boolean equals(Object other) { && value.equals(((Email) other).value)); // state check } + public boolean isEmptyEmail() { + return this == EMPTY_EMAIL; + } + @Override public int hashCode() { return value.hashCode(); diff --git a/src/main/java/teambuilder/model/person/Major.java b/src/main/java/teambuilder/model/person/Major.java new file mode 100644 index 00000000000..25dcb062423 --- /dev/null +++ b/src/main/java/teambuilder/model/person/Major.java @@ -0,0 +1,94 @@ +package teambuilder.model.person; + +import static java.util.Objects.requireNonNull; +import static teambuilder.commons.util.AppUtil.checkArgument; + +/** + * Represents a Person's major study in the contact list. + * Guarantees: immutable; is valid as declared in {@link #isValidMajor(String)} + */ +public class Major { + + public static final String MESSAGE_CONSTRAINTS = + "Majors should only contain alphanumeric characters and spaces."; + + + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*|^\\s*$"; + private static final Major EMPTY_MAJOR = new Major(); + private final String majorStudy; + + /** + * Constructs a {@code Name}. + * + * @param major A valid major. + */ + private Major(String major) { + requireNonNull(major); + checkArgument(isValidMajor(major), MESSAGE_CONSTRAINTS); + majorStudy = major; + } + + private Major() { + majorStudy = ""; + } + + /** + * Public static method to create major. + * Returns default EMPTY_MAJOR if the input is blank or contains only whitespaces. + * + * @param major Major given by input. + * @return Respective major instance based on given input. + */ + public static Major of(String major) { + requireNonNull(major); + checkArgument(isValidMajor(major), MESSAGE_CONSTRAINTS); + if (major.length() == 0) { + return getEmptyMajor(); + } + return new Major(major); + } + + /** + * Returns the static final default EMPTY_MAJOR + * + * @return EMPTY_MAJOR. + */ + public static Major getEmptyMajor() { + return EMPTY_MAJOR; + } + + /** + * Returns true if a given string is a valid name. + */ + public static boolean isValidMajor(String test) { + return test.matches(VALIDATION_REGEX); + } + + /** + * Checks if the major instance calling this method is the default EMPTY_MAJOR. + * + * @return True if instance is the EMPTY_MAJOR, false otherwise. + */ + public boolean isEmptyMajor() { + return this == EMPTY_MAJOR; + } + + + @Override + public String toString() { + return majorStudy; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Major // instanceof handles nulls + && majorStudy.equals(((Major) other).majorStudy)); // state check + } + + @Override + public int hashCode() { + return majorStudy.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/teambuilder/model/person/Name.java similarity index 84% rename from src/main/java/seedu/address/model/person/Name.java rename to src/main/java/teambuilder/model/person/Name.java index 79244d71cf7..d8f89d9bb55 100644 --- a/src/main/java/seedu/address/model/person/Name.java +++ b/src/main/java/teambuilder/model/person/Name.java @@ -1,10 +1,10 @@ -package seedu.address.model.person; +package teambuilder.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static teambuilder.commons.util.AppUtil.checkArgument; /** - * Represents a Person's name in the address book. + * Represents a Person's name in the TeamBuilder. * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} */ public class Name { @@ -48,7 +48,7 @@ public String toString() { public boolean equals(Object other) { return other == this // short circuit if same object || (other instanceof Name // instanceof handles nulls - && fullName.equals(((Name) other).fullName)); // state check + && fullName.trim().equalsIgnoreCase(((Name) other).fullName.trim())); // state check } @Override diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/teambuilder/model/person/Person.java similarity index 65% rename from src/main/java/seedu/address/model/person/Person.java rename to src/main/java/teambuilder/model/person/Person.java index 8ff1d83fe89..39388dda9c9 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/teambuilder/model/person/Person.java @@ -1,16 +1,16 @@ -package seedu.address.model.person; +package teambuilder.model.person; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static teambuilder.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; +import teambuilder.model.tag.Tag; /** - * Represents a Person in the address book. + * Represents a Person in the contact list. * Guarantees: details are present and not null, field values are validated, immutable. */ public class Person { @@ -22,18 +22,23 @@ public class Person { // Data fields private final Address address; + private final Major major; private final Set tags = new HashSet<>(); + private final Set teams = new HashSet<>(); /** - * Every field must be present and not null. + * Every field must be present and not null. A person can however have no tags within their team tags. */ - public Person(Name name, Phone phone, Email email, Address address, Set tags) { - requireAllNonNull(name, phone, email, address, tags); + public Person(Name name, Phone phone, Email email, Address address, Major major, + Set tags, Set teams) { + requireAllNonNull(name, email, address, major, tags, teams); this.name = name; this.phone = phone; this.email = email; this.address = address; + this.major = major; this.tags.addAll(tags); + this.teams.addAll(teams); } public Name getName() { @@ -52,6 +57,10 @@ public Address getAddress() { return address; } + public Major getMajor() { + return major; + } + /** * Returns an immutable tag set, which throws {@code UnsupportedOperationException} * if modification is attempted. @@ -60,6 +69,21 @@ public Set getTags() { return Collections.unmodifiableSet(tags); } + /** + * Returns an immutable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + */ + public Set getTeams() { + return Collections.unmodifiableSet(teams); + } + + /** + * Returns number of tags. + */ + public int getNumTags() { + return tags.size(); + } + /** * Returns true if both persons have the same name. * This defines a weaker notion of equality between two persons. @@ -92,13 +116,15 @@ public boolean equals(Object other) { && otherPerson.getPhone().equals(getPhone()) && otherPerson.getEmail().equals(getEmail()) && otherPerson.getAddress().equals(getAddress()) - && otherPerson.getTags().equals(getTags()); + && otherPerson.getMajor().equals(getMajor()) + && otherPerson.getTags().equals(getTags()) + && otherPerson.getTeams().equals((getTeams())); } @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); + return Objects.hash(name, phone, email, address, major, tags, teams); } @Override @@ -110,13 +136,21 @@ public String toString() { .append("; Email: ") .append(getEmail()) .append("; Address: ") - .append(getAddress()); + .append(getAddress()) + .append("; Major: ") + .append(getMajor()); Set tags = getTags(); if (!tags.isEmpty()) { builder.append("; Tags: "); tags.forEach(builder::append); } + + Set teams = getTeams(); + if (!teams.isEmpty()) { + builder.append("; Teams: "); + teams.forEach(builder::append); + } return builder.toString(); } diff --git a/src/main/java/teambuilder/model/person/PersonContainsKeywordsPredicate.java b/src/main/java/teambuilder/model/person/PersonContainsKeywordsPredicate.java new file mode 100644 index 00000000000..6907893bd5b --- /dev/null +++ b/src/main/java/teambuilder/model/person/PersonContainsKeywordsPredicate.java @@ -0,0 +1,38 @@ +package teambuilder.model.person; + +import java.util.List; +import java.util.function.Predicate; + +import teambuilder.commons.util.StringUtil; + +/** + * Tests that a {@code Person}'s {@code Name} or {@code Major} or {@code Tags} + * matches any of the keywords given. + */ +public class PersonContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public PersonContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Person person) { + boolean isInName = keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)); + boolean isInMajor = keywords.stream() + .anyMatch(keywords -> StringUtil.containsWordIgnoreCase(person.getMajor().toString(), keywords)); + boolean isInTag = keywords.stream() + .anyMatch(keyword -> person.getTags().stream() + .anyMatch(tag -> StringUtil.containsWordIgnoreCase(tag.tagName, keyword))); + return isInName || isInMajor || isInTag; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof PersonContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((PersonContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/teambuilder/model/person/Phone.java b/src/main/java/teambuilder/model/person/Phone.java new file mode 100644 index 00000000000..96ffd554f03 --- /dev/null +++ b/src/main/java/teambuilder/model/person/Phone.java @@ -0,0 +1,83 @@ +package teambuilder.model.person; + +import static java.util.Objects.requireNonNull; +import static teambuilder.commons.util.AppUtil.checkArgument; + +/** + * Represents a Person's phone number in the TeamBuilder. + * 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,}|^\\s*"; + private static final Phone NO_PHONE = new Phone(); + private final String value; + + /** + * Constructs a {@code Phone}. + * + * @param phone A valid phone number. + */ + private Phone(String phone) { + requireNonNull(phone); + checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS); + value = phone; + } + + private Phone() { + value = ""; + } + + public static Phone getEmptyPhone() { + return NO_PHONE; + } + + /** + * Creates a phone instance if the phone number is not blank, otherwise return the unique "empty_phone" instance. + * The method also ensures that the phone is of the correct formatting, i.e. if the phone is not blank it should + * only contain numerical characters and have a length of at least 3. + * + * @param phone The phone number is given by the input string. + * @return An instance of Phone, based on the input string. + */ + public static Phone of(String phone) { + requireNonNull(phone); + checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS); + if (phone.length() == 0) { + return getEmptyPhone(); + } + return new Phone(phone); + } + + public boolean isEmptyPhone() { + return this == NO_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/teambuilder/model/person/TeamContainsKeywordsPredicate.java b/src/main/java/teambuilder/model/person/TeamContainsKeywordsPredicate.java new file mode 100644 index 00000000000..7c01e26776a --- /dev/null +++ b/src/main/java/teambuilder/model/person/TeamContainsKeywordsPredicate.java @@ -0,0 +1,31 @@ +package teambuilder.model.person; + +import java.util.List; +import java.util.function.Predicate; + +import teambuilder.commons.util.StringUtil; + +/** + * Tests that a {@code Person}'s {@code teams} matches any of the keywords given. + */ +public class TeamContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public TeamContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> person.getTeams().stream() + .anyMatch(team -> StringUtil.containsWordIgnoreCase(team.tagName, keyword))); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof TeamContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((TeamContainsKeywordsPredicate) other).keywords)); // state check + } +} diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/teambuilder/model/person/UniquePersonList.java similarity index 94% rename from src/main/java/seedu/address/model/person/UniquePersonList.java rename to src/main/java/teambuilder/model/person/UniquePersonList.java index 0fee4fe57e6..d8a1ab707d2 100644 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ b/src/main/java/teambuilder/model/person/UniquePersonList.java @@ -1,15 +1,15 @@ -package seedu.address.model.person; +package teambuilder.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static teambuilder.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; +import teambuilder.model.person.exceptions.DuplicatePersonException; +import teambuilder.model.person.exceptions.PersonNotFoundException; /** * A list of persons that enforces uniqueness between its elements and does not allow nulls. diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/teambuilder/model/person/exceptions/DuplicatePersonException.java similarity index 87% rename from src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java rename to src/main/java/teambuilder/model/person/exceptions/DuplicatePersonException.java index d7290f59442..7a8bbbef4a3 100644 --- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java +++ b/src/main/java/teambuilder/model/person/exceptions/DuplicatePersonException.java @@ -1,4 +1,4 @@ -package seedu.address.model.person.exceptions; +package teambuilder.model.person.exceptions; /** * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/teambuilder/model/person/exceptions/PersonNotFoundException.java similarity index 75% rename from src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java rename to src/main/java/teambuilder/model/person/exceptions/PersonNotFoundException.java index fa764426ca7..7b9fc13ed17 100644 --- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java +++ b/src/main/java/teambuilder/model/person/exceptions/PersonNotFoundException.java @@ -1,4 +1,4 @@ -package seedu.address.model.person.exceptions; +package teambuilder.model.person.exceptions; /** * Signals that the operation is unable to find the specified person. diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/teambuilder/model/tag/Tag.java similarity index 75% rename from src/main/java/seedu/address/model/tag/Tag.java rename to src/main/java/teambuilder/model/tag/Tag.java index b0ea7e7dad7..3a09beecd43 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/teambuilder/model/tag/Tag.java @@ -1,16 +1,17 @@ -package seedu.address.model.tag; +package teambuilder.model.tag; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static teambuilder.commons.util.AppUtil.checkArgument; /** - * Represents a Tag in the address book. + * Represents a Tag in the TeamBuilder. * 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 static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric," + + " with only a single whitespace between words if there are multiple words"; + public static final String VALIDATION_REGEX = "^([a-zA-Z0-9]+\\s)*[a-zA-Z0-9]+$"; public final String tagName; @@ -32,6 +33,10 @@ public static boolean isValidTagName(String test) { return test.matches(VALIDATION_REGEX); } + public String getName() { + return tagName; + } + @Override public boolean equals(Object other) { return other == this // short circuit if same object diff --git a/src/main/java/teambuilder/model/team/Desc.java b/src/main/java/teambuilder/model/team/Desc.java new file mode 100644 index 00000000000..9eb44cc46d3 --- /dev/null +++ b/src/main/java/teambuilder/model/team/Desc.java @@ -0,0 +1,52 @@ +package teambuilder.model.team; + +import static java.util.Objects.requireNonNull; +import static teambuilder.commons.util.AppUtil.checkArgument; + +/** + * Represents a Team's description. + * Guarantees: immutable; is valid as declared in {@link #isValidTeamDesc(String)} + */ +public class Desc { + + public static final String MESSAGE_CONSTRAINTS = "Descriptions can take any values, and it should not be blank"; + + public static final String VALIDATION_REGEX = "[^\\s].*"; + + public final String value; + + /** + * Constructs an {@code Desc}. + * + * @param desc A valid address. + */ + public Desc(String desc) { + requireNonNull(desc); + checkArgument(isValidTeamDesc(desc), MESSAGE_CONSTRAINTS); + value = desc; + } + + /** + * Returns true if a given string is a valid email. + */ + public static boolean isValidTeamDesc(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 Desc // instanceof handles nulls + && value.equals(((Desc) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/teambuilder/model/team/Team.java b/src/main/java/teambuilder/model/team/Team.java new file mode 100644 index 00000000000..579d270c851 --- /dev/null +++ b/src/main/java/teambuilder/model/team/Team.java @@ -0,0 +1,121 @@ +package teambuilder.model.team; + +import static java.util.Objects.requireNonNull; + +import java.util.HashSet; +import java.util.Set; + +import teambuilder.model.person.Name; +import teambuilder.model.tag.Tag; + +/** + * Represents a Team in the TeamBuilder. + */ +public class Team { + + public static final String MESSAGE_CONSTRAINTS = + "Team names should only contain alphanumeric characters and spaces, and it should not be blank"; + + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + private final TeamName teamName; + private final Desc teamDesc; + private final Set skillTags = new HashSet<>(); + private final Set members = new HashSet<>(); + + + /** + * Constructs a {@code Team}. + * + * @param teamName A valid team name. + * @param teamDesc A team description. + * @param skillTags A set of skill tags. + */ + public Team(TeamName teamName, Desc teamDesc, Set skillTags) { + requireNonNull(teamName); + this.teamName = teamName; + this.teamDesc = teamDesc; + this.skillTags.addAll(skillTags); + } + + /** + * Constructs a completely new {@code Team} with new members. + * + * @param t The team to have new members. + * @param names The set of names that are the new members. + */ + public Team(Team t, Set names) { + requireNonNull(t); + this.teamName = t.teamName; + this.teamDesc = t.teamDesc; + this.skillTags.addAll(t.skillTags); + members.addAll(names); + } + + public TeamName getName() { + return this.teamName; + } + + public void addPerson(Name name) { + members.add(name); + } + + public void removePerson(Name name) { + members.remove(name); + } + + public Set getMembers() { + return members; + } + + public Set getTags() { + return skillTags; + } + + @Override + public int hashCode() { + return teamName.hashCode(); + } + + public String toString() { + return teamName.toString(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Team // instanceof handles nulls + && teamName.equals(((Team) other).teamName)); // state check + } + + /** + * Getter method for the team name of team instance. + * + * @return TeamName of Team instance. + */ + public TeamName getTeamName() { + return teamName; + } + + public Desc getDesc() { + return teamDesc; + } + + public Set getSkillTags() { + return skillTags; + } + + /** + * Returns true if both teams have the same name. + */ + public boolean isSameTeam(Team otherTeam) { + if (otherTeam == this) { + return true; + } + + return otherTeam != null + && otherTeam.getTeamName().equals(getTeamName()); + } + + +} diff --git a/src/main/java/teambuilder/model/team/TeamName.java b/src/main/java/teambuilder/model/team/TeamName.java new file mode 100644 index 00000000000..842554c3498 --- /dev/null +++ b/src/main/java/teambuilder/model/team/TeamName.java @@ -0,0 +1,54 @@ +package teambuilder.model.team; + +import static java.util.Objects.requireNonNull; +import static teambuilder.commons.util.AppUtil.checkArgument; + +/** + * Represents a Team's name in TeamBuilder. + */ +public class TeamName { + + public static final String MESSAGE_CONSTRAINTS = "Team names should be alphanumeric," + + " with only a single whitespace between words if there are multiple words"; + + public static final String VALIDATION_REGEX = "^([a-zA-Z0-9]+\\s)*[a-zA-Z0-9]+$"; + + public final String teamName; + + /** + * Constructs a {@code Tag}. + * + * @param teamName A valid tag name. + */ + public TeamName(String teamName) { + requireNonNull(teamName); + checkArgument(isValidTeamName(teamName), MESSAGE_CONSTRAINTS); + this.teamName = teamName; + } + + /** + * Returns true if a given string is a valid team name. + */ + public static boolean isValidTeamName(String test) { + return test.matches(VALIDATION_REGEX); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof TeamName // instanceof handles nulls + && teamName.trim().equalsIgnoreCase(((TeamName) other).teamName.trim())); // state check + } + + @Override + public int hashCode() { + return teamName.hashCode(); + } + + /** + * Format state as text for viewing. + */ + public String toString() { + return teamName; + } +} diff --git a/src/main/java/teambuilder/model/team/UniqueTeamList.java b/src/main/java/teambuilder/model/team/UniqueTeamList.java new file mode 100644 index 00000000000..6b2e343091e --- /dev/null +++ b/src/main/java/teambuilder/model/team/UniqueTeamList.java @@ -0,0 +1,189 @@ +package teambuilder.model.team; + +import static java.util.Objects.requireNonNull; +import static teambuilder.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.exceptions.DuplicateTeamException; +import teambuilder.model.team.exceptions.TeamNotFoundException; + +/** + * The type Unique team list. + */ +public class UniqueTeamList implements Iterable { + + private final ObservableList internalList = FXCollections.observableArrayList(); + private final ObservableList internalUnmodifiableList = FXCollections + .unmodifiableObservableList(internalList); + + /** + * Returns true if the list contains an equivalent team as the given argument. + */ + public boolean contains(Team toCheck) { + requireNonNull(toCheck); + return internalList.stream().anyMatch(toCheck::isSameTeam); + } + + /** + * Adds a team to the list. + * The team must not already exist in the list. + */ + public void add(Team toAdd) { + requireNonNull(toAdd); + if (contains(toAdd)) { + throw new DuplicateTeamException(); + } + internalList.add(toAdd); + } + + /** + * Replaces the Team {@code target} in the list with {@code editedTeam}. + * {@code target} must exist in the list. + * The Team identity of {@code editedTeam} must not be the same as another existing team in the list. + */ + public void setTeam(Team target, Team editedTeam) { + requireAllNonNull(target, editedTeam); + + int index = internalList.indexOf(target); + if (index == -1) { + throw new TeamNotFoundException(); + } + + if (!target.isSameTeam(editedTeam) && contains(editedTeam)) { + throw new DuplicateTeamException(); + } + + internalList.set(index, editedTeam); + } + + /** + * Removes the equivalent person from the list. + * The person must exist in the list. + */ + public void remove(Team toRemove) { + requireNonNull(toRemove); + if (!internalList.remove(toRemove)) { + throw new TeamNotFoundException(); + } + } + + /** + * Add or delete person from TeamList depending on presence or absence of team tag respectively. + */ + public void updatePersonInTeams(Person person) { + requireNonNull(person); + Tag[] allTeamTags = new Tag[person.getTeams().size()]; + person.getTeams().toArray(allTeamTags); + + for (Team team : internalList) { + boolean isPresent = false; + for (Tag tag : allTeamTags) { + if (tag.getName().equals(team.toString())) { + Team editedTeam = addNameToTeamMember(team, person.getName()); + setTeam(team, editedTeam); + isPresent = true; + break; + } + } + if (!isPresent) { + Team editedTeam = removeNameFromTeamMember(team, person.getName()); + setTeam(team, editedTeam); + } + } + + } + + /** + * delete person from all teams in TeamList. + */ + public void removeFromAllTeams(Person person) { + requireNonNull(person); + Name nameToRemove = person.getName(); + for (Team team : internalList) { + if (team.getMembers().contains(nameToRemove)) { + Team editedTeam = removeNameFromTeamMember(team, nameToRemove); + setTeam(team, editedTeam); + } + } + + } + + public void setTeams(UniqueTeamList replacement) { + requireNonNull(replacement); + internalList.setAll(replacement.internalList); + } + + /** + * Replaces the contents of this list with {@code teams}. + * {@code teams} must not contain duplicate teams. + */ + public void setTeams(List teams) { + requireAllNonNull(teams); + if (!teamsAreUnique(teams)) { + throw new DuplicateTeamException(); + } + + internalList.setAll(teams); + } + + /** + * 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 UniqueTeamList // instanceof handles nulls + && internalList.equals(((UniqueTeamList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + + /** + * Returns true if {@code teams} contains only unique teams. + */ + private boolean teamsAreUnique(List teams) { + for (int i = 0; i < teams.size() - 1; i++) { + for (int j = i + 1; j < teams.size(); j++) { + if (teams.get(i).isSameTeam(teams.get(j))) { + return false; + } + } + } + return true; + } + + private Team addNameToTeamMember(Team team, Name name) { + HashSet editedNames = new HashSet<>(); + editedNames.addAll(team.getMembers()); + editedNames.add(name); + return new Team(team, editedNames); + } + + private Team removeNameFromTeamMember(Team team, Name name) { + HashSet editedNames = new HashSet<>(); + editedNames.addAll(team.getMembers()); + editedNames.remove(name); + return new Team(team, editedNames); + } + +} diff --git a/src/main/java/teambuilder/model/team/exceptions/DuplicateTeamException.java b/src/main/java/teambuilder/model/team/exceptions/DuplicateTeamException.java new file mode 100644 index 00000000000..47000c0dc97 --- /dev/null +++ b/src/main/java/teambuilder/model/team/exceptions/DuplicateTeamException.java @@ -0,0 +1,11 @@ +package teambuilder.model.team.exceptions; + +/** + * Signals that the operation will result in duplicate Teams (Teams are considered duplicates if they have the same + * name). + */ +public class DuplicateTeamException extends RuntimeException { + public DuplicateTeamException() { + super("Operation would result in duplicate teams"); + } +} diff --git a/src/main/java/teambuilder/model/team/exceptions/TeamNotFoundException.java b/src/main/java/teambuilder/model/team/exceptions/TeamNotFoundException.java new file mode 100644 index 00000000000..271809a96cc --- /dev/null +++ b/src/main/java/teambuilder/model/team/exceptions/TeamNotFoundException.java @@ -0,0 +1,7 @@ +package teambuilder.model.team.exceptions; + +/** + * Signals that the operation is unable to find the specified team. + */ +public class TeamNotFoundException extends RuntimeException { +} diff --git a/src/main/java/teambuilder/model/util/SampleDataUtil.java b/src/main/java/teambuilder/model/util/SampleDataUtil.java new file mode 100644 index 00000000000..59d8f9d033f --- /dev/null +++ b/src/main/java/teambuilder/model/util/SampleDataUtil.java @@ -0,0 +1,70 @@ +package teambuilder.model.util; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.TeamBuilder; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; + +/** + * 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"), Phone.of("87438807"), Email.of("alexyeoh@example.com"), + Address.of("Blk 30 Geylang Street 29, #06-40"), Major.of("Computer Science"), + getTagSet("friends"), getTagSet()), + new Person(new Name("Bernice Yu"), Phone.of("99272758"), Email.of("berniceyu@example.com"), + Address.of("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), Major.of("Computer Science"), + getTagSet("colleagues", "friends"), getTagSet()), + new Person(new Name("Charlotte Oliveiro"), Phone.of("93210283"), Email.of("charlotte@example.com"), + Address.of("Blk 11 Ang Mo Kio Street 74, #11-04"), Major.of("Computer Science"), + getTagSet("neighbours"), getTagSet()), + new Person(new Name("David Li"), Phone.of("91031282"), Email.of("lidavid@example.com"), + Address.of("Blk 436 Serangoon Gardens Street 26, #16-43"), Major.of("Computer Science"), + getTagSet("family"), getTagSet()), + new Person(new Name("Irfan Ibrahim"), Phone.of("92492021"), Email.of("irfan@example.com"), + Address.of("Blk 47 Tampines Street 20, #17-35"), Major.of("Computer Science"), + getTagSet("classmates"), getTagSet()), + new Person(new Name("Roy Balakrishnan"), Phone.of("92624417"), Email.of("royb@example.com"), + Address.of("Blk 45 Aljunied Street 85, #11-31"), Major.of("Computer Science"), + getTagSet("colleagues"), getTagSet()) + }; + } + + public static ReadOnlyTeamBuilder getSampleAddressBook() { + TeamBuilder sampleAb = new TeamBuilder(); + for (Person samplePerson : getSamplePersons()) { + sampleAb.addPerson(samplePerson); + } + return sampleAb; + } + + /** + * Returns a tag set containing the list of strings given. + */ + public static Set getTagSet(String... strings) { + return Arrays.stream(strings) + .map(Tag::new) + .collect(Collectors.toSet()); + } + + /** + * Returns a name set containing the list of strings given. + */ + public static Set getNameSet(String... strings) { + return Arrays.stream(strings) + .map(Name::new) + .collect(Collectors.toSet()); + } + +} diff --git a/src/main/java/teambuilder/storage/JsonAdaptedName.java b/src/main/java/teambuilder/storage/JsonAdaptedName.java new file mode 100644 index 00000000000..92305cdda3e --- /dev/null +++ b/src/main/java/teambuilder/storage/JsonAdaptedName.java @@ -0,0 +1,46 @@ +package teambuilder.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.model.person.Name; + +/** + * Jackson-friendly version of {@link Name}. + */ +public class JsonAdaptedName { + private final String name; + + /** + * Constructs a {@code JsonAdaptedName} with the given {@code name}. + */ + @JsonCreator + public JsonAdaptedName(String name) { + this.name = name; + } + + /** + * Converts a given {@code name} into this class for Jackson use. + */ + public JsonAdaptedName(Name source) { + name = source.toString(); + } + + @JsonValue + public String getName() { + return name; + } + + /** + * Converts this Jackson-friendly adapted name object into the model's {@code name} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted tag. + */ + public Name toModelType() throws IllegalValueException { + if (!Name.isValidName(name)) { + throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS); + } + return new Name(name); + } +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/teambuilder/storage/JsonAdaptedPerson.java similarity index 62% rename from src/main/java/seedu/address/storage/JsonAdaptedPerson.java rename to src/main/java/teambuilder/storage/JsonAdaptedPerson.java index a6321cec2ea..33800a1e78b 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/teambuilder/storage/JsonAdaptedPerson.java @@ -1,4 +1,4 @@ -package seedu.address.storage; +package teambuilder.storage; import java.util.ArrayList; import java.util.HashSet; @@ -9,13 +9,14 @@ 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; +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; /** * Jackson-friendly version of {@link Person}. @@ -28,7 +29,9 @@ class JsonAdaptedPerson { private final String phone; private final String email; private final String address; + private final String major; private final List tagged = new ArrayList<>(); + private final List teams = new ArrayList<>(); /** * Constructs a {@code JsonAdaptedPerson} with the given person details. @@ -36,27 +39,36 @@ class JsonAdaptedPerson { @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tagged") List tagged) { + @JsonProperty("major") String major, @JsonProperty("tagged") List tagged, + @JsonProperty("teams") List teams) { this.name = name; this.phone = phone; this.email = email; this.address = address; + this.major = major; if (tagged != null) { this.tagged.addAll(tagged); } + if (teams != null) { + this.teams.addAll(teams); + } } /** * 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; + name = source.getName().toString(); + phone = source.getPhone().toString(); + email = source.getEmail().toString(); + address = source.getAddress().toString(); + major = source.getMajor().toString(); tagged.addAll(source.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList())); + teams.addAll(source.getTeams().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList())); } /** @@ -69,6 +81,10 @@ public Person toModelType() throws IllegalValueException { for (JsonAdaptedTag tag : tagged) { personTags.add(tag.toModelType()); } + final List personTeams = new ArrayList<>(); + for (JsonAdaptedTag tag : teams) { + personTeams.add(tag.toModelType()); + } if (name == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName())); @@ -84,7 +100,7 @@ public Person toModelType() throws IllegalValueException { if (!Phone.isValidPhone(phone)) { throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS); } - final Phone modelPhone = new Phone(phone); + final Phone modelPhone = Phone.of(phone); if (email == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName())); @@ -92,7 +108,7 @@ public Person toModelType() throws IllegalValueException { if (!Email.isValidEmail(email)) { throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS); } - final Email modelEmail = new Email(email); + final Email modelEmail = Email.of(email); if (address == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName())); @@ -100,10 +116,21 @@ public Person toModelType() throws IllegalValueException { if (!Address.isValidAddress(address)) { throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS); } - final Address modelAddress = new Address(address); + final Address modelAddress = Address.of(address); + + if (major == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Major.class.getSimpleName())); + } + if (!Address.isValidAddress(major)) { + throw new IllegalValueException(Major.MESSAGE_CONSTRAINTS); + } + final Major modelMajor = Major.of(major); final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); + + final Set modelTeams = new HashSet<>(personTeams); + + return new Person(modelName, modelPhone, modelEmail, modelAddress, modelMajor, modelTags, modelTeams); } } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/teambuilder/storage/JsonAdaptedTag.java similarity index 89% rename from src/main/java/seedu/address/storage/JsonAdaptedTag.java rename to src/main/java/teambuilder/storage/JsonAdaptedTag.java index 0df22bdb754..3377c4e872e 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java +++ b/src/main/java/teambuilder/storage/JsonAdaptedTag.java @@ -1,10 +1,10 @@ -package seedu.address.storage; +package teambuilder.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; +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.model.tag.Tag; /** * Jackson-friendly version of {@link Tag}. diff --git a/src/main/java/teambuilder/storage/JsonAdaptedTeam.java b/src/main/java/teambuilder/storage/JsonAdaptedTeam.java new file mode 100644 index 00000000000..e32688b6f50 --- /dev/null +++ b/src/main/java/teambuilder/storage/JsonAdaptedTeam.java @@ -0,0 +1,105 @@ +package teambuilder.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 teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.model.person.Name; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + + +/** + * Jackson-friendly version of {@link Team}. + */ +public class JsonAdaptedTeam { + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Team's %s field is missing!"; + + private final String teamName; + private final String teamDesc; + private final List skills = new ArrayList<>(); + private final List members = new ArrayList<>(); + + /** + * Constructs a {@code JsonAdaptedTeam} with the given team details. + */ + @JsonCreator + public JsonAdaptedTeam(@JsonProperty("teamName") String teamName, + @JsonProperty("teamDesc") String teamDesc, + @JsonProperty("skills") List skillTags, + @JsonProperty("members") List members) { + this.teamName = teamName; + this.teamDesc = teamDesc; + if (skillTags != null) { + this.skills.addAll(skillTags); + } + if (members != null) { + this.members.addAll(members); + } + } + + /** + * Converts a given {@code Team} into this class for Jackson use. + */ + public JsonAdaptedTeam(Team source) { + teamName = source.getTeamName().toString(); + teamDesc = source.getDesc().toString(); + skills.addAll(source.getSkillTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList())); + members.addAll(source.getMembers().stream() + .map(JsonAdaptedName::new) + .collect(Collectors.toList())); + + } + + /** + * Converts this Jackson-friendly adapted team object into the model's {@code team} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted team. + */ + public Team toModelType() throws IllegalValueException { + final List teamMembers = new ArrayList<>(); + for (JsonAdaptedName name : members) { + teamMembers.add(name.toModelType()); + } + final List skilltags = new ArrayList<>(); + for (JsonAdaptedTag skillTag : skills) { + skilltags.add(skillTag.toModelType()); + } + if (teamName == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + TeamName.class.getSimpleName())); + } + if (!TeamName.isValidTeamName(teamName)) { + throw new IllegalValueException(TeamName.MESSAGE_CONSTRAINTS); + } + final TeamName modelName = new TeamName(teamName); + // TODO: check if members of team exists in team builder before adding team. + if (teamDesc == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + Desc.class.getSimpleName())); + } + if (!Desc.isValidTeamDesc(teamDesc)) { + throw new IllegalValueException(Desc.MESSAGE_CONSTRAINTS); + } + final Desc modelDesc = new Desc(teamDesc); + + final Set modelSkillTags = new HashSet<>(skilltags); + + Team modelTeam = new Team(modelName, modelDesc, modelSkillTags); + for (Name member : teamMembers) { + modelTeam.addPerson(member); + } + return modelTeam; + } + +} diff --git a/src/main/java/teambuilder/storage/JsonSerializableTeamBuilder.java b/src/main/java/teambuilder/storage/JsonSerializableTeamBuilder.java new file mode 100644 index 00000000000..d016e8e3a4a --- /dev/null +++ b/src/main/java/teambuilder/storage/JsonSerializableTeamBuilder.java @@ -0,0 +1,115 @@ +package teambuilder.storage; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRootName; + +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.TeamBuilder; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +/** + * An Immutable AddressBook that is serializable to JSON format. + */ +@JsonRootName(value = "addressbook") +class JsonSerializableTeamBuilder { + + public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; + public static final String MESSAGE_DUPLICATE_TEAM = "Team list contains duplicate team(s)."; + public static final String MESSAGE_TEAM_NOT_EXIST = "TeamTag of person does not exist in Team list."; + public static final String MESSAGE_PERSON_NOT_EXIST = "Person does not exist in Person list."; + + private final List persons = new ArrayList<>(); + private final List teams = new ArrayList<>(); + + /** + * Constructs a {@code JsonSerializableAddressBook} with the given persons. + */ + @JsonCreator + public JsonSerializableTeamBuilder(@JsonProperty("persons") List persons, + @JsonProperty("teams") List teams) { + this.persons.addAll(persons); + this.teams.addAll(teams); + } + + + /** + * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use. + * + * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}. + */ + public JsonSerializableTeamBuilder(ReadOnlyTeamBuilder source) { + persons.addAll(source.getPersonList().stream() + .map(JsonAdaptedPerson::new) + .collect(Collectors.toList())); + + teams.addAll(source.getTeamList().stream() + .map(JsonAdaptedTeam::new) + .collect(Collectors.toList())); + } + + /** + * Converts this TeamBuilder into the model's {@code AddressBook} object. + * + * @throws IllegalValueException if there were any data constraints violated. + */ + public TeamBuilder toModelType() throws IllegalValueException { + TeamBuilder teamBuilder = new TeamBuilder(); + + List teamList = new ArrayList<>(); + for (JsonAdaptedTeam jsonAdaptedTeam : teams) { + Team team = jsonAdaptedTeam.toModelType(); + if (teamBuilder.hasTeam(team)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_TEAM); + } + teamList.add(team); + } + List teamNameList = teamList.stream() + .map(Team::getTeamName) + .map(TeamName::toString) + .collect(Collectors.toList()); + + List personList = new ArrayList<>(); + for (JsonAdaptedPerson jsonAdaptedPerson : persons) { + Person person = jsonAdaptedPerson.toModelType(); + if (teamBuilder.hasPerson(person)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON); + } + personList.add(person); + } + List personNameList = personList.stream() + .map(Person::getName) + .collect(Collectors.toList()); + + + for (Team t : teamList) { + for (Name member: t.getMembers()) { + if (!personNameList.contains(member)) { + throw new IllegalValueException(MESSAGE_PERSON_NOT_EXIST); + } + } + teamBuilder.addTeam(t); + } + + for (Person p : personList) { + for (Tag teamTag : p.getTeams()) { + if (!teamNameList.contains(teamTag.tagName)) { + throw new IllegalValueException(MESSAGE_TEAM_NOT_EXIST); + } + } + teamBuilder.addPerson(p); + } + + return teamBuilder; + } + +} diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/teambuilder/storage/JsonTeamBuilderStorage.java similarity index 61% rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java rename to src/main/java/teambuilder/storage/JsonTeamBuilderStorage.java index dfab9daaa0d..a3dbc7913e9 100644 --- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java +++ b/src/main/java/teambuilder/storage/JsonTeamBuilderStorage.java @@ -1,4 +1,4 @@ -package seedu.address.storage; +package teambuilder.storage; import static java.util.Objects.requireNonNull; @@ -7,23 +7,23 @@ import java.util.Optional; import java.util.logging.Logger; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.commons.util.FileUtil; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.ReadOnlyAddressBook; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.commons.util.FileUtil; +import teambuilder.commons.util.JsonUtil; +import teambuilder.model.ReadOnlyTeamBuilder; /** * A class to access AddressBook data stored as a json file on the hard disk. */ -public class JsonAddressBookStorage implements AddressBookStorage { +public class JsonTeamBuilderStorage implements TeamBuilderStorage { - private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class); + private static final Logger logger = LogsCenter.getLogger(JsonTeamBuilderStorage.class); private Path filePath; - public JsonAddressBookStorage(Path filePath) { + public JsonTeamBuilderStorage(Path filePath) { this.filePath = filePath; } @@ -32,7 +32,7 @@ public Path getAddressBookFilePath() { } @Override - public Optional readAddressBook() throws DataConversionException { + public Optional readAddressBook() throws DataConversionException { return readAddressBook(filePath); } @@ -42,11 +42,11 @@ public Optional readAddressBook() throws DataConversionExce * @param filePath location of the data. Cannot be null. * @throws DataConversionException if the file is not in the correct format. */ - public Optional readAddressBook(Path filePath) throws DataConversionException { + public Optional readAddressBook(Path filePath) throws DataConversionException { requireNonNull(filePath); - Optional jsonAddressBook = JsonUtil.readJsonFile( - filePath, JsonSerializableAddressBook.class); + Optional jsonAddressBook = JsonUtil.readJsonFile( + filePath, JsonSerializableTeamBuilder.class); if (!jsonAddressBook.isPresent()) { return Optional.empty(); } @@ -60,21 +60,21 @@ public Optional readAddressBook(Path filePath) throws DataC } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { + public void saveAddressBook(ReadOnlyTeamBuilder addressBook) throws IOException { saveAddressBook(addressBook, filePath); } /** - * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}. + * Similar to {@link #saveAddressBook(ReadOnlyTeamBuilder)}. * * @param filePath location of the data. Cannot be null. */ - public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException { + public void saveAddressBook(ReadOnlyTeamBuilder addressBook, Path filePath) throws IOException { requireNonNull(addressBook); requireNonNull(filePath); FileUtil.createIfMissing(filePath); - JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath); + JsonUtil.saveJsonFile(new JsonSerializableTeamBuilder(addressBook), filePath); } } diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/teambuilder/storage/JsonUserPrefsStorage.java similarity index 83% rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java rename to src/main/java/teambuilder/storage/JsonUserPrefsStorage.java index bc2bbad84aa..2fcbbc8014c 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/teambuilder/storage/JsonUserPrefsStorage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; +package teambuilder.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.commons.util.JsonUtil; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.UserPrefs; /** * A class to access UserPrefs stored in the hard disk as a json file diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/teambuilder/storage/Storage.java similarity index 51% rename from src/main/java/seedu/address/storage/Storage.java rename to src/main/java/teambuilder/storage/Storage.java index beda8bd9f11..65f019c7dca 100644 --- a/src/main/java/seedu/address/storage/Storage.java +++ b/src/main/java/teambuilder/storage/Storage.java @@ -1,18 +1,18 @@ -package seedu.address.storage; +package teambuilder.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.UserPrefs; /** * API of the Storage component */ -public interface Storage extends AddressBookStorage, UserPrefsStorage { +public interface Storage extends TeamBuilderStorage, UserPrefsStorage { @Override Optional readUserPrefs() throws DataConversionException, IOException; @@ -24,9 +24,9 @@ public interface Storage extends AddressBookStorage, UserPrefsStorage { Path getAddressBookFilePath(); @Override - Optional readAddressBook() throws DataConversionException, IOException; + Optional readAddressBook() throws DataConversionException, IOException; @Override - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; + void saveAddressBook(ReadOnlyTeamBuilder addressBook) throws IOException; } diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/teambuilder/storage/StorageManager.java similarity index 75% rename from src/main/java/seedu/address/storage/StorageManager.java rename to src/main/java/teambuilder/storage/StorageManager.java index 6cfa0162164..bdb866abc54 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/teambuilder/storage/StorageManager.java @@ -1,15 +1,15 @@ -package seedu.address.storage; +package teambuilder.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; import java.util.logging.Logger; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.UserPrefs; /** * Manages storage of AddressBook data in local storage. @@ -17,13 +17,13 @@ public class StorageManager implements Storage { private static final Logger logger = LogsCenter.getLogger(StorageManager.class); - private AddressBookStorage addressBookStorage; + private TeamBuilderStorage addressBookStorage; private UserPrefsStorage userPrefsStorage; /** * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}. */ - public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) { + public StorageManager(TeamBuilderStorage addressBookStorage, UserPrefsStorage userPrefsStorage) { this.addressBookStorage = addressBookStorage; this.userPrefsStorage = userPrefsStorage; } @@ -54,23 +54,23 @@ public Path getAddressBookFilePath() { } @Override - public Optional readAddressBook() throws DataConversionException, IOException { + public Optional readAddressBook() throws DataConversionException, IOException { return readAddressBook(addressBookStorage.getAddressBookFilePath()); } @Override - public Optional readAddressBook(Path filePath) throws DataConversionException, IOException { + public Optional readAddressBook(Path filePath) throws DataConversionException, IOException { logger.fine("Attempting to read data from file: " + filePath); return addressBookStorage.readAddressBook(filePath); } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { + public void saveAddressBook(ReadOnlyTeamBuilder addressBook) throws IOException { saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath()); } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException { + public void saveAddressBook(ReadOnlyTeamBuilder addressBook, Path filePath) throws IOException { logger.fine("Attempting to write to data file: " + filePath); addressBookStorage.saveAddressBook(addressBook, filePath); } diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/teambuilder/storage/TeamBuilderStorage.java similarity index 53% rename from src/main/java/seedu/address/storage/AddressBookStorage.java rename to src/main/java/teambuilder/storage/TeamBuilderStorage.java index 4599182b3f9..7de76dadc7e 100644 --- a/src/main/java/seedu/address/storage/AddressBookStorage.java +++ b/src/main/java/teambuilder/storage/TeamBuilderStorage.java @@ -1,16 +1,16 @@ -package seedu.address.storage; +package teambuilder.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.model.ReadOnlyTeamBuilder; /** - * Represents a storage for {@link seedu.address.model.AddressBook}. + * Represents a storage for {@link teambuilder.model.TeamBuilder}. */ -public interface AddressBookStorage { +public interface TeamBuilderStorage { /** * Returns the file path of the data file. @@ -18,28 +18,28 @@ public interface AddressBookStorage { Path getAddressBookFilePath(); /** - * Returns AddressBook data as a {@link ReadOnlyAddressBook}. + * Returns AddressBook data as a {@link ReadOnlyTeamBuilder}. * Returns {@code Optional.empty()} if storage file is not found. * @throws DataConversionException if the data in storage is not in the expected format. * @throws IOException if there was any problem when reading from the storage. */ - Optional readAddressBook() throws DataConversionException, IOException; + Optional readAddressBook() throws DataConversionException, IOException; /** * @see #getAddressBookFilePath() */ - Optional readAddressBook(Path filePath) throws DataConversionException, IOException; + Optional readAddressBook(Path filePath) throws DataConversionException, IOException; /** - * Saves the given {@link ReadOnlyAddressBook} to the storage. + * Saves the given {@link ReadOnlyTeamBuilder} to the storage. * @param addressBook cannot be null. * @throws IOException if there was any problem writing to the file. */ - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; + void saveAddressBook(ReadOnlyTeamBuilder addressBook) throws IOException; /** - * @see #saveAddressBook(ReadOnlyAddressBook) + * @see #saveAddressBook(ReadOnlyTeamBuilder) */ - void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException; + void saveAddressBook(ReadOnlyTeamBuilder addressBook, Path filePath) throws IOException; } diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/teambuilder/storage/UserPrefsStorage.java similarity index 71% rename from src/main/java/seedu/address/storage/UserPrefsStorage.java rename to src/main/java/teambuilder/storage/UserPrefsStorage.java index 29eef178dbc..c84b9c52b67 100644 --- a/src/main/java/seedu/address/storage/UserPrefsStorage.java +++ b/src/main/java/teambuilder/storage/UserPrefsStorage.java @@ -1,15 +1,15 @@ -package seedu.address.storage; +package teambuilder.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.UserPrefs; /** - * Represents a storage for {@link seedu.address.model.UserPrefs}. + * Represents a storage for {@link teambuilder.model.UserPrefs}. */ public interface UserPrefsStorage { @@ -27,7 +27,7 @@ public interface UserPrefsStorage { Optional readUserPrefs() throws DataConversionException, IOException; /** - * Saves the given {@link seedu.address.model.ReadOnlyUserPrefs} to the storage. + * Saves the given {@link teambuilder.model.ReadOnlyUserPrefs} to the storage. * @param userPrefs cannot be null. * @throws IOException if there was any problem writing to the file. */ diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/teambuilder/ui/CommandBox.java similarity index 89% rename from src/main/java/seedu/address/ui/CommandBox.java rename to src/main/java/teambuilder/ui/CommandBox.java index 9e75478664b..9d5c55724eb 100644 --- a/src/main/java/seedu/address/ui/CommandBox.java +++ b/src/main/java/teambuilder/ui/CommandBox.java @@ -1,12 +1,12 @@ -package seedu.address.ui; +package teambuilder.ui; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.TextField; import javafx.scene.layout.Region; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; +import teambuilder.logic.commands.CommandResult; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.logic.parser.exceptions.ParseException; /** * The UI component that is responsible for receiving user command inputs. @@ -77,7 +77,7 @@ public interface CommandExecutor { /** * Executes the command and returns the result. * - * @see seedu.address.logic.Logic#execute(String) + * @see teambuilder.logic.Logic#execute(String) */ CommandResult execute(String commandText) throws CommandException, ParseException; } diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/teambuilder/ui/HelpWindow.java similarity index 93% rename from src/main/java/seedu/address/ui/HelpWindow.java rename to src/main/java/teambuilder/ui/HelpWindow.java index 3f16b2fcf26..a99c2f87ada 100644 --- a/src/main/java/seedu/address/ui/HelpWindow.java +++ b/src/main/java/teambuilder/ui/HelpWindow.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import java.util.logging.Logger; @@ -8,14 +8,14 @@ import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.stage.Stage; -import seedu.address.commons.core.LogsCenter; +import teambuilder.commons.core.LogsCenter; /** * Controller for a help page */ public class HelpWindow extends UiPart { - public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html"; + public static final String USERGUIDE_URL = "https://ay2223s2-cs2103t-t17-1.github.io/tp/UserGuide.html"; public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL; private static final Logger logger = LogsCenter.getLogger(HelpWindow.class); diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/teambuilder/ui/MainWindow.java similarity index 90% rename from src/main/java/seedu/address/ui/MainWindow.java rename to src/main/java/teambuilder/ui/MainWindow.java index 9106c3aa6e5..cfbd1309a6a 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/teambuilder/ui/MainWindow.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import java.util.logging.Logger; @@ -10,12 +10,12 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.StackPane; import javafx.stage.Stage; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.core.LogsCenter; -import seedu.address.logic.Logic; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.core.LogsCenter; +import teambuilder.logic.Logic; +import teambuilder.logic.commands.CommandResult; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.logic.parser.exceptions.ParseException; /** * The Main Window. Provides the basic application layout containing @@ -32,6 +32,7 @@ public class MainWindow extends UiPart { // Independent Ui parts residing in this Ui container private PersonListPanel personListPanel; + private TeamListPanel teamListPanel; private ResultDisplay resultDisplay; private HelpWindow helpWindow; @@ -44,6 +45,9 @@ public class MainWindow extends UiPart { @FXML private StackPane personListPanelPlaceholder; + @FXML + private StackPane teamListPanelPlaceholder; + @FXML private StackPane resultDisplayPlaceholder; @@ -113,6 +117,9 @@ void fillInnerParts() { personListPanel = new PersonListPanel(logic.getFilteredPersonList()); personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + teamListPanel = new TeamListPanel(logic.getAddressBook().getTeamList()); + teamListPanelPlaceholder.getChildren().add(teamListPanel.getRoot()); + resultDisplay = new ResultDisplay(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); @@ -170,7 +177,7 @@ public PersonListPanel getPersonListPanel() { /** * Executes the command and returns the result. * - * @see seedu.address.logic.Logic#execute(String) + * @see teambuilder.logic.Logic#execute(String) */ private CommandResult executeCommand(String commandText) throws CommandException, ParseException { try { diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/teambuilder/ui/PersonCard.java similarity index 55% rename from src/main/java/seedu/address/ui/PersonCard.java rename to src/main/java/teambuilder/ui/PersonCard.java index 7fc927bc5d9..ba988956ffc 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/teambuilder/ui/PersonCard.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import java.util.Comparator; @@ -7,10 +7,10 @@ import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; -import seedu.address.model.person.Person; +import teambuilder.model.person.Person; /** - * An UI component that displays information of a {@code Person}. + * A UI component that displays information of a {@code Person}. */ public class PersonCard extends UiPart { @@ -39,7 +39,11 @@ public class PersonCard extends UiPart { @FXML private Label email; @FXML + private Label major; + @FXML private FlowPane tags; + @FXML + private FlowPane teams; /** * Creates a {@code PersonCode} with the given {@code Person} and index to display. @@ -49,12 +53,52 @@ public PersonCard(Person person, int displayedIndex) { 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); + setPhone(person); + setAddress(person); + setEmail(person); + setMajor(person); person.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); + person.getTeams().stream() + .sorted(Comparator.comparing(tag -> tag.tagName)) + .forEach(tag -> teams.getChildren().add(new Label(tag.tagName))); + } + + private void setPhone(Person person) { + if (person.getPhone().isEmptyPhone()) { + phone.setVisible(false); + phone.setManaged(false); + } else { + phone.setText(person.getPhone().toString()); + } + } + + private void setEmail(Person person) { + if (person.getEmail().isEmptyEmail()) { + email.setVisible(false); + email.setManaged(false); + } else { + email.setText(person.getEmail().toString()); + } + } + + private void setMajor(Person person) { + if (person.getMajor().isEmptyMajor()) { + major.setVisible(false); + major.setManaged(false); + } else { + major.setText(person.getMajor().toString()); + } + } + + private void setAddress(Person person) { + if (person.getAddress().isEmptyAddress()) { + address.setVisible(false); + address.setManaged(false); + } else { + address.setText(person.getAddress().toString()); + } } @Override diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/teambuilder/ui/PersonListPanel.java similarity index 92% rename from src/main/java/seedu/address/ui/PersonListPanel.java rename to src/main/java/teambuilder/ui/PersonListPanel.java index f4c501a897b..dab2fb64f79 100644 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ b/src/main/java/teambuilder/ui/PersonListPanel.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import java.util.logging.Logger; @@ -7,8 +7,8 @@ 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; +import teambuilder.commons.core.LogsCenter; +import teambuilder.model.person.Person; /** * Panel containing the list of persons. diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/teambuilder/ui/ResultDisplay.java similarity index 95% rename from src/main/java/seedu/address/ui/ResultDisplay.java rename to src/main/java/teambuilder/ui/ResultDisplay.java index 7d98e84eedf..4ca17dd151a 100644 --- a/src/main/java/seedu/address/ui/ResultDisplay.java +++ b/src/main/java/teambuilder/ui/ResultDisplay.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/teambuilder/ui/StatusBarFooter.java similarity index 96% rename from src/main/java/seedu/address/ui/StatusBarFooter.java rename to src/main/java/teambuilder/ui/StatusBarFooter.java index b577f829423..b3c99b5c7b5 100644 --- a/src/main/java/seedu/address/ui/StatusBarFooter.java +++ b/src/main/java/teambuilder/ui/StatusBarFooter.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/src/main/java/teambuilder/ui/TeamCard.java b/src/main/java/teambuilder/ui/TeamCard.java new file mode 100644 index 00000000000..1a2493b1742 --- /dev/null +++ b/src/main/java/teambuilder/ui/TeamCard.java @@ -0,0 +1,78 @@ +package teambuilder.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 teambuilder.model.team.Team; + +//@@author chen-jerry-junior +/** + * A UI component that displays information of a {@code Team}. + */ +public class TeamCard extends UiPart { + + private static final String FXML = "TeamListCard.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 Team team; + + @FXML + private HBox cardPane; + @FXML + private Label teamName; + @FXML + private Label id; + @FXML + private Label teamDesc; + @FXML + private FlowPane skillTags; + @FXML + private FlowPane members; + + /** + * Creates a {@code TeamCode} with the given {@code Team} and index to display. + */ + public TeamCard(Team team, int displayedIndex) { + super(FXML); + this.team = team; + id.setText(displayedIndex + ". "); + teamName.setText(team.getName().teamName); + teamDesc.setText(team.getDesc().value); + team.getTags().stream() + .sorted(Comparator.comparing(tag -> tag.tagName)) + .forEach(tag -> skillTags.getChildren().add(new Label(tag.tagName))); + team.getMembers().stream() + .sorted(Comparator.comparing(member -> member.fullName)) + .forEach(member -> members.getChildren().add(new Label(member.fullName))); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof TeamCard)) { + return false; + } + + // state check + TeamCard card = (TeamCard) other; + return id.getText().equals(card.id.getText()) + && team.equals(card.team); + } +} + diff --git a/src/main/java/teambuilder/ui/TeamListPanel.java b/src/main/java/teambuilder/ui/TeamListPanel.java new file mode 100644 index 00000000000..bf1db6b4e91 --- /dev/null +++ b/src/main/java/teambuilder/ui/TeamListPanel.java @@ -0,0 +1,50 @@ +package teambuilder.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 teambuilder.commons.core.LogsCenter; +import teambuilder.model.team.Team; + +//@@author chen-jerry-junior +/** + * Panel containing the list of teams. + */ +public class TeamListPanel extends UiPart { + private static final String FXML = "TeamListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(TeamListPanel.class); + + @FXML + private ListView teamListView; + + /** + * Creates a {@code PersonListPanel} with the given {@code ObservableList}. + */ + public TeamListPanel(ObservableList teamList) { + super(FXML); + teamListView.setItems(teamList); + teamListView.setCellFactory(listView -> new TeamListViewCell()); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Team} using a {@code TeamCard}. + */ + class TeamListViewCell extends ListCell { + @Override + protected void updateItem(Team team, boolean empty) { + super.updateItem(team, empty); + + if (empty || team == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new TeamCard(team, getIndex() + 1).getRoot()); + } + } + } + +} diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/teambuilder/ui/Ui.java similarity index 86% rename from src/main/java/seedu/address/ui/Ui.java rename to src/main/java/teambuilder/ui/Ui.java index 17aa0b494fe..bece4f4a23a 100644 --- a/src/main/java/seedu/address/ui/Ui.java +++ b/src/main/java/teambuilder/ui/Ui.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import javafx.stage.Stage; diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/teambuilder/ui/UiManager.java similarity index 91% rename from src/main/java/seedu/address/ui/UiManager.java rename to src/main/java/teambuilder/ui/UiManager.java index fdf024138bc..a38af022241 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/teambuilder/ui/UiManager.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import java.util.logging.Logger; @@ -7,10 +7,10 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.image.Image; import javafx.stage.Stage; -import seedu.address.MainApp; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; +import teambuilder.MainApp; +import teambuilder.commons.core.LogsCenter; +import teambuilder.commons.util.StringUtil; +import teambuilder.logic.Logic; /** * The manager of the UI component. @@ -20,7 +20,7 @@ public class UiManager implements Ui { public static final String ALERT_DIALOG_PANE_FIELD_ID = "alertDialogPane"; private static final Logger logger = LogsCenter.getLogger(UiManager.class); - private static final String ICON_APPLICATION = "/images/address_book_32.png"; + private static final String ICON_APPLICATION = "/images/team_builder_icon.png"; private Logic logic; private MainWindow mainWindow; diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/teambuilder/ui/UiPart.java similarity index 97% rename from src/main/java/seedu/address/ui/UiPart.java rename to src/main/java/teambuilder/ui/UiPart.java index fc820e01a9c..b0306013ec4 100644 --- a/src/main/java/seedu/address/ui/UiPart.java +++ b/src/main/java/teambuilder/ui/UiPart.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import static java.util.Objects.requireNonNull; @@ -6,7 +6,7 @@ import java.net.URL; import javafx.fxml.FXMLLoader; -import seedu.address.MainApp; +import teambuilder.MainApp; /** * Represents a distinct part of the UI. e.g. Windows, dialogs, panels, status bars, etc. diff --git a/src/main/resources/images/address_book_32.png b/src/main/resources/images/address_book_32.png deleted file mode 100644 index 29810cf1fd9..00000000000 Binary files a/src/main/resources/images/address_book_32.png and /dev/null differ diff --git a/src/main/resources/images/team_builder_icon.png b/src/main/resources/images/team_builder_icon.png new file mode 100644 index 00000000000..e5e7cfd2156 Binary files /dev/null and b/src/main/resources/images/team_builder_icon.png differ diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 36e6b001cd8..f074daa2fce 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -350,3 +350,45 @@ -fx-background-radius: 2; -fx-font-size: 11; } + +#teams { + -fx-hgap: 7; + -fx-vgap: 3; +} + +#teams .label { + -fx-text-fill: white; + -fx-background-color: #C9333D; + -fx-padding: 1 3 1 3; + -fx-border-radius: 2; + -fx-background-radius: 2; + -fx-font-size: 11; +} + +#skillTags { + -fx-hgap: 7; + -fx-vgap: 3; +} + +#skillTags .label { + -fx-text-fill: white; + -fx-background-color: #228C45; + -fx-padding: 1 3 1 3; + -fx-border-radius: 2; + -fx-background-radius: 2; + -fx-font-size: 11; +} + +#members { + -fx-hgap: 7; + -fx-vgap: 3; +} + +#members .label { + -fx-text-fill: white; + -fx-background-color: #DF8824; + -fx-padding: 1 3 1 3; + -fx-border-radius: 2; + -fx-background-radius: 2; + -fx-font-size: 11; +} diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index a431648f6c0..6eaeddd5acf 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -6,15 +6,15 @@ - + + - + - + @@ -33,26 +33,33 @@ - + - + - + - + - - - - - - + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index f08ea32ad55..e97b5b45192 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -9,28 +9,30 @@ - + - + - + - + diff --git a/src/main/resources/view/TeamListCard.fxml b/src/main/resources/view/TeamListCard.fxml new file mode 100644 index 00000000000..20501d9806d --- /dev/null +++ b/src/main/resources/view/TeamListCard.fxml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/TeamListPanel.fxml b/src/main/resources/view/TeamListPanel.fxml new file mode 100644 index 00000000000..d83f3cf5c71 --- /dev/null +++ b/src/main/resources/view/TeamListPanel.fxml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json index 48831cc7674..570382c095e 100644 --- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json @@ -4,11 +4,19 @@ "phone": "94351253", "email": "alice@example.com", "address": "123, Jurong West Ave 6, #08-111", - "tagged": [ "friends" ] + "major": "computer science", + "tagged": [ "Python" ] }, { "name": "Alice Pauline", "phone": "94351253", "email": "pauline@example.com", - "address": "4th street" + "address": "4th street", + "major": "computer science" + } ], + "teams" : [ { + "teamName" : "Hacker Gang", + "teamDesc" : "Hackathon group for ABC company", + "skills" : [ ], + "members" : [ ] } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json index ad3f135ae42..a3e33ba0eb5 100644 --- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json @@ -3,6 +3,13 @@ "name": "Hans Muster", "phone": "9482424", "email": "invalid@email!3e", - "address": "4th street" + "address": "4th street", + "major": "computer science" + } ], + "teams" : [ { + "teamName" : "Hacker Gang", + "teamDesc" : "Hackathon group for ABC company", + "skills" : [ ], + "members" : [ ] } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index f10eddee12e..913bfbca047 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -5,42 +5,73 @@ "phone" : "94351253", "email" : "alice@example.com", "address" : "123, Jurong West Ave 6, #08-111", - "tagged" : [ "friends" ] + "major": "computer science", + "tagged" : [ "Python" ], + "teams" : [] }, { "name" : "Benson Meier", "phone" : "98765432", "email" : "johnd@example.com", "address" : "311, Clementi Ave 2, #02-25", - "tagged" : [ "owesMoney", "friends" ] + "major": "computer science", + "tagged" : [ "C", "PgSQL" ], + "teams" : ["TeamA"] }, { "name" : "Carl Kurz", "phone" : "95352563", "email" : "heinz@example.com", "address" : "wall street", - "tagged" : [ ] + "major": "computer science", + "tagged" : [ ], + "teams" : ["TeamA"] }, { "name" : "Daniel Meier", "phone" : "87652533", "email" : "cornelia@example.com", "address" : "10th street", - "tagged" : [ "friends" ] + "major": "computer science", + "tagged" : [ "React Native" ], + "teams" : ["TeamB"] }, { "name" : "Elle Meyer", "phone" : "9482224", "email" : "werner@example.com", "address" : "michegan ave", - "tagged" : [ ] + "major": "computer science", + "tagged" : [ ], + "teams" : ["TeamB"] }, { "name" : "Fiona Kunz", "phone" : "9482427", "email" : "lydia@example.com", "address" : "little tokyo", - "tagged" : [ ] + "major": "computer science", + "tagged" : [ ], + "teams" : ["TeamC"] }, { "name" : "George Best", "phone" : "9482442", "email" : "anna@example.com", "address" : "4th street", - "tagged" : [ ] - } ] + "major": "computer science", + "tagged" : [ ], + "teams" : [] + } ], + "teams" : [ { + "teamName" : "TeamA", + "teamDesc" : "Project group TeamA", + "skills" : [ ], + "members" : ["Carl Kurz"] + }, { + "teamName" : "TeamB", + "teamDesc" : "Project group TeamB", + "skills" : ["Java", "ReactNative"], + "members" : ["Daniel Meier", "Elle Meyer"] + }, { + "teamName" : "TeamC", + "teamDesc" : "Project group TeamC", + "skills" : ["PgSQL", "C"], + "members" : ["Fiona Kunz"] + } + ] } 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/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java deleted file mode 100644 index 188c9058d20..00000000000 --- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package seedu.address.storage; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static seedu.address.testutil.Assert.assertThrows; - -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.junit.jupiter.api.Test; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.AddressBook; -import seedu.address.testutil.TypicalPersons; - -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"); - - @Test - public void toModelType_typicalPersonsFile_success() throws Exception { - JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE, - JsonSerializableAddressBook.class).get(); - AddressBook addressBookFromFile = dataFromFile.toModelType(); - AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook(); - assertEquals(addressBookFromFile, typicalPersonsAddressBook); - } - - @Test - public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception { - JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE, - JsonSerializableAddressBook.class).get(); - assertThrows(IllegalValueException.class, dataFromFile::toModelType); - } - - @Test - public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception { - JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE, - JsonSerializableAddressBook.class).get(); - assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON, - dataFromFile::toModelType); - } - -} 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/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/AppParametersTest.java b/src/test/java/teambuilder/AppParametersTest.java similarity index 98% rename from src/test/java/seedu/address/AppParametersTest.java rename to src/test/java/teambuilder/AppParametersTest.java index 61326b2d31a..73fe268bee2 100644 --- a/src/test/java/seedu/address/AppParametersTest.java +++ b/src/test/java/teambuilder/AppParametersTest.java @@ -1,4 +1,4 @@ -package seedu.address; +package teambuilder; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/seedu/address/commons/core/ConfigTest.java b/src/test/java/teambuilder/commons/core/ConfigTest.java similarity index 95% rename from src/test/java/seedu/address/commons/core/ConfigTest.java rename to src/test/java/teambuilder/commons/core/ConfigTest.java index 07cd7f73d53..6fe910a1afe 100644 --- a/src/test/java/seedu/address/commons/core/ConfigTest.java +++ b/src/test/java/teambuilder/commons/core/ConfigTest.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/src/test/java/seedu/address/commons/core/VersionTest.java b/src/test/java/teambuilder/commons/core/VersionTest.java similarity index 98% rename from src/test/java/seedu/address/commons/core/VersionTest.java rename to src/test/java/teambuilder/commons/core/VersionTest.java index 495cd231554..fe7887af2ac 100644 --- a/src/test/java/seedu/address/commons/core/VersionTest.java +++ b/src/test/java/teambuilder/commons/core/VersionTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.core; +package teambuilder.commons.core; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/address/commons/core/index/IndexTest.java b/src/test/java/teambuilder/commons/core/index/IndexTest.java similarity index 95% rename from src/test/java/seedu/address/commons/core/index/IndexTest.java rename to src/test/java/teambuilder/commons/core/index/IndexTest.java index a3ec6f8e747..0fe645be8e3 100644 --- a/src/test/java/seedu/address/commons/core/index/IndexTest.java +++ b/src/test/java/teambuilder/commons/core/index/IndexTest.java @@ -1,9 +1,9 @@ -package seedu.address.commons.core.index; +package teambuilder.commons.core.index; 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.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/address/commons/util/AppUtilTest.java b/src/test/java/teambuilder/commons/util/AppUtilTest.java similarity index 85% rename from src/test/java/seedu/address/commons/util/AppUtilTest.java rename to src/test/java/teambuilder/commons/util/AppUtilTest.java index 594de1e6365..9171da5bd67 100644 --- a/src/test/java/seedu/address/commons/util/AppUtilTest.java +++ b/src/test/java/teambuilder/commons/util/AppUtilTest.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -9,7 +9,7 @@ public class AppUtilTest { @Test public void getImage_exitingImage() { - assertNotNull(AppUtil.getImage("/images/address_book_32.png")); + assertNotNull(AppUtil.getImage("/images/team_builder_icon.png")); } @Test diff --git a/src/test/java/seedu/address/commons/util/CollectionUtilTest.java b/src/test/java/teambuilder/commons/util/CollectionUtilTest.java similarity index 96% rename from src/test/java/seedu/address/commons/util/CollectionUtilTest.java rename to src/test/java/teambuilder/commons/util/CollectionUtilTest.java index b467a3dc025..c0ff0d13749 100644 --- a/src/test/java/seedu/address/commons/util/CollectionUtilTest.java +++ b/src/test/java/teambuilder/commons/util/CollectionUtilTest.java @@ -1,9 +1,9 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.commons.util.CollectionUtil.requireAllNonNull; +import static teambuilder.testutil.Assert.assertThrows; import java.util.Arrays; import java.util.Collection; diff --git a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java b/src/test/java/teambuilder/commons/util/ConfigUtilTest.java similarity index 94% rename from src/test/java/seedu/address/commons/util/ConfigUtilTest.java rename to src/test/java/teambuilder/commons/util/ConfigUtilTest.java index d2ab2839a52..5d668424757 100644 --- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java +++ b/src/test/java/teambuilder/commons/util/ConfigUtilTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; 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 teambuilder.testutil.Assert.assertThrows; import java.io.IOException; import java.nio.file.Path; @@ -13,8 +13,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import seedu.address.commons.core.Config; -import seedu.address.commons.exceptions.DataConversionException; +import teambuilder.commons.core.Config; +import teambuilder.commons.exceptions.DataConversionException; public class ConfigUtilTest { diff --git a/src/test/java/seedu/address/commons/util/FileUtilTest.java b/src/test/java/teambuilder/commons/util/FileUtilTest.java similarity index 84% rename from src/test/java/seedu/address/commons/util/FileUtilTest.java rename to src/test/java/teambuilder/commons/util/FileUtilTest.java index 1fe5478c756..712746749e4 100644 --- a/src/test/java/seedu/address/commons/util/FileUtilTest.java +++ b/src/test/java/teambuilder/commons/util/FileUtilTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/teambuilder/commons/util/HistoryUtilTest.java b/src/test/java/teambuilder/commons/util/HistoryUtilTest.java new file mode 100644 index 00000000000..889d710238c --- /dev/null +++ b/src/test/java/teambuilder/commons/util/HistoryUtilTest.java @@ -0,0 +1,131 @@ +package teambuilder.commons.util; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import teambuilder.commons.core.Memento; + +public class HistoryUtilTest { + /** + * HistoryUtil has a single permanent instance. Hence, the order of tests can affect the result of tests. + */ + + @Test + public void compileTest() { + assertTrue(true); + assertFalse(false); + } + + @Test + public void singleInstanceTest() { + HistoryUtil one = HistoryUtil.getInstance(); + HistoryUtil two = HistoryUtil.getInstance(); + HistoryUtil three = HistoryUtil.getInstance(); + assertTrue(one == two && two == three && two != null); + } + + @Test + public void getLastUndoDescription_hasLastUndo_descriptReturned() { + HistoryUtil history = getFreshHistoryUtil(); + history.storePast(new FilledMomentoStub(), FilledMomentoStub.DESC); + Optional description = history.undo(); + assertTrue(description.get() == FilledMomentoStub.DESC); + } + + @Test + public void undo_infiniteEmptyUndo_alwaysFalse() { + HistoryUtil history = getFreshHistoryUtil(); + boolean isSuccessful = true; + for (int i = 0; i < 100; i++) { + isSuccessful = history.undo().isPresent(); + assertFalse(isSuccessful); + } + assertFalse(isSuccessful); + } + + @Test + public void undo_infiniteUndoThenStoreAndUndo_failureThenSuccess() { + HistoryUtil history = getFreshHistoryUtil(); + boolean isSuccessful = true; + for (int i = 0; i < 100; i++) { + isSuccessful = history.undo().isPresent(); + assertFalse(isSuccessful); + } + history.storePast(new FilledMomentoStub(), FilledMomentoStub.DESC); + isSuccessful = history.undo().isPresent(); + assertTrue(isSuccessful); + } + + @Test + public void undo_nonMultipleStoreThenUndoAll_alwaysSuccess() { + HistoryUtil history = getFreshHistoryUtil(); + for (int i = 0; i < 13; i++) { + history.storePast(new FilledMomentoStub(), FilledMomentoStub.DESC); + } + boolean isSuccessful = false; + for (int i = 0; i < 10; i++) { + isSuccessful = history.undo().isPresent(); + assertTrue(isSuccessful); + } + assertTrue(isSuccessful); + } + + @Test + public void undo_afterStoringMaxPlusOneMemo_success() { + HistoryUtil history = getFreshHistoryUtil(); + for (int i = 0; i < 11; i++) { + history.storePast(new FilledMomentoStub(), FilledMomentoStub.DESC); + } + boolean isSuccessful = history.undo().isPresent(); + assertTrue(isSuccessful); + } + + @Test + public void undo_twiceWithOneMemo_successThenFailure() { + HistoryUtil history = getFreshHistoryUtil(); + history.storePast(new FilledMomentoStub(), FilledMomentoStub.DESC); + + boolean isFirstSuccessful = history.undo().isPresent(); + assertTrue(isFirstSuccessful); + boolean isSecondSuccessful = history.undo().isPresent(); + assertFalse(isSecondSuccessful); + } + + @Test + public void store_infiniteStores_noExceptionThrown() { + HistoryUtil history = getFreshHistoryUtil(); + for (int i = 0; i < 100; i++) { + history.storePast(new FilledMomentoStub(), FilledMomentoStub.DESC); + } + } + + private HistoryUtil getFreshHistoryUtil() { + HistoryUtil history = HistoryUtil.getInstance(); + while (history.undo().isPresent()) { + } + ; + return history; + } + + /** + * Momento that returns true on restore and also already has a description. + */ + private class FilledMomentoStub implements Memento { + private static final String DESC = "THIS SHOULD APPEAR!"; + + @Override + public boolean restore() { + return true; + } + + @Override + public Memento getUpdatedMemento() { + return new FilledMomentoStub(); + } + + } +} diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/teambuilder/commons/util/JsonUtilTest.java similarity index 92% rename from src/test/java/seedu/address/commons/util/JsonUtilTest.java rename to src/test/java/teambuilder/commons/util/JsonUtilTest.java index d4907539dee..6997ce0b75e 100644 --- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java +++ b/src/test/java/teambuilder/commons/util/JsonUtilTest.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -7,8 +7,8 @@ import org.junit.jupiter.api.Test; -import seedu.address.testutil.SerializableTestClass; -import seedu.address.testutil.TestUtil; +import teambuilder.testutil.SerializableTestClass; +import teambuilder.testutil.TestUtil; /** * Tests JSON Read and Write diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/teambuilder/commons/util/StringUtilTest.java similarity index 98% rename from src/test/java/seedu/address/commons/util/StringUtilTest.java rename to src/test/java/teambuilder/commons/util/StringUtilTest.java index c56d407bf3f..0a4bf3929bf 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/teambuilder/commons/util/StringUtilTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package teambuilder.commons.util; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import java.io.FileNotFoundException; diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/teambuilder/logic/LogicManagerTest.java similarity index 76% rename from src/test/java/seedu/address/logic/LogicManagerTest.java rename to src/test/java/teambuilder/logic/LogicManagerTest.java index ad923ac249a..5c0f11640c4 100644 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ b/src/test/java/teambuilder/logic/LogicManagerTest.java @@ -1,14 +1,15 @@ -package seedu.address.logic; +package teambuilder.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.NAME_DESC_AMY; -import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY; -import static seedu.address.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalPersons.AMY; +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX; +import static teambuilder.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static teambuilder.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.MAJOR_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.NAME_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.PHONE_DESC_AMY; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.AMY; import java.io.IOException; import java.nio.file.Path; @@ -17,20 +18,20 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.ListCommand; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; -import seedu.address.model.person.Person; -import seedu.address.storage.JsonAddressBookStorage; -import seedu.address.storage.JsonUserPrefsStorage; -import seedu.address.storage.StorageManager; -import seedu.address.testutil.PersonBuilder; +import teambuilder.logic.commands.AddCommand; +import teambuilder.logic.commands.CommandResult; +import teambuilder.logic.commands.ListCommand; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.UserPrefs; +import teambuilder.model.person.Person; +import teambuilder.storage.JsonTeamBuilderStorage; +import teambuilder.storage.JsonUserPrefsStorage; +import teambuilder.storage.StorageManager; +import teambuilder.testutil.PersonBuilder; public class LogicManagerTest { private static final IOException DUMMY_IO_EXCEPTION = new IOException("dummy exception"); @@ -43,8 +44,8 @@ public class LogicManagerTest { @BeforeEach public void setUp() { - JsonAddressBookStorage addressBookStorage = - new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json")); + JsonTeamBuilderStorage addressBookStorage = + new JsonTeamBuilderStorage(temporaryFolder.resolve("addressBook.json")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json")); StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage); logic = new LogicManager(model, storage); @@ -71,7 +72,7 @@ public void execute_validCommand_success() throws Exception { @Test public void execute_storageThrowsIoException_throwsCommandException() { // Setup LogicManager with JsonAddressBookIoExceptionThrowingStub - JsonAddressBookStorage addressBookStorage = + JsonTeamBuilderStorage addressBookStorage = new JsonAddressBookIoExceptionThrowingStub(temporaryFolder.resolve("ioExceptionAddressBook.json")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("ioExceptionUserPrefs.json")); @@ -80,8 +81,8 @@ public void execute_storageThrowsIoException_throwsCommandException() { // 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(); + + ADDRESS_DESC_AMY + MAJOR_DESC_AMY; + Person expectedPerson = new PersonBuilder(AMY).withTags().withTeams().build(); ModelManager expectedModel = new ModelManager(); expectedModel.addPerson(expectedPerson); String expectedMessage = LogicManager.FILE_OPS_ERROR_MESSAGE + DUMMY_IO_EXCEPTION; @@ -129,7 +130,7 @@ private void assertCommandException(String inputCommand, String expectedMessage) */ private void assertCommandFailure(String inputCommand, Class expectedException, String expectedMessage) { - Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + Model expectedModel = new ModelManager(model.getTeamBuilder(), new UserPrefs()); assertCommandFailure(inputCommand, expectedException, expectedMessage, expectedModel); } @@ -149,13 +150,13 @@ private void assertCommandFailure(String inputCommand, Class new AddCommand(null)); @@ -50,6 +60,13 @@ public void execute_duplicatePerson_throwsCommandException() { assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PERSON, () -> addCommand.execute(modelStub)); } + @Test + public void execute_teamTagDoNotExist_throwsCommandException() { + Person validPerson = new PersonBuilder().withName("John Doe").withTeams("NUS").build(); + AddCommand addCommand = new AddCommand(validPerson); + assertThrows(CommandException.class, AddCommand.MESSAGE_TEAM_NOT_FOUND, () -> addCommand.execute(model)); + } + @Test public void equals() { Person alice = new PersonBuilder().withName("Alice").build(); @@ -78,6 +95,21 @@ public void equals() { * A default model stub that have all of the methods failing. */ private class ModelStub implements Model { + @Override + public Memento save() { + return new Memento() { + @Override + public boolean restore() { + return true; + } + + @Override + public Memento getUpdatedMemento() { + return this; + } + }; + } + @Override public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { throw new AssertionError("This method should not be called."); @@ -114,12 +146,17 @@ public void addPerson(Person person) { } @Override - public void setAddressBook(ReadOnlyAddressBook newData) { + public void addTeam(Team team) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setTeamBuilder(ReadOnlyTeamBuilder newData) { throw new AssertionError("This method should not be called."); } @Override - public ReadOnlyAddressBook getAddressBook() { + public ReadOnlyTeamBuilder getTeamBuilder() { throw new AssertionError("This method should not be called."); } @@ -128,6 +165,7 @@ public boolean hasPerson(Person person) { throw new AssertionError("This method should not be called."); } + @Override public void deletePerson(Person target) { throw new AssertionError("This method should not be called."); @@ -139,12 +177,60 @@ public void setPerson(Person target, Person editedPerson) { } @Override - public ObservableList getFilteredPersonList() { + public boolean hasTeam(Team team) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteTeam(Team target) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updatePersonInTeams(Person person) { + return; + } + + @Override + public void removeFromAllTeams(Person person) { + throw new AssertionError("This method should not be called."); + } + + public void setTeam(Team target, Team editedPerson) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getSortedPersonList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getTeamList() { + return new FilteredList<>(FXCollections.unmodifiableObservableList(FXCollections.observableArrayList())); + } + + public ObservableList getSortedTeamList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredPersonList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredTeamList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateSortPerson(Comparator comparator) { throw new AssertionError("This method should not be called."); } @Override - public void updateFilteredPersonList(Predicate predicate) { + public void updateSortTeam(Comparator comparator) { throw new AssertionError("This method should not be called."); } } @@ -186,8 +272,8 @@ public void addPerson(Person person) { } @Override - public ReadOnlyAddressBook getAddressBook() { - return new AddressBook(); + public ReadOnlyTeamBuilder getTeamBuilder() { + return new TeamBuilder(); } } diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/teambuilder/logic/commands/ClearCommandTest.java similarity index 62% rename from src/test/java/seedu/address/logic/commands/ClearCommandTest.java rename to src/test/java/teambuilder/logic/commands/ClearCommandTest.java index 80d9110c03a..1571522273b 100644 --- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/ClearCommandTest.java @@ -1,14 +1,14 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; import org.junit.jupiter.api.Test; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.UserPrefs; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.TeamBuilder; +import teambuilder.model.UserPrefs; public class ClearCommandTest { @@ -24,7 +24,7 @@ public void execute_emptyAddressBook_success() { public void execute_nonEmptyAddressBook_success() { Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - expectedModel.setAddressBook(new AddressBook()); + expectedModel.setTeamBuilder(new TeamBuilder()); assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel); } diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/teambuilder/logic/commands/CommandResultTest.java similarity index 98% rename from src/test/java/seedu/address/logic/commands/CommandResultTest.java rename to src/test/java/teambuilder/logic/commands/CommandResultTest.java index 4f3eb46e9ef..20e9f408a09 100644 --- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java +++ b/src/test/java/teambuilder/logic/commands/CommandResultTest.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/teambuilder/logic/commands/CommandTestUtil.java similarity index 64% rename from src/test/java/seedu/address/logic/commands/CommandTestUtil.java rename to src/test/java/teambuilder/logic/commands/CommandTestUtil.java index 643a1d08069..f5c8ea96bb3 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/teambuilder/logic/commands/CommandTestUtil.java @@ -1,25 +1,28 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; 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_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_EMAIL; +import static teambuilder.logic.parser.CliSyntax.PREFIX_MAJOR; +import static teambuilder.logic.parser.CliSyntax.PREFIX_NAME; +import static teambuilder.logic.parser.CliSyntax.PREFIX_PHONE; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAMDESC; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAMNAME; +import static teambuilder.testutil.Assert.assertThrows; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import seedu.address.commons.core.index.Index; -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 teambuilder.commons.core.index.Index; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.TeamBuilder; +import teambuilder.model.person.Person; +import teambuilder.model.person.PersonContainsKeywordsPredicate; +import teambuilder.testutil.EditPersonDescriptorBuilder; /** * Contains helper methods for testing commands. @@ -33,9 +36,17 @@ public class CommandTestUtil { 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_MAJOR_AMY = "Computer Science"; public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3"; + public static final String VALID_MAJOR_BOB = "Business"; public static final String VALID_TAG_HUSBAND = "husband"; public static final String VALID_TAG_FRIEND = "friend"; + public static final String VALID_TAG_TEAM = "project"; + public static final String VALID_SKILLTAG_TEAM = "Python"; + public static final String VALID_TEAMNAME_A = "Team A"; + public static final String VALID_TEAMDESC_A = "This is a valid description."; + public static final String VALID_ORDER = "asc"; + public static final String VALID_SORT_BY = "tcount"; public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY; public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB; @@ -45,8 +56,13 @@ public class CommandTestUtil { 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 MAJOR_DESC_AMY = " " + PREFIX_MAJOR + VALID_MAJOR_AMY; + public static final String MAJOR_DESC_BOB = " " + PREFIX_MAJOR + VALID_MAJOR_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 TEAMNAME_DESC_A = " " + PREFIX_TEAMNAME + VALID_TEAMNAME_A; + public static final String TEAMDESC_DESC_A = " " + PREFIX_TEAMDESC + VALID_TEAMDESC_A; + public static final String TAG_DESC_A = " " + PREFIX_TAG + VALID_SKILLTAG_TEAM; 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 @@ -63,10 +79,11 @@ public class CommandTestUtil { 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(); + .withMajor(VALID_MAJOR_AMY).withTags(VALID_TAG_FRIEND).withTeams(VALID_TAG_TEAM).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(); + .withMajor(VALID_MAJOR_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND) + .withTeams(VALID_TAG_TEAM).build(); } /** @@ -99,30 +116,30 @@ 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 TeamBuilder, filtered person list and selected person 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()); + TeamBuilder expectedAddressBook = new TeamBuilder(actualModel.getTeamBuilder()); + List expectedFilteredList = new ArrayList<>(actualModel.getSortedPersonList()); assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel)); - assertEquals(expectedAddressBook, actualModel.getAddressBook()); - assertEquals(expectedFilteredList, actualModel.getFilteredPersonList()); + assertEquals(expectedAddressBook, actualModel.getTeamBuilder()); + assertEquals(expectedFilteredList, actualModel.getSortedPersonList()); } /** * Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the - * {@code model}'s address book. + * {@code model}'s TeamBuilder. */ public static void showPersonAtIndex(Model model, Index targetIndex) { - assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size()); + assertTrue(targetIndex.getZeroBased() < model.getSortedPersonList().size()); - Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased()); + Person person = model.getSortedPersonList().get(targetIndex.getZeroBased()); final String[] splitName = person.getName().fullName.split("\\s+"); - model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0]))); + model.updateFilteredPersonList(new PersonContainsKeywordsPredicate(Arrays.asList(splitName[0]))); - assertEquals(1, model.getFilteredPersonList().size()); + assertEquals(1, model.getSortedPersonList().size()); } } diff --git a/src/test/java/teambuilder/logic/commands/CreateCommandTest.java b/src/test/java/teambuilder/logic/commands/CreateCommandTest.java new file mode 100644 index 00000000000..898ed19b856 --- /dev/null +++ b/src/test/java/teambuilder/logic/commands/CreateCommandTest.java @@ -0,0 +1,82 @@ +package teambuilder.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 teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.Arrays; +import java.util.HashSet; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +public class CreateCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void execute_allArgumentsSpecifiedSuccessfullyNoTag_success() throws CommandException { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), new HashSet<>()); + CommandResult commandResult = new CreateCommand(team).execute(model); + assertEquals(String.format(CreateCommand.MESSAGE_SUCCESS, validTeamName), commandResult.getFeedbackToUser()); + } + + @Test + public void execute_allArgumentsSpecifiedSuccessfullyTagPresent_success() throws CommandException { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + CommandResult commandResult = new CreateCommand(team).execute(model); + assertEquals(String.format(CreateCommand.MESSAGE_SUCCESS, validTeamName), commandResult.getFeedbackToUser()); + } + + @Test + public void execute_throw() throws CommandException { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + new CreateCommand(team).execute(model); + CreateCommand command = new CreateCommand(team); + assertThrows(CommandException.class, CreateCommand.MESSAGE_DUPLICATE_TEAM, () -> command.execute(model)); + } + + @Test + public void equals() { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + final CreateCommand standardCommand = new CreateCommand(team); + + // same values -> returns true + CreateCommand sameCommand = new CreateCommand(team); + assertTrue(standardCommand.equals(sameCommand)); + + // 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 order -> returns false + TeamName anotherValidTeamName = new TeamName("Team B"); + Team anotherTeam = new Team(anotherValidTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + CreateCommand diffCommand = new CreateCommand(anotherTeam); + assertFalse(standardCommand.equals(diffCommand)); + + } +} diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/teambuilder/logic/commands/DeleteCommandTest.java similarity index 66% rename from src/test/java/seedu/address/logic/commands/DeleteCommandTest.java rename to src/test/java/teambuilder/logic/commands/DeleteCommandTest.java index 45a8c910ba1..e5bab707b62 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/DeleteCommandTest.java @@ -1,22 +1,22 @@ -package seedu.address.logic.commands; +package teambuilder.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.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 teambuilder.logic.commands.CommandTestUtil.assertCommandFailure; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.logic.commands.CommandTestUtil.showPersonAtIndex; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static teambuilder.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static teambuilder.testutil.TypicalPersons.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 teambuilder.commons.core.Messages; +import teambuilder.commons.core.index.Index; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; +import teambuilder.model.person.Person; /** * Contains integration tests (interaction with the Model) and unit tests for @@ -28,12 +28,12 @@ public class DeleteCommandTest { @Test public void execute_validIndexUnfilteredList_success() { - Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person personToDelete = model.getSortedPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON); String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete); - ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + ModelManager expectedModel = new ModelManager(model.getTeamBuilder(), new UserPrefs()); expectedModel.deletePerson(personToDelete); assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); @@ -41,7 +41,7 @@ public void execute_validIndexUnfilteredList_success() { @Test public void execute_invalidIndexUnfilteredList_throwsCommandException() { - Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); + Index outOfBoundIndex = Index.fromOneBased(model.getSortedPersonList().size() + 1); DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex); assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); @@ -51,12 +51,12 @@ public void execute_invalidIndexUnfilteredList_throwsCommandException() { public void execute_validIndexFilteredList_success() { showPersonAtIndex(model, INDEX_FIRST_PERSON); - Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person personToDelete = model.getSortedPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON); String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete); - Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + Model expectedModel = new ModelManager(model.getTeamBuilder(), new UserPrefs()); expectedModel.deletePerson(personToDelete); showNoPerson(expectedModel); @@ -68,8 +68,8 @@ public void execute_invalidIndexFilteredList_throwsCommandException() { showPersonAtIndex(model, INDEX_FIRST_PERSON); Index outOfBoundIndex = INDEX_SECOND_PERSON; - // ensures that outOfBoundIndex is still in bounds of address book list - assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size()); + // ensures that outOfBoundIndex is still in bounds of TeamBuilder list + assertTrue(outOfBoundIndex.getZeroBased() < model.getTeamBuilder().getPersonList().size()); DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex); @@ -104,6 +104,6 @@ public void equals() { private void showNoPerson(Model model) { model.updateFilteredPersonList(p -> false); - assertTrue(model.getFilteredPersonList().isEmpty()); + assertTrue(model.getSortedPersonList().isEmpty()); } } diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/teambuilder/logic/commands/EditCommandTest.java similarity index 64% rename from src/test/java/seedu/address/logic/commands/EditCommandTest.java rename to src/test/java/teambuilder/logic/commands/EditCommandTest.java index 214c6c2507b..d533b5c5513 100644 --- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/EditCommandTest.java @@ -1,31 +1,31 @@ -package seedu.address.logic.commands; +package teambuilder.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.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.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 teambuilder.logic.commands.CommandTestUtil.DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandFailure; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.logic.commands.CommandTestUtil.showPersonAtIndex; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static teambuilder.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; 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.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 teambuilder.commons.core.Messages; +import teambuilder.commons.core.index.Index; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.TeamBuilder; +import teambuilder.model.UserPrefs; +import teambuilder.model.person.Person; +import teambuilder.testutil.EditPersonDescriptorBuilder; +import teambuilder.testutil.PersonBuilder; /** * Contains integration tests (interaction with the Model) and unit tests for EditCommand. @@ -42,16 +42,16 @@ public void execute_allFieldsSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson); - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); - expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson); + Model expectedModel = new ModelManager(new TeamBuilder(model.getTeamBuilder()), new UserPrefs()); + expectedModel.setPerson(model.getSortedPersonList().get(0), editedPerson); 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 indexLastPerson = Index.fromOneBased(model.getSortedPersonList().size()); + Person lastPerson = model.getSortedPersonList().get(indexLastPerson.getZeroBased()); PersonBuilder personInList = new PersonBuilder(lastPerson); Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB) @@ -63,7 +63,7 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson); - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); + Model expectedModel = new ModelManager(new TeamBuilder(model.getTeamBuilder()), new UserPrefs()); expectedModel.setPerson(lastPerson, editedPerson); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); @@ -72,11 +72,11 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() { @Test public void execute_noFieldSpecifiedUnfilteredList_success() { EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor()); - Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person editedPerson = model.getSortedPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson); - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); + Model expectedModel = new ModelManager(new TeamBuilder(model.getTeamBuilder()), new UserPrefs()); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); } @@ -85,22 +85,22 @@ public void execute_noFieldSpecifiedUnfilteredList_success() { public void execute_filteredList_success() { showPersonAtIndex(model, INDEX_FIRST_PERSON); - Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person personInFilteredList = model.getSortedPersonList().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_PERSON_SUCCESS, editedPerson); - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); - expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson); + Model expectedModel = new ModelManager(new TeamBuilder(model.getTeamBuilder()), new UserPrefs()); + expectedModel.setPerson(model.getSortedPersonList().get(0), editedPerson); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); } @Test public void execute_duplicatePersonUnfilteredList_failure() { - Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person firstPerson = model.getSortedPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build(); EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor); @@ -111,8 +111,8 @@ public void execute_duplicatePersonUnfilteredList_failure() { public void execute_duplicatePersonFilteredList_failure() { showPersonAtIndex(model, INDEX_FIRST_PERSON); - // edit person in filtered list into a duplicate in address book - Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased()); + // edit person in filtered list into a duplicate in TeamBuilder + Person personInList = model.getTeamBuilder().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased()); EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptorBuilder(personInList).build()); @@ -121,7 +121,7 @@ public void execute_duplicatePersonFilteredList_failure() { @Test public void execute_invalidPersonIndexUnfilteredList_failure() { - Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); + Index outOfBoundIndex = Index.fromOneBased(model.getSortedPersonList().size() + 1); EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build(); EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor); @@ -130,14 +130,14 @@ public void execute_invalidPersonIndexUnfilteredList_failure() { /** * Edit filtered list where index is larger than size of filtered list, - * but smaller than size of address book + * but smaller than size of TeamBuilder */ @Test public void execute_invalidPersonIndexFilteredList_failure() { showPersonAtIndex(model, INDEX_FIRST_PERSON); Index outOfBoundIndex = INDEX_SECOND_PERSON; - // ensures that outOfBoundIndex is still in bounds of address book list - assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size()); + // ensures that outOfBoundIndex is still in bounds of TeamBuilder list + assertTrue(outOfBoundIndex.getZeroBased() < model.getTeamBuilder().getPersonList().size()); EditCommand editCommand = new EditCommand(outOfBoundIndex, new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build()); diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/teambuilder/logic/commands/EditPersonDescriptorTest.java similarity index 71% rename from src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java rename to src/test/java/teambuilder/logic/commands/EditPersonDescriptorTest.java index e0288792e72..9ed99352c72 100644 --- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java +++ b/src/test/java/teambuilder/logic/commands/EditPersonDescriptorTest.java @@ -1,19 +1,19 @@ -package seedu.address.logic.commands; +package teambuilder.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.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_NAME_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.logic.commands.CommandTestUtil.DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; import org.junit.jupiter.api.Test; -import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.testutil.EditPersonDescriptorBuilder; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.testutil.EditPersonDescriptorBuilder; public class EditPersonDescriptorTest { diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/teambuilder/logic/commands/ExitCommandTest.java similarity index 60% rename from src/test/java/seedu/address/logic/commands/ExitCommandTest.java rename to src/test/java/teambuilder/logic/commands/ExitCommandTest.java index 9533c473875..17a026683d7 100644 --- a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/ExitCommandTest.java @@ -1,12 +1,12 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT; import org.junit.jupiter.api.Test; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; public class ExitCommandTest { private Model model = new ModelManager(); diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/teambuilder/logic/commands/FindCommandTest.java similarity index 62% rename from src/test/java/seedu/address/logic/commands/FindCommandTest.java rename to src/test/java/teambuilder/logic/commands/FindCommandTest.java index 9b15db28bbb..58c4a8d5d9e 100644 --- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/FindCommandTest.java @@ -1,24 +1,24 @@ -package seedu.address.logic.commands; +package teambuilder.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_PERSONS_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 teambuilder.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.testutil.TypicalPersons.CARL; +import static teambuilder.testutil.TypicalPersons.ELLE; +import static teambuilder.testutil.TypicalPersons.FIONA; +import static teambuilder.testutil.TypicalPersons.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.person.NameContainsKeywordsPredicate; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; +import teambuilder.model.person.PersonContainsKeywordsPredicate; /** * Contains integration tests (interaction with the Model) for {@code FindCommand}. @@ -29,10 +29,10 @@ public class FindCommandTest { @Test public void equals() { - NameContainsKeywordsPredicate firstPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("first")); - NameContainsKeywordsPredicate secondPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("second")); + PersonContainsKeywordsPredicate firstPredicate = + new PersonContainsKeywordsPredicate(Collections.singletonList("first")); + PersonContainsKeywordsPredicate secondPredicate = + new PersonContainsKeywordsPredicate(Collections.singletonList("second")); FindCommand findFirstCommand = new FindCommand(firstPredicate); FindCommand findSecondCommand = new FindCommand(secondPredicate); @@ -57,27 +57,27 @@ public void equals() { @Test public void execute_zeroKeywords_noPersonFound() { String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); - NameContainsKeywordsPredicate predicate = preparePredicate(" "); + PersonContainsKeywordsPredicate predicate = preparePredicate(" "); FindCommand command = new FindCommand(predicate); expectedModel.updateFilteredPersonList(predicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); - assertEquals(Collections.emptyList(), model.getFilteredPersonList()); + assertEquals(Collections.emptyList(), model.getSortedPersonList()); } @Test public void execute_multipleKeywords_multiplePersonsFound() { String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); - NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz"); + PersonContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz"); FindCommand command = new FindCommand(predicate); expectedModel.updateFilteredPersonList(predicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); - assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList()); + assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getSortedPersonList()); } /** * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}. */ - private NameContainsKeywordsPredicate preparePredicate(String userInput) { - return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + private PersonContainsKeywordsPredicate preparePredicate(String userInput) { + return new PersonContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); } } diff --git a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java b/src/test/java/teambuilder/logic/commands/HelpCommandTest.java similarity index 61% rename from src/test/java/seedu/address/logic/commands/HelpCommandTest.java rename to src/test/java/teambuilder/logic/commands/HelpCommandTest.java index 4904fc4352e..186e5f18290 100644 --- a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/HelpCommandTest.java @@ -1,12 +1,12 @@ -package seedu.address.logic.commands; +package teambuilder.logic.commands; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE; import org.junit.jupiter.api.Test; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; public class HelpCommandTest { private Model model = new ModelManager(); diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/teambuilder/logic/commands/ListCommandTest.java similarity index 61% rename from src/test/java/seedu/address/logic/commands/ListCommandTest.java rename to src/test/java/teambuilder/logic/commands/ListCommandTest.java index 435ff1f7275..87a12cd194c 100644 --- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java +++ b/src/test/java/teambuilder/logic/commands/ListCommandTest.java @@ -1,16 +1,16 @@ -package seedu.address.logic.commands; +package teambuilder.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 teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.logic.commands.CommandTestUtil.showPersonAtIndex; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.UserPrefs; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; /** * Contains integration tests (interaction with the Model) and unit tests for ListCommand. @@ -23,7 +23,7 @@ public class ListCommandTest { @BeforeEach public void setUp() { model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + expectedModel = new ModelManager(model.getTeamBuilder(), new UserPrefs()); } @Test diff --git a/src/test/java/teambuilder/logic/commands/RedoCommandIntegrationTest.java b/src/test/java/teambuilder/logic/commands/RedoCommandIntegrationTest.java new file mode 100644 index 00000000000..d82cc39948f --- /dev/null +++ b/src/test/java/teambuilder/logic/commands/RedoCommandIntegrationTest.java @@ -0,0 +1,256 @@ +package teambuilder.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 java.nio.file.Path; +import java.util.Comparator; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; + +import javafx.collections.ObservableList; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.core.Memento; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; + +public class RedoCommandIntegrationTest { + @Test + public void constructor_noNull() { + RedoCommand undoer = new RedoCommand(); + assertTrue(undoer != null); + } + + @Test + public void execute_redoUnsuccessful_failureMessage() throws CommandException { + Model stub = new ModelStub(); + HistoryUtil history = HistoryUtil.getInstance(); + while (history.redo().isPresent()) + ; + CommandResult commandResult = new RedoCommand().execute(stub); + assertEquals(RedoCommand.MESSAGE_FAILURE, commandResult.getFeedbackToUser()); + } + + @Test + public void execute_restoreUnsuccessful_failureMessage() throws CommandException { + Model stub = new EmptyModelStub(); + HistoryUtil history = HistoryUtil.getInstance(); + history.storePast(stub.save(), EmptyMomentoStub.DESC); + history.undo(); + + CommandResult commandResult = new RedoCommand().execute(stub); + assertEquals(RedoCommand.MESSAGE_FAILURE, commandResult.getFeedbackToUser()); + } + + @Test + public void execute_restoreSuccessFul_successMessage() throws CommandException { + Model stub = new ModelStub(); + HistoryUtil history = HistoryUtil.getInstance(); + history.storePast(new FilledMomento(), FilledMomento.DESC); + history.undo(); + + CommandResult commandResult = new RedoCommand().execute(stub); + assertEquals(RedoCommand.MESSAGE_SUCCESS + FilledMomento.DESC, commandResult.getFeedbackToUser()); + } + + @Test + public void equals() { + RedoCommand one = new RedoCommand(); + RedoCommand ptrOne = one; + RedoCommand two = new RedoCommand(); + Object obj = new Object(); + String str = "Hello!"; + + assertTrue(one.equals(ptrOne)); + assertTrue(ptrOne.equals(one)); + + assertFalse(two.equals(one)); + assertFalse(one.equals(two)); + + assertFalse(one.equals(str)); + assertFalse(one.equals(obj)); + + } + + private class FilledMomento implements Memento { + private static final String DESC = "Everything"; + + @Override + public boolean restore() { + return true; + } + + @Override + public Memento getUpdatedMemento() { + return new FilledMomento(); + } + } + + private class ModelStub implements Model { + + @Override + public Memento save() { + return new FilledMomento(); + } + + @Override + public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { + throw new UnsupportedOperationException("Unimplemented method 'setUserPrefs'"); + } + + @Override + public ReadOnlyUserPrefs getUserPrefs() { + throw new UnsupportedOperationException("Unimplemented method 'getUserPrefs'"); + } + + @Override + public GuiSettings getGuiSettings() { + throw new UnsupportedOperationException("Unimplemented method 'getGuiSettings'"); + } + + @Override + public void setGuiSettings(GuiSettings guiSettings) { + throw new UnsupportedOperationException("Unimplemented method 'setGuiSettings'"); + } + + @Override + public Path getAddressBookFilePath() { + + throw new UnsupportedOperationException("Unimplemented method 'getAddressBookFilePath'"); + } + + @Override + public void setAddressBookFilePath(Path addressBookFilePath) { + throw new UnsupportedOperationException("Unimplemented method 'setAddressBookFilePath'"); + } + + @Override + public void setTeamBuilder(ReadOnlyTeamBuilder teamBuilder) { + throw new UnsupportedOperationException("Unimplemented method 'setAddressBook'"); + } + + @Override + public ReadOnlyTeamBuilder getTeamBuilder() { + throw new UnsupportedOperationException("Unimplemented method 'getAddressBook'"); + } + + @Override + public boolean hasPerson(Person person) { + + throw new UnsupportedOperationException("Unimplemented method 'hasPerson'"); + } + + @Override + public void deletePerson(Person target) { + + throw new UnsupportedOperationException("Unimplemented method 'deletePerson'"); + } + + @Override + public void addPerson(Person person) { + + throw new UnsupportedOperationException("Unimplemented method 'addPerson'"); + } + + @Override + public void setPerson(Person target, Person editedPerson) { + + throw new UnsupportedOperationException("Unimplemented method 'setPerson'"); + } + + @Override + public boolean hasTeam(Team team) { + throw new UnsupportedOperationException("Unimplemented method 'hasTeam'"); + } + + @Override + public void deleteTeam(Team target) { + throw new UnsupportedOperationException("Unimplemented method 'deleteTeam'"); + } + + @Override + public void addTeam(Team team) { + throw new UnsupportedOperationException("Unimplemented method 'addTeam'"); + } + + @Override + public void updatePersonInTeams(Person person) { + throw new UnsupportedOperationException("Unimplemented method 'updatePersonInTeams'"); + } + + @Override + public void removeFromAllTeams(Person person) { + throw new UnsupportedOperationException("Unimplemented method 'removeFromAllTeams'"); + } + + @Override + public ObservableList getSortedPersonList() { + throw new UnsupportedOperationException("Unimplemented method 'getSortedPersonList'"); + } + + @Override + public void setTeam(Team team, Team editedTeam) { + throw new UnsupportedOperationException("Unimplemented method 'setTeam'"); + } + + @Override + public ObservableList getSortedTeamList() { + throw new UnsupportedOperationException("Unimplemented method 'getSortedTeamList'"); + } + + @Override + public void updateFilteredPersonList(Predicate predicate) { + throw new UnsupportedOperationException("Unimplemented method 'updateFilteredPersonList'"); + } + + @Override + public void updateFilteredTeamList(Predicate predicate) { + throw new UnsupportedOperationException("Unimplemented method 'updateFilteredTeamList'"); + } + + @Override + public void updateSortPerson(Comparator comparator) { + throw new UnsupportedOperationException("Unimplemented method 'updateSortPerson'"); + } + + @Override + public void updateSortTeam(Comparator comparator) { + throw new UnsupportedOperationException("Unimplemented method 'updateSortTeam'"); + } + + @Override + public ObservableList getTeamList() { + throw new AssertionError("This method should not be called."); + } + + } + + private class EmptyMomentoStub implements Memento { + private static final String DESC = "This should not matter"; + + @Override + public boolean restore() { + return false; + } + + @Override + public Memento getUpdatedMemento() { + return new EmptyMomentoStub(); + } + } + + private class EmptyModelStub extends ModelStub { + + @Override + public Memento save() { + return new EmptyMomentoStub(); + } + } +} diff --git a/src/test/java/teambuilder/logic/commands/RemoveCommandTest.java b/src/test/java/teambuilder/logic/commands/RemoveCommandTest.java new file mode 100644 index 00000000000..f04d32c556c --- /dev/null +++ b/src/test/java/teambuilder/logic/commands/RemoveCommandTest.java @@ -0,0 +1,75 @@ +package teambuilder.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 teambuilder.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.Arrays; +import java.util.HashSet; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +class RemoveCommandTest { + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void execute_allArgumentsSpecifiedSuccessfullyNoTag_success() throws CommandException { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), new HashSet<>()); + new CreateCommand(team).execute(model); + CommandResult commandResult = new RemoveCommand(team.getName()).execute(model); + assertEquals(String.format(RemoveCommand.MESSAGE_DELETE_TEAM_SUCCESS, validTeamName), + commandResult.getFeedbackToUser()); + } + + @Test + public void execute_allArgumentsSpecifiedSuccessfullyTagPresent_success() throws CommandException { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + new CreateCommand(team).execute(model); + CommandResult commandResult = new RemoveCommand(team.getName()).execute(model); + assertEquals(String.format(RemoveCommand.MESSAGE_DELETE_TEAM_SUCCESS, validTeamName), + commandResult.getFeedbackToUser()); + } + + @Test + public void equals() { + TeamName validTeamName = new TeamName("Team A"); + Team team = new Team(validTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + final RemoveCommand standardCommand = new RemoveCommand(team.getName()); + + // same values -> returns true + RemoveCommand sameCommand = new RemoveCommand(team.getName()); + assertTrue(standardCommand.equals(sameCommand)); + + // 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 order -> returns false + TeamName anotherValidTeamName = new TeamName("Team B"); + Team anotherTeam = new Team(anotherValidTeamName, new Desc("This is a description."), + new HashSet<>(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + RemoveCommand diffCommand = new RemoveCommand(anotherTeam.getName()); + assertFalse(standardCommand.equals(diffCommand)); + + } + +} diff --git a/src/test/java/teambuilder/logic/commands/ShowCommandTest.java b/src/test/java/teambuilder/logic/commands/ShowCommandTest.java new file mode 100644 index 00000000000..d12233d4163 --- /dev/null +++ b/src/test/java/teambuilder/logic/commands/ShowCommandTest.java @@ -0,0 +1,86 @@ +package teambuilder.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 teambuilder.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static teambuilder.logic.commands.CommandTestUtil.assertCommandSuccess; +import static teambuilder.testutil.TypicalPersons.BENSON; +import static teambuilder.testutil.TypicalPersons.CARL; +import static teambuilder.testutil.TypicalPersons.DANIEL; +import static teambuilder.testutil.TypicalPersons.ELLE; +import static teambuilder.testutil.TypicalPersons.FIONA; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.Arrays; +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; +import teambuilder.model.person.TeamContainsKeywordsPredicate; + +/** + * Contains integration tests (interaction with the Model) for {@code ShowCommand}. + */ +class ShowCommandTest { + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void equals() { + TeamContainsKeywordsPredicate firstPredicate = + new TeamContainsKeywordsPredicate(Collections.singletonList("first")); + TeamContainsKeywordsPredicate secondPredicate = + new TeamContainsKeywordsPredicate(Collections.singletonList("second")); + + ShowCommand showFirstCommand = new ShowCommand(firstPredicate); + ShowCommand showSecondCommand = new ShowCommand(secondPredicate); + + // same object -> returns true + assertTrue(showFirstCommand.equals(showFirstCommand)); + + // same values -> returns true + ShowCommand showFirstCommandCopy = new ShowCommand(firstPredicate); + assertTrue(showFirstCommand.equals(showFirstCommandCopy)); + + // different types -> returns false + assertFalse(showFirstCommand.equals(1)); + + // null -> returns false + assertFalse(showFirstCommand.equals(null)); + + // different person -> returns false + assertFalse(showFirstCommand.equals(showSecondCommand)); + } + + @Test + public void execute_zeroKeywords_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + TeamContainsKeywordsPredicate predicate = preparePredicate(" "); + ShowCommand command = new ShowCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getSortedPersonList()); + } + + @Test + public void execute_multipleKeywords_multiplePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 5); + TeamContainsKeywordsPredicate predicate = preparePredicate("TeamA TeamB TeamC"); + ShowCommand command = new ShowCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(BENSON, CARL, DANIEL, ELLE, FIONA), model.getSortedPersonList()); + } + + /** + * Parses {@code userInput} into a {@code TeamContainsKeywordsPredicate}. + */ + private TeamContainsKeywordsPredicate preparePredicate(String userInput) { + return new TeamContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + } + +} diff --git a/src/test/java/teambuilder/logic/commands/SortCommandTest.java b/src/test/java/teambuilder/logic/commands/SortCommandTest.java new file mode 100644 index 00000000000..befc02c547a --- /dev/null +++ b/src/test/java/teambuilder/logic/commands/SortCommandTest.java @@ -0,0 +1,77 @@ +package teambuilder.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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; + +import org.junit.jupiter.api.Test; + +import teambuilder.commons.core.Messages; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.ModelManager; +import teambuilder.model.UserPrefs; + +public class SortCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void execute_unknownOrderSpecified_failure() { + CommandException thrown = assertThrows(CommandException.class, () -> + new SortCommand("unknown", "tcount").execute(model)); + assertTrue(thrown.getMessage().contentEquals(Messages.MESSAGE_INVALID_SORTING_ORDER)); + } + + @Test + public void execute_emptyOrderSpecified_failure() { + CommandException thrown = assertThrows(CommandException.class, () -> + new SortCommand("", "tcount").execute(model)); + assertTrue(thrown.getMessage().contentEquals(Messages.MESSAGE_INVALID_SORTING_ORDER)); + } + + @Test + public void execute_unknownSortBySpecified_failure() { + CommandException thrown = assertThrows(CommandException.class, () -> + new SortCommand("desc", "unknown").execute(model)); + assertTrue(thrown.getMessage().contentEquals(Messages.MESSAGE_INVALID_SORT_BY)); + } + + @Test + public void execute_emptySortBySpecified_failure() { + CommandException thrown = assertThrows(CommandException.class, () -> + new SortCommand("desc", "").execute(model)); + assertTrue(thrown.getMessage().contentEquals(Messages.MESSAGE_INVALID_SORT_BY)); + } + + @Test + public void execute_allArgumentsSpecifiedSuccessfully_success() throws CommandException { + CommandResult commandResult = new SortCommand("desc", "tcount").execute(model); + assertEquals(SortCommand.MESSAGE_SUCCESS, commandResult.getFeedbackToUser()); + } + + @Test + public void equals() { + final SortCommand standardCommand = new SortCommand("desc", "tcount"); + + // same values -> returns true + SortCommand sameCommand = new SortCommand("desc", "tcount"); + assertTrue(standardCommand.equals(sameCommand)); + + // 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 order -> returns false + assertFalse(standardCommand.equals(new SortCommand("asc", "tcount"))); + + } + +} diff --git a/src/test/java/teambuilder/logic/commands/UndoCommandIntegrationTest.java b/src/test/java/teambuilder/logic/commands/UndoCommandIntegrationTest.java new file mode 100644 index 00000000000..1357d1ca5f2 --- /dev/null +++ b/src/test/java/teambuilder/logic/commands/UndoCommandIntegrationTest.java @@ -0,0 +1,263 @@ +package teambuilder.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 java.nio.file.Path; +import java.util.Comparator; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; + +import javafx.collections.ObservableList; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.core.Memento; +import teambuilder.commons.util.HistoryUtil; +import teambuilder.logic.commands.exceptions.CommandException; +import teambuilder.model.Model; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.ReadOnlyUserPrefs; +import teambuilder.model.person.Person; +import teambuilder.model.team.Team; + +public class UndoCommandIntegrationTest { + @Test + public void constructor_noNull() { + UndoCommand undoer = new UndoCommand(); + assertTrue(undoer != null); + } + + @Test + public void execute_undoSuccessFul_successMessage() throws CommandException { + Model stub = new ModelStub(); + HistoryUtil history = HistoryUtil.getInstance(); + history.storePast(new FilledMomento(), FilledMomento.DESC); + CommandResult commandResult = new UndoCommand().execute(stub); + assertEquals(UndoCommand.MESSAGE_SUCCESS + FilledMomento.DESC, commandResult.getFeedbackToUser()); + } + + @Test + public void execute_undoUnsuccessful_failureMessage() throws CommandException { + Model stub = new ModelStub(); + HistoryUtil history = HistoryUtil.getInstance(); + for (int i = 0; i < 11; i++) { + history.undo(); + }; + CommandResult commandResult = new UndoCommand().execute(stub); + assertEquals(UndoCommand.MESSAGE_FAILURE, commandResult.getFeedbackToUser()); + } + + @Test + public void execute_restoreUnsuccessful_failureMessage() throws CommandException { + Model stub = new EmptyModelStub(); + HistoryUtil history = HistoryUtil.getInstance(); + history.storePast(stub.save(), EmptyMomentoStub.DESC); + + CommandResult commandResult = new UndoCommand().execute(stub); + assertEquals(UndoCommand.MESSAGE_FAILURE, commandResult.getFeedbackToUser()); + } + + @Test + public void equals() { + UndoCommand one = new UndoCommand(); + UndoCommand ptrOne = one; + UndoCommand two = new UndoCommand(); + Object obj = new Object(); + String str = "Hello!"; + + assertTrue(one.equals(ptrOne)); + assertTrue(ptrOne.equals(one)); + + assertFalse(two.equals(one)); + assertFalse(one.equals(two)); + + assertFalse(one.equals(str)); + assertFalse(one.equals(obj)); + + } + + private class FilledMomento implements Memento { + private static final String DESC = "Everything"; + + @Override + public boolean restore() { + return true; + } + + @Override + public Memento getUpdatedMemento() { + return new FilledMomento(); + } + } + + private class ModelStub implements Model { + + @Override + public Memento save() { + return new Memento() { + @Override + public boolean restore() { + return true; + } + + @Override + public Memento getUpdatedMemento() { + return this; + } + }; + } + + @Override + public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { + throw new UnsupportedOperationException("Unimplemented method 'setUserPrefs'"); + } + + @Override + public ReadOnlyUserPrefs getUserPrefs() { + throw new UnsupportedOperationException("Unimplemented method 'getUserPrefs'"); + } + + @Override + public GuiSettings getGuiSettings() { + throw new UnsupportedOperationException("Unimplemented method 'getGuiSettings'"); + } + + @Override + public void setGuiSettings(GuiSettings guiSettings) { + throw new UnsupportedOperationException("Unimplemented method 'setGuiSettings'"); + } + + @Override + public Path getAddressBookFilePath() { + + throw new UnsupportedOperationException("Unimplemented method 'getAddressBookFilePath'"); + } + + @Override + public void setAddressBookFilePath(Path addressBookFilePath) { + throw new UnsupportedOperationException("Unimplemented method 'setAddressBookFilePath'"); + } + + @Override + public void setTeamBuilder(ReadOnlyTeamBuilder teamBuilder) { + throw new UnsupportedOperationException("Unimplemented method 'setAddressBook'"); + } + + @Override + public ReadOnlyTeamBuilder getTeamBuilder() { + throw new UnsupportedOperationException("Unimplemented method 'getAddressBook'"); + } + + @Override + public boolean hasPerson(Person person) { + + throw new UnsupportedOperationException("Unimplemented method 'hasPerson'"); + } + + @Override + public void deletePerson(Person target) { + + throw new UnsupportedOperationException("Unimplemented method 'deletePerson'"); + } + + @Override + public void addPerson(Person person) { + + throw new UnsupportedOperationException("Unimplemented method 'addPerson'"); + } + + @Override + public void setPerson(Person target, Person editedPerson) { + + throw new UnsupportedOperationException("Unimplemented method 'setPerson'"); + } + + @Override + public boolean hasTeam(Team team) { + throw new AssertionError("Unimplemented method 'hasTeam'"); + } + + @Override + public void deleteTeam(Team target) { + throw new AssertionError("Unimplemented method 'deleteTeam'"); + } + + @Override + public void addTeam(Team team) { + throw new AssertionError("Unimplemented method 'addTeam'"); + } + + @Override + public void updatePersonInTeams(Person person) { + throw new AssertionError("Unimplemented method 'updatePersonInTeams'"); + } + + @Override + public void removeFromAllTeams(Person person) { + throw new AssertionError("Unimplemented method 'removeFromAllTeams'"); + } + + @Override + public void setTeam(Team team, Team editedTeam) { + throw new UnsupportedOperationException("Unimplemented method 'setTeam'"); + } + + @Override + public ObservableList getSortedTeamList() { + throw new UnsupportedOperationException("Unimplemented method 'getSortedTeamList'"); + } + + @Override + public ObservableList getSortedPersonList() { + + throw new UnsupportedOperationException("Unimplemented method 'getSortedPersonList'"); + } + + @Override + public void updateFilteredPersonList(Predicate predicate) { + throw new UnsupportedOperationException("Unimplemented method 'updateFilteredPersonList'"); + } + + @Override + public void updateFilteredTeamList(Predicate predicate) { + + } + + @Override + public void updateSortPerson(Comparator comparator) { + throw new UnsupportedOperationException("Unimplemented method 'updateSortPerson'"); + } + + @Override + public void updateSortTeam(Comparator comparator) { + throw new UnsupportedOperationException("Unimplemented method 'updateSortTeam'"); + } + + @Override + public ObservableList getTeamList() { + throw new AssertionError("Unimplemented method 'getTeamList'"); + } + } + + private class EmptyMomentoStub implements Memento { + private static final String DESC = "This should not matter"; + + @Override + public boolean restore() { + return false; + } + + @Override + public Memento getUpdatedMemento() { + return new EmptyMomentoStub(); + } + } + + private class EmptyModelStub extends ModelStub { + @Override + public Memento save() { + return new EmptyMomentoStub(); + } + } +} diff --git a/src/test/java/teambuilder/logic/parser/AddCommandParserTest.java b/src/test/java/teambuilder/logic/parser/AddCommandParserTest.java new file mode 100644 index 00000000000..563678b1daf --- /dev/null +++ b/src/test/java/teambuilder/logic/parser/AddCommandParserTest.java @@ -0,0 +1,139 @@ + +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_NAME_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_PHONE_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_TAG_DESC; +import static teambuilder.logic.commands.CommandTestUtil.MAJOR_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.MAJOR_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.NAME_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.NAME_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.PHONE_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.PHONE_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY; +import static teambuilder.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static teambuilder.logic.commands.CommandTestUtil.TAG_DESC_FRIEND; +import static teambuilder.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static teambuilder.testutil.TypicalPersons.AMY; +import static teambuilder.testutil.TypicalPersons.BOB; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.AddCommand; +import teambuilder.model.person.Email; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; +import teambuilder.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 + MAJOR_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 + MAJOR_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 + MAJOR_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 + MAJOR_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 + MAJOR_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 + + MAJOR_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 + MAJOR_DESC_AMY, new AddCommand(expectedPerson)); + // missing phone prefix + Person expectedBob = new PersonBuilder(BOB).withoutPhone().withTags().build(); + assertParseSuccess(parser, NAME_DESC_BOB + EMAIL_DESC_BOB + + ADDRESS_DESC_BOB + MAJOR_DESC_BOB, new AddCommand(expectedBob)); + assertParseSuccess(parser, NAME_DESC_BOB + " p/ " + EMAIL_DESC_BOB + + ADDRESS_DESC_BOB + MAJOR_DESC_BOB, new AddCommand(expectedBob)); + + expectedBob = new PersonBuilder(BOB).withoutEmail().withTags().build(); + assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + + ADDRESS_DESC_BOB + MAJOR_DESC_BOB, new AddCommand(expectedBob)); + assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + " e/" + + ADDRESS_DESC_BOB + MAJOR_DESC_BOB, new AddCommand(expectedBob)); + } + + @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 + MAJOR_DESC_BOB, expectedMessage); + + // all prefixes missing + assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + + VALID_ADDRESS_BOB + MAJOR_DESC_BOB, expectedMessage); + } + + @Test + public void parse_invalidValue_failure() { + // invalid name + assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + + MAJOR_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 + + MAJOR_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 + + MAJOR_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS); + + // invalid tag + assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + + MAJOR_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 + + MAJOR_DESC_BOB, Name.MESSAGE_CONSTRAINTS); + + // non-empty preamble + assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + + ADDRESS_DESC_BOB + MAJOR_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/ArgumentTokenizerTest.java b/src/test/java/teambuilder/logic/parser/ArgumentTokenizerTest.java similarity index 99% rename from src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java rename to src/test/java/teambuilder/logic/parser/ArgumentTokenizerTest.java index c97308935f5..1ed79f23346 100644 --- a/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java +++ b/src/test/java/teambuilder/logic/parser/ArgumentTokenizerTest.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; diff --git a/src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java b/src/test/java/teambuilder/logic/parser/CommandParserTestUtil.java similarity index 89% rename from src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java rename to src/test/java/teambuilder/logic/parser/CommandParserTestUtil.java index 9bf1ccf1cef..387b7649774 100644 --- a/src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java +++ b/src/test/java/teambuilder/logic/parser/CommandParserTestUtil.java @@ -1,9 +1,9 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; import static org.junit.jupiter.api.Assertions.assertEquals; -import seedu.address.logic.commands.Command; -import seedu.address.logic.parser.exceptions.ParseException; +import teambuilder.logic.commands.Command; +import teambuilder.logic.parser.exceptions.ParseException; /** * Contains helper methods for testing command parsers. diff --git a/src/test/java/teambuilder/logic/parser/CreateCommandParserTest.java b/src/test/java/teambuilder/logic/parser/CreateCommandParserTest.java new file mode 100644 index 00000000000..1ce53389b9d --- /dev/null +++ b/src/test/java/teambuilder/logic/parser/CreateCommandParserTest.java @@ -0,0 +1,51 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static teambuilder.logic.commands.CommandTestUtil.TAG_DESC_A; +import static teambuilder.logic.commands.CommandTestUtil.TEAMDESC_DESC_A; +import static teambuilder.logic.commands.CommandTestUtil.TEAMNAME_DESC_A; +import static teambuilder.logic.commands.CommandTestUtil.VALID_SKILLTAG_TEAM; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TEAMDESC_A; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TEAMNAME_A; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import java.util.Arrays; +import java.util.HashSet; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.CreateCommand; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +public class CreateCommandParserTest { + + private CreateCommandParser parser = new CreateCommandParser(); + + @Test + public void parse_allFieldsPresent_success() { + Team expectedTeam = new Team(new TeamName(VALID_TEAMNAME_A), new Desc(VALID_TEAMDESC_A), + new HashSet<>(Arrays.asList(new Tag(VALID_SKILLTAG_TEAM)))); + + // whitespace only preamble + assertParseSuccess(parser, PREAMBLE_WHITESPACE + TEAMNAME_DESC_A + TEAMDESC_DESC_A + TAG_DESC_A, + new CreateCommand(expectedTeam)); + + } + + @Test + public void parse_compulsoryFieldMissing_failure() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, CreateCommand.MESSAGE_USAGE); + + // missing team name prefix + assertParseFailure(parser, TEAMDESC_DESC_A + TAG_DESC_A, expectedMessage); + + // missing team desc prefix + assertParseFailure(parser, TEAMNAME_DESC_A + TAG_DESC_A, expectedMessage); + } + +} diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/teambuilder/logic/parser/DeleteCommandParserTest.java similarity index 57% rename from src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java rename to src/test/java/teambuilder/logic/parser/DeleteCommandParserTest.java index 27eaec84450..19686e9e02f 100644 --- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java +++ b/src/test/java/teambuilder/logic/parser/DeleteCommandParserTest.java @@ -1,13 +1,13 @@ -package seedu.address.logic.parser; +package teambuilder.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 static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import org.junit.jupiter.api.Test; -import seedu.address.logic.commands.DeleteCommand; +import teambuilder.logic.commands.DeleteCommand; /** * As we are only doing white-box testing, our test cases do not cover path variations @@ -27,6 +27,7 @@ public void parse_validArgs_returnsDeleteCommand() { @Test public void parse_invalidArgs_throwsParseException() { - assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + assertParseFailure(parser, "a", String.format(ParserUtil.MESSAGE_INVALID_INDEX + "\n" + + MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); } } diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/teambuilder/logic/parser/EditCommandParserTest.java similarity index 73% rename from src/test/java/seedu/address/logic/parser/EditCommandParserTest.java rename to src/test/java/teambuilder/logic/parser/EditCommandParserTest.java index 2ff31522486..6766c0157de 100644 --- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java +++ b/src/test/java/teambuilder/logic/parser/EditCommandParserTest.java @@ -1,54 +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.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.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.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_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.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; +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_NAME_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_PHONE_DESC; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_TAG_DESC; +import static teambuilder.logic.commands.CommandTestUtil.NAME_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.PHONE_DESC_AMY; +import static teambuilder.logic.commands.CommandTestUtil.PHONE_DESC_BOB; +import static teambuilder.logic.commands.CommandTestUtil.TAG_DESC_FRIEND; +import static teambuilder.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static teambuilder.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static teambuilder.testutil.TypicalIndexes.INDEX_THIRD_PERSON; 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 teambuilder.commons.core.index.Index; +import teambuilder.logic.commands.EditCommand; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.model.person.Email; +import teambuilder.model.person.Name; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; +import teambuilder.testutil.EditPersonDescriptorBuilder; 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); + String.format(ParserUtil.MESSAGE_INVALID_INDEX + "\n" + + MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE); private EditCommandParser parser = new EditCommandParser(); @@ -84,7 +83,6 @@ 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 diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/teambuilder/logic/parser/FindCommandParserTest.java similarity index 59% rename from src/test/java/seedu/address/logic/parser/FindCommandParserTest.java rename to src/test/java/teambuilder/logic/parser/FindCommandParserTest.java index 70f4f0e79c4..d8847072b4d 100644 --- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java +++ b/src/test/java/teambuilder/logic/parser/FindCommandParserTest.java @@ -1,15 +1,15 @@ -package seedu.address.logic.parser; +package teambuilder.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 static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; import java.util.Arrays; import org.junit.jupiter.api.Test; -import seedu.address.logic.commands.FindCommand; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import teambuilder.logic.commands.FindCommand; +import teambuilder.model.person.PersonContainsKeywordsPredicate; public class FindCommandParserTest { @@ -24,7 +24,7 @@ public void parse_emptyArg_throwsParseException() { public void parse_validArgs_returnsFindCommand() { // no leading and trailing whitespaces FindCommand expectedFindCommand = - new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); + new FindCommand(new PersonContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); assertParseSuccess(parser, "Alice Bob", expectedFindCommand); // multiple whitespaces between keywords diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/teambuilder/logic/parser/ParserUtilTest.java similarity index 70% rename from src/test/java/seedu/address/logic/parser/ParserUtilTest.java rename to src/test/java/teambuilder/logic/parser/ParserUtilTest.java index 4256788b1a7..f1db0e1dee0 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/teambuilder/logic/parser/ParserUtilTest.java @@ -1,10 +1,10 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; 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 teambuilder.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import java.util.Arrays; import java.util.Collections; @@ -13,12 +13,14 @@ 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 teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Name; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.TeamName; public class ParserUtilTest { private static final String INVALID_NAME = "R@chel"; @@ -26,6 +28,9 @@ public class ParserUtilTest { 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_TEAM = "Hackathon +"; + private static final String INVALID_TEAMDESC = ""; + private static final String VALID_NAME = "Rachel Walker"; private static final String VALID_PHONE = "123456"; @@ -33,6 +38,9 @@ public class ParserUtilTest { 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_TEAM_1 = "CS2103 T17 1"; + private static final String VALID_TEAM_2 = "TeamBest"; + private static final String VALID_TEAMDESC_1 = "This is a valid description."; private static final String WHITESPACE = " \t\r\n"; @@ -91,14 +99,14 @@ public void parsePhone_invalidValue_throwsParseException() { @Test public void parsePhone_validValueWithoutWhitespace_returnsPhone() throws Exception { - Phone expectedPhone = new Phone(VALID_PHONE); + Phone expectedPhone = Phone.of(VALID_PHONE); assertEquals(expectedPhone, ParserUtil.parsePhone(VALID_PHONE)); } @Test public void parsePhone_validValueWithWhitespace_returnsTrimmedPhone() throws Exception { String phoneWithWhitespace = WHITESPACE + VALID_PHONE + WHITESPACE; - Phone expectedPhone = new Phone(VALID_PHONE); + Phone expectedPhone = Phone.of(VALID_PHONE); assertEquals(expectedPhone, ParserUtil.parsePhone(phoneWithWhitespace)); } @@ -107,21 +115,16 @@ public void parseAddress_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> ParserUtil.parseAddress((String) null)); } - @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); + Address expectedAddress = Address.of(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); + Address expectedAddress = Address.of(VALID_ADDRESS); assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace)); } @@ -137,14 +140,14 @@ public void parseEmail_invalidValue_throwsParseException() { @Test public void parseEmail_validValueWithoutWhitespace_returnsEmail() throws Exception { - Email expectedEmail = new Email(VALID_EMAIL); + Email expectedEmail = Email.of(VALID_EMAIL); assertEquals(expectedEmail, ParserUtil.parseEmail(VALID_EMAIL)); } @Test public void parseEmail_validValueWithWhitespace_returnsTrimmedEmail() throws Exception { String emailWithWhitespace = WHITESPACE + VALID_EMAIL + WHITESPACE; - Email expectedEmail = new Email(VALID_EMAIL); + Email expectedEmail = Email.of(VALID_EMAIL); assertEquals(expectedEmail, ParserUtil.parseEmail(emailWithWhitespace)); } @@ -193,4 +196,45 @@ public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception { assertEquals(expectedTagSet, actualTagSet); } + + @Test + public void parseTeams_collectionWithValidTeams_returnsTeamSet() throws Exception { + Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TEAM_1, VALID_TEAM_2)); + Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TEAM_1), + new Tag(VALID_TEAM_2))); + assertEquals(expectedTagSet, actualTagSet); + } + + @Test + public void parseTags_collectionWithInvalidTeams_throwsParseException() { + assertThrows(ParseException.class, () -> + ParserUtil.parseTags(Arrays.asList(VALID_TEAM_1, INVALID_TEAM))); + } + + @Test + public void parseTeamName_invalidTeam_throwsParseException() { + assertThrows(ParseException.class, () -> + ParserUtil.parseTeamName(INVALID_TEAM)); + } + + @Test + public void parseTeamDesc_invalidDesc_throwsParseException() { + assertThrows(ParseException.class, () -> + ParserUtil.parseTeamDesc(INVALID_TEAMDESC)); + } + + @Test + public void parseTeamName_validTeam_returnsTeamSet() throws Exception { + TeamName actualDesc = ParserUtil.parseTeamName(VALID_TEAM_1); + TeamName expectedDesc = new TeamName(VALID_TEAM_1); + assertEquals(expectedDesc, actualDesc); + } + + @Test + public void parseTeamDesc_validDesc_returnsTeamSet() throws Exception { + Desc actualDesc = ParserUtil.parseTeamDesc(VALID_TEAMDESC_1); + Desc expectedDesc = new Desc(VALID_TEAMDESC_1); + assertEquals(expectedDesc, actualDesc); + } + } diff --git a/src/test/java/teambuilder/logic/parser/RemoveCommandParserTest.java b/src/test/java/teambuilder/logic/parser/RemoveCommandParserTest.java new file mode 100644 index 00000000000..61ef8bea302 --- /dev/null +++ b/src/test/java/teambuilder/logic/parser/RemoveCommandParserTest.java @@ -0,0 +1,48 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.commands.CommandTestUtil.INVALID_TAG_DESC; +import static teambuilder.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static teambuilder.logic.commands.CommandTestUtil.VALID_SKILLTAG_TEAM; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TEAMDESC_A; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TEAMNAME_A; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import java.util.Arrays; +import java.util.HashSet; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.RemoveCommand; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +class RemoveCommandParserTest { + private RemoveCommandParser parser = new RemoveCommandParser(); + + @Test + public void parse_allFieldsPresent_success() { + Team expectedTeam = new Team(new TeamName(VALID_TEAMNAME_A), new Desc(VALID_TEAMDESC_A), + new HashSet<>(Arrays.asList(new Tag(VALID_SKILLTAG_TEAM)))); + + // whitespace only preamble + assertParseSuccess(parser, PREAMBLE_WHITESPACE + VALID_TEAMNAME_A, + new RemoveCommand(expectedTeam.getName())); + + } + + @Test + public void parse_compulsoryFieldMissing_failure() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, RemoveCommand.MESSAGE_USAGE); + + // missing team name prefix + assertParseFailure(parser, INVALID_TAG_DESC, expectedMessage); + + // missing team desc prefix + assertParseFailure(parser, INVALID_TAG_DESC, expectedMessage); + } + +} diff --git a/src/test/java/teambuilder/logic/parser/ShowCommandParserTest.java b/src/test/java/teambuilder/logic/parser/ShowCommandParserTest.java new file mode 100644 index 00000000000..309ef8feb81 --- /dev/null +++ b/src/test/java/teambuilder/logic/parser/ShowCommandParserTest.java @@ -0,0 +1,33 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.ShowCommand; +import teambuilder.model.person.TeamContainsKeywordsPredicate; + +class ShowCommandParserTest { + private ShowCommandParser parser = new ShowCommandParser(); + + @Test + public void parse_emptyArg_throwsParseException() { + assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, ShowCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_validArgs_returnsFindCommand() { + // no leading and trailing whitespaces + ShowCommand expectedFindCommand = + new ShowCommand(new TeamContainsKeywordsPredicate(Arrays.asList("TeamA", "TeamB"))); + assertParseSuccess(parser, "TeamA TeamB", expectedFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n TeamA \n \t TeamB \t", expectedFindCommand); + } + +} diff --git a/src/test/java/teambuilder/logic/parser/SortCommandParserTest.java b/src/test/java/teambuilder/logic/parser/SortCommandParserTest.java new file mode 100644 index 00000000000..3403b3bd809 --- /dev/null +++ b/src/test/java/teambuilder/logic/parser/SortCommandParserTest.java @@ -0,0 +1,43 @@ +package teambuilder.logic.parser; + +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ORDER; +import static teambuilder.logic.commands.CommandTestUtil.VALID_SORT_BY; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseFailure; +import static teambuilder.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import org.junit.jupiter.api.Test; + +import teambuilder.logic.commands.SortCommand; + +public class SortCommandParserTest { + + private SortCommandParser parser = new SortCommandParser(); + + @Test + public void parse_allFieldsPresent_success() { + + SortCommand expectedSortCommand = new SortCommand(VALID_ORDER, VALID_SORT_BY); + + // whitespace only preamble + assertParseSuccess(parser, PREAMBLE_WHITESPACE + " " + VALID_ORDER + " " + VALID_SORT_BY, + expectedSortCommand); + + // no whitespace + assertParseSuccess(parser, VALID_ORDER + " " + VALID_SORT_BY, + expectedSortCommand); + + } + + @Test + public void parse_compulsoryFieldMissing_failure() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE); + + // missing order + assertParseFailure(parser, VALID_SORT_BY, expectedMessage); + + // missing sort by + assertParseFailure(parser, VALID_ORDER, expectedMessage); + } +} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/teambuilder/logic/parser/TeamBuilderParserTest.java similarity index 52% rename from src/test/java/seedu/address/logic/parser/AddressBookParserTest.java rename to src/test/java/teambuilder/logic/parser/TeamBuilderParserTest.java index d9659205b57..18e93df5c48 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/teambuilder/logic/parser/TeamBuilderParserTest.java @@ -1,11 +1,11 @@ -package seedu.address.logic.parser; +package teambuilder.logic.parser; import static org.junit.jupiter.api.Assertions.assertEquals; 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.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static teambuilder.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static teambuilder.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import java.util.Arrays; import java.util.List; @@ -13,25 +13,28 @@ import org.junit.jupiter.api.Test; -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.commands.ClearCommand; -import seedu.address.logic.commands.DeleteCommand; -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.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; - -public class AddressBookParserTest { - - private final AddressBookParser parser = new AddressBookParser(); +import teambuilder.logic.commands.AddCommand; +import teambuilder.logic.commands.ClearCommand; +import teambuilder.logic.commands.DeleteCommand; +import teambuilder.logic.commands.EditCommand; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.logic.commands.ExitCommand; +import teambuilder.logic.commands.FindCommand; +import teambuilder.logic.commands.HelpCommand; +import teambuilder.logic.commands.ListCommand; +import teambuilder.logic.commands.ShowCommand; +import teambuilder.logic.commands.SortCommand; +import teambuilder.logic.parser.exceptions.ParseException; +import teambuilder.model.person.Person; +import teambuilder.model.person.PersonContainsKeywordsPredicate; +import teambuilder.model.person.TeamContainsKeywordsPredicate; +import teambuilder.testutil.EditPersonDescriptorBuilder; +import teambuilder.testutil.PersonBuilder; +import teambuilder.testutil.PersonUtil; + +public class TeamBuilderParserTest { + + private final TeamBuilderParser parser = new TeamBuilderParser(); @Test public void parseCommand_add() throws Exception { @@ -48,8 +51,8 @@ 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()); + DeleteCommand command = (DeleteCommand) parser + .parseCommand(DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased()); assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command); } @@ -57,9 +60,10 @@ public void parseCommand_delete() throws Exception { public void parseCommand_edit() throws Exception { Person person = new PersonBuilder().build(); EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build(); + EditCommand expected = new EditCommand(INDEX_FIRST_PERSON, descriptor); EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor)); - assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command); + assertEquals(expected, command); } @Test @@ -71,9 +75,17 @@ public void parseCommand_exit() throws Exception { @Test public void parseCommand_find() throws Exception { List keywords = Arrays.asList("foo", "bar", "baz"); - FindCommand command = (FindCommand) parser.parseCommand( - FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); - assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command); + FindCommand command = (FindCommand) parser + .parseCommand(FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); + assertEquals(new FindCommand(new PersonContainsKeywordsPredicate(keywords)), command); + } + + @Test + public void parseCommand_show() throws Exception { + List keywords = Arrays.asList("TeamA"); + ShowCommand command = (ShowCommand) parser + .parseCommand(ShowCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); + assertEquals(new ShowCommand(new TeamContainsKeywordsPredicate(keywords)), command); } @Test @@ -88,6 +100,13 @@ public void parseCommand_list() throws Exception { assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand); } + @Test + public void parseCommand_sort() throws Exception { + SortCommand command = (SortCommand) parser.parseCommand(SortCommand.COMMAND_WORD + " " + + "desc" + " " + "tcount"); + assertEquals(new SortCommand("desc", "tcount"), command); + } + @Test public void parseCommand_unrecognisedInput_throwsParseException() { assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), () @@ -98,4 +117,6 @@ public void parseCommand_unrecognisedInput_throwsParseException() { public void parseCommand_unknownCommand_throwsParseException() { assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand")); } + } + diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/teambuilder/model/ModelManagerTest.java similarity index 83% rename from src/test/java/seedu/address/model/ModelManagerTest.java rename to src/test/java/teambuilder/model/ModelManagerTest.java index 2cf1418d116..df9f56c16fa 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/teambuilder/model/ModelManagerTest.java @@ -1,12 +1,12 @@ -package seedu.address.model; +package teambuilder.model; 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.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalPersons.ALICE; -import static seedu.address.testutil.TypicalPersons.BENSON; +import static teambuilder.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.ALICE; +import static teambuilder.testutil.TypicalPersons.BENSON; import java.nio.file.Path; import java.nio.file.Paths; @@ -14,9 +14,9 @@ import org.junit.jupiter.api.Test; -import seedu.address.commons.core.GuiSettings; -import seedu.address.model.person.NameContainsKeywordsPredicate; -import seedu.address.testutil.AddressBookBuilder; +import teambuilder.commons.core.GuiSettings; +import teambuilder.model.person.PersonContainsKeywordsPredicate; +import teambuilder.testutil.TeamBuilderMaker; public class ModelManagerTest { @@ -26,7 +26,7 @@ public class ModelManagerTest { public void constructor() { assertEquals(new UserPrefs(), modelManager.getUserPrefs()); assertEquals(new GuiSettings(), modelManager.getGuiSettings()); - assertEquals(new AddressBook(), new AddressBook(modelManager.getAddressBook())); + assertEquals(new TeamBuilder(), new TeamBuilder(modelManager.getTeamBuilder())); } @Test @@ -90,13 +90,13 @@ public void hasPerson_personInAddressBook_returnsTrue() { @Test public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() { - assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0)); + assertThrows(UnsupportedOperationException.class, () -> modelManager.getSortedPersonList().remove(0)); } @Test public void equals() { - AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build(); - AddressBook differentAddressBook = new AddressBook(); + TeamBuilder addressBook = new TeamBuilderMaker().withPerson(ALICE).withPerson(BENSON).build(); + TeamBuilder differentAddressBook = new TeamBuilder(); UserPrefs userPrefs = new UserPrefs(); // same values -> returns true @@ -118,7 +118,7 @@ public void equals() { // different filteredList -> returns false String[] keywords = ALICE.getName().fullName.split("\\s+"); - modelManager.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(keywords))); + modelManager.updateFilteredPersonList(new PersonContainsKeywordsPredicate(Arrays.asList(keywords))); assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs))); // resets modelManager to initial state for upcoming tests diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/teambuilder/model/TeamBuilderTest.java similarity index 73% rename from src/test/java/seedu/address/model/AddressBookTest.java rename to src/test/java/teambuilder/model/TeamBuilderTest.java index 87782528ecd..4d7577caffd 100644 --- a/src/test/java/seedu/address/model/AddressBookTest.java +++ b/src/test/java/teambuilder/model/TeamBuilderTest.java @@ -1,13 +1,13 @@ -package seedu.address.model; +package teambuilder.model; 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.getTypicalAddressBook; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.ALICE; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; import java.util.Arrays; import java.util.Collection; @@ -18,13 +18,14 @@ 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 teambuilder.model.person.Person; +import teambuilder.model.person.exceptions.DuplicatePersonException; +import teambuilder.model.team.Team; +import teambuilder.testutil.PersonBuilder; -public class AddressBookTest { +public class TeamBuilderTest { - private final AddressBook addressBook = new AddressBook(); + private final TeamBuilder addressBook = new TeamBuilder(); @Test public void constructor() { @@ -38,7 +39,7 @@ public void resetData_null_throwsNullPointerException() { @Test public void resetData_withValidReadOnlyAddressBook_replacesData() { - AddressBook newData = getTypicalAddressBook(); + TeamBuilder newData = getTypicalAddressBook(); addressBook.resetData(newData); assertEquals(newData, addressBook); } @@ -86,8 +87,9 @@ public void getPersonList_modifyList_throwsUnsupportedOperationException() { /** * A stub ReadOnlyAddressBook whose persons list can violate interface constraints. */ - private static class AddressBookStub implements ReadOnlyAddressBook { + private static class AddressBookStub implements ReadOnlyTeamBuilder { private final ObservableList persons = FXCollections.observableArrayList(); + private final ObservableList teams = FXCollections.observableArrayList(); AddressBookStub(Collection persons) { this.persons.setAll(persons); @@ -97,6 +99,11 @@ private static class AddressBookStub implements ReadOnlyAddressBook { public ObservableList getPersonList() { return persons; } + + @Override + public ObservableList getTeamList() { + throw new AssertionError("This method should not be called."); + } } } diff --git a/src/test/java/seedu/address/model/UserPrefsTest.java b/src/test/java/teambuilder/model/UserPrefsTest.java similarity index 86% rename from src/test/java/seedu/address/model/UserPrefsTest.java rename to src/test/java/teambuilder/model/UserPrefsTest.java index b1307a70d52..05b80021fdc 100644 --- a/src/test/java/seedu/address/model/UserPrefsTest.java +++ b/src/test/java/teambuilder/model/UserPrefsTest.java @@ -1,6 +1,6 @@ -package seedu.address.model; +package teambuilder.model; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/teambuilder/model/person/AddressTest.java similarity index 54% rename from src/test/java/seedu/address/model/person/AddressTest.java rename to src/test/java/teambuilder/model/person/AddressTest.java index dcd3be87b3a..55ea2c3d228 100644 --- a/src/test/java/seedu/address/model/person/AddressTest.java +++ b/src/test/java/teambuilder/model/person/AddressTest.java @@ -1,8 +1,7 @@ -package seedu.address.model.person; +package teambuilder.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 static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -10,13 +9,7 @@ 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)); + assertThrows(NullPointerException.class, () -> Address.of(null)); } @Test @@ -25,8 +18,8 @@ public void isValidAddress() { assertThrows(NullPointerException.class, () -> Address.isValidAddress(null)); // invalid addresses - assertFalse(Address.isValidAddress("")); // empty string - assertFalse(Address.isValidAddress(" ")); // spaces only + assertTrue(Address.isValidAddress("")); // empty string + assertTrue(Address.isValidAddress(" ")); // spaces only // valid addresses assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355")); diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/teambuilder/model/person/EmailTest.java similarity index 87% rename from src/test/java/seedu/address/model/person/EmailTest.java rename to src/test/java/teambuilder/model/person/EmailTest.java index bbcc6c8c98e..3f6734d2251 100644 --- a/src/test/java/seedu/address/model/person/EmailTest.java +++ b/src/test/java/teambuilder/model/person/EmailTest.java @@ -1,8 +1,8 @@ -package seedu.address.model.person; +package teambuilder.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 static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -10,13 +10,7 @@ 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)); + assertThrows(NullPointerException.class, () -> Email.of(null)); } @Test @@ -25,8 +19,8 @@ public void isValidEmail() { assertThrows(NullPointerException.class, () -> Email.isValidEmail(null)); // blank email - assertFalse(Email.isValidEmail("")); // empty string - assertFalse(Email.isValidEmail(" ")); // spaces only + assertTrue(Email.isValidEmail("")); // empty string + assertTrue(Email.isValidEmail(" ")); // spaces only // missing parts assertFalse(Email.isValidEmail("@example.com")); // missing local part diff --git a/src/test/java/seedu/address/model/person/NameTest.java b/src/test/java/teambuilder/model/person/NameTest.java similarity index 93% rename from src/test/java/seedu/address/model/person/NameTest.java rename to src/test/java/teambuilder/model/person/NameTest.java index c9801392874..e15c4936d0d 100644 --- a/src/test/java/seedu/address/model/person/NameTest.java +++ b/src/test/java/teambuilder/model/person/NameTest.java @@ -1,8 +1,8 @@ -package seedu.address.model.person; +package teambuilder.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 static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/teambuilder/model/person/PersonContainsKeywordsPredicateTest.java similarity index 62% rename from src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java rename to src/test/java/teambuilder/model/person/PersonContainsKeywordsPredicateTest.java index f136664e017..e208ceaeada 100644 --- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java +++ b/src/test/java/teambuilder/model/person/PersonContainsKeywordsPredicateTest.java @@ -1,4 +1,4 @@ -package seedu.address.model.person; +package teambuilder.model.person; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -9,23 +9,25 @@ import org.junit.jupiter.api.Test; -import seedu.address.testutil.PersonBuilder; +import teambuilder.testutil.PersonBuilder; -public class NameContainsKeywordsPredicateTest { +public class PersonContainsKeywordsPredicateTest { @Test public void equals() { List firstPredicateKeywordList = Collections.singletonList("first"); List secondPredicateKeywordList = Arrays.asList("first", "second"); - NameContainsKeywordsPredicate firstPredicate = new NameContainsKeywordsPredicate(firstPredicateKeywordList); - NameContainsKeywordsPredicate secondPredicate = new NameContainsKeywordsPredicate(secondPredicateKeywordList); + PersonContainsKeywordsPredicate firstPredicate = new PersonContainsKeywordsPredicate(firstPredicateKeywordList); + PersonContainsKeywordsPredicate secondPredicate = + new PersonContainsKeywordsPredicate(secondPredicateKeywordList); // same object -> returns true assertTrue(firstPredicate.equals(firstPredicate)); // same values -> returns true - NameContainsKeywordsPredicate firstPredicateCopy = new NameContainsKeywordsPredicate(firstPredicateKeywordList); + PersonContainsKeywordsPredicate firstPredicateCopy = + new PersonContainsKeywordsPredicate(firstPredicateKeywordList); assertTrue(firstPredicate.equals(firstPredicateCopy)); // different types -> returns false @@ -41,34 +43,35 @@ public void equals() { @Test public void test_nameContainsKeywords_returnsTrue() { // One keyword - NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Alice")); + PersonContainsKeywordsPredicate predicate = + new PersonContainsKeywordsPredicate(Collections.singletonList("Alice")); assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build())); // Multiple keywords - predicate = new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")); + predicate = new PersonContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")); assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build())); // Only one matching keyword - predicate = new NameContainsKeywordsPredicate(Arrays.asList("Bob", "Carol")); + predicate = new PersonContainsKeywordsPredicate(Arrays.asList("Bob", "Carol")); assertTrue(predicate.test(new PersonBuilder().withName("Alice Carol").build())); // Mixed-case keywords - predicate = new NameContainsKeywordsPredicate(Arrays.asList("aLIce", "bOB")); + predicate = new PersonContainsKeywordsPredicate(Arrays.asList("aLIce", "bOB")); assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build())); } @Test public void test_nameDoesNotContainKeywords_returnsFalse() { // Zero keywords - NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.emptyList()); + PersonContainsKeywordsPredicate predicate = new PersonContainsKeywordsPredicate(Collections.emptyList()); assertFalse(predicate.test(new PersonBuilder().withName("Alice").build())); // Non-matching keyword - predicate = new NameContainsKeywordsPredicate(Arrays.asList("Carol")); + predicate = new PersonContainsKeywordsPredicate(Arrays.asList("Carol")); assertFalse(predicate.test(new PersonBuilder().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")); + predicate = new PersonContainsKeywordsPredicate(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())); } diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/teambuilder/model/person/PersonTest.java similarity index 80% rename from src/test/java/seedu/address/model/person/PersonTest.java rename to src/test/java/teambuilder/model/person/PersonTest.java index b29c097cfd4..a14df4b4ca7 100644 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ b/src/test/java/teambuilder/model/person/PersonTest.java @@ -1,19 +1,19 @@ -package seedu.address.model.person; +package teambuilder.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 static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.ALICE; +import static teambuilder.testutil.TypicalPersons.BOB; import org.junit.jupiter.api.Test; -import seedu.address.testutil.PersonBuilder; +import teambuilder.testutil.PersonBuilder; public class PersonTest { @@ -42,12 +42,12 @@ public void isSamePerson() { // 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)); + assertTrue(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)); + assertTrue(BOB.isSamePerson(editedBob)); } @Test diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/teambuilder/model/person/PhoneTest.java similarity index 68% rename from src/test/java/seedu/address/model/person/PhoneTest.java rename to src/test/java/teambuilder/model/person/PhoneTest.java index 8dd52766a5f..80058c8d149 100644 --- a/src/test/java/seedu/address/model/person/PhoneTest.java +++ b/src/test/java/teambuilder/model/person/PhoneTest.java @@ -1,8 +1,9 @@ -package seedu.address.model.person; +package teambuilder.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.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -10,13 +11,13 @@ public class PhoneTest { @Test public void constructor_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new Phone(null)); + assertThrows(NullPointerException.class, () -> Phone.of(null)); } @Test - public void constructor_invalidPhone_throwsIllegalArgumentException() { + public void constructor_emptyString_returnsEmptyPhone() { String invalidPhone = ""; - assertThrows(IllegalArgumentException.class, () -> new Phone(invalidPhone)); + assertEquals(Phone.getEmptyPhone(), Phone.of(invalidPhone)); } @Test @@ -25,8 +26,8 @@ public void isValidPhone() { assertThrows(NullPointerException.class, () -> Phone.isValidPhone(null)); // invalid phone numbers - assertFalse(Phone.isValidPhone("")); // empty string - assertFalse(Phone.isValidPhone(" ")); // spaces only + assertTrue(Phone.isValidPhone("")); // empty string + assertTrue(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 diff --git a/src/test/java/teambuilder/model/person/TeamContainsKeywordsPredicateTest.java b/src/test/java/teambuilder/model/person/TeamContainsKeywordsPredicateTest.java new file mode 100644 index 00000000000..4c8e0f43637 --- /dev/null +++ b/src/test/java/teambuilder/model/person/TeamContainsKeywordsPredicateTest.java @@ -0,0 +1,77 @@ +package teambuilder.model.person; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import teambuilder.testutil.PersonBuilder; + +class TeamContainsKeywordsPredicateTest { + + @Test + public void testEquals() { + List firstPredicateKeywordList = Collections.singletonList("first"); + List secondPredicateKeywordList = Arrays.asList("first", "second"); + + TeamContainsKeywordsPredicate firstPredicate = new TeamContainsKeywordsPredicate(firstPredicateKeywordList); + TeamContainsKeywordsPredicate secondPredicate = new TeamContainsKeywordsPredicate(secondPredicateKeywordList); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + TeamContainsKeywordsPredicate firstPredicateCopy = new TeamContainsKeywordsPredicate(firstPredicateKeywordList); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different person -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_teamContainsKeywords_returnsTrue() { + // One keyword + TeamContainsKeywordsPredicate predicate = new TeamContainsKeywordsPredicate(Collections.singletonList("TeamA")); + assertTrue(predicate.test(new PersonBuilder().withName("Alice").withTeams("TeamA").build())); + + // Multiple keywords + predicate = new TeamContainsKeywordsPredicate(Arrays.asList("TeamA", "TeamB")); + assertTrue(predicate.test(new PersonBuilder().withName("Alice").withTeams("TeamA TeamB").build())); + + // Only one matching keyword + predicate = new TeamContainsKeywordsPredicate(Arrays.asList("TeamA", "TeamB")); + assertTrue(predicate.test(new PersonBuilder().withName("Alice").withTeams("TeamA").build())); + + // Mixed-case keywords + predicate = new TeamContainsKeywordsPredicate(Arrays.asList("teaMa", "tEAmB")); + assertTrue(predicate.test(new PersonBuilder().withName("Alice").withTeams("TeamA TeamB").build())); + + } + + @Test + public void test_teamDoesNotContainKeywords_returnsFalse() { + // Zero keywords + TeamContainsKeywordsPredicate predicate = new TeamContainsKeywordsPredicate(Collections.emptyList()); + assertFalse(predicate.test(new PersonBuilder().withTeams("TeamA").build())); + + // Non-matching keyword + predicate = new TeamContainsKeywordsPredicate(Arrays.asList("TeamA")); + assertFalse(predicate.test(new PersonBuilder().withTeams("TeamB").build())); + + // Keywords match phone, email and address, but does not match name + predicate = new TeamContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street")); + assertFalse(predicate.test(new PersonBuilder().withTeams("TeamA").withPhone("12345") + .withEmail("alice@email.com").withAddress("Main Street").build())); + } + +} diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/teambuilder/model/person/UniquePersonListTest.java similarity index 91% rename from src/test/java/seedu/address/model/person/UniquePersonListTest.java rename to src/test/java/teambuilder/model/person/UniquePersonListTest.java index 1cc5fe9e0fe..73883012cd0 100644 --- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java +++ b/src/test/java/teambuilder/model/person/UniquePersonListTest.java @@ -1,13 +1,13 @@ -package seedu.address.model.person; +package teambuilder.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 static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.ALICE; +import static teambuilder.testutil.TypicalPersons.BOB; import java.util.Arrays; import java.util.Collections; @@ -15,9 +15,9 @@ 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; +import teambuilder.model.person.exceptions.DuplicatePersonException; +import teambuilder.model.person.exceptions.PersonNotFoundException; +import teambuilder.testutil.PersonBuilder; public class UniquePersonListTest { diff --git a/src/test/java/teambuilder/model/person/UniqueTeamListTest.java b/src/test/java/teambuilder/model/person/UniqueTeamListTest.java new file mode 100644 index 00000000000..68f643eccd2 --- /dev/null +++ b/src/test/java/teambuilder/model/person/UniqueTeamListTest.java @@ -0,0 +1,45 @@ +package teambuilder.model.person; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalTeams.TEAM_A; + +import org.junit.jupiter.api.Test; + +import teambuilder.model.team.UniqueTeamList; +import teambuilder.model.team.exceptions.DuplicateTeamException; + +public class UniqueTeamListTest { + + private final UniqueTeamList uniqueTeamList = new UniqueTeamList(); + + @Test + public void contains_nullTeam_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTeamList.contains(null)); + } + + @Test + public void contains_personNotInList_returnsFalse() { + assertFalse(uniqueTeamList.contains(TEAM_A)); + } + + @Test + public void contains_personInList_returnsTrue() { + uniqueTeamList.add(TEAM_A); + assertTrue(uniqueTeamList.contains(TEAM_A)); + } + + @Test + public void add_nullPerson_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTeamList.add(null)); + } + + @Test + public void add_duplicatePerson_throwsDuplicatePersonException() { + uniqueTeamList.add(TEAM_A); + assertThrows(DuplicateTeamException.class, () -> uniqueTeamList.add(TEAM_A)); + } + + +} diff --git a/src/test/java/seedu/address/model/tag/TagTest.java b/src/test/java/teambuilder/model/tag/TagTest.java similarity index 86% rename from src/test/java/seedu/address/model/tag/TagTest.java rename to src/test/java/teambuilder/model/tag/TagTest.java index 64d07d79ee2..91c21ee0952 100644 --- a/src/test/java/seedu/address/model/tag/TagTest.java +++ b/src/test/java/teambuilder/model/tag/TagTest.java @@ -1,6 +1,6 @@ -package seedu.address.model.tag; +package teambuilder.model.tag; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/teambuilder/model/team/TeamTest.java b/src/test/java/teambuilder/model/team/TeamTest.java new file mode 100644 index 00000000000..2e428ae0140 --- /dev/null +++ b/src/test/java/teambuilder/model/team/TeamTest.java @@ -0,0 +1,79 @@ +package teambuilder.model.team; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static teambuilder.logic.commands.CommandTestUtil.VALID_SKILLTAG_TEAM; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TEAMDESC_A; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TEAMNAME_A; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalTeams.TEAM_A; +import static teambuilder.testutil.TypicalTeams.TEAM_B; +import static teambuilder.testutil.TypicalTeams.TEAM_C; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import teambuilder.testutil.TeamBuilder; + +class TeamTest { + @Test + public void asObservableList_modifyList_throwsUnsupportedOperationException() { + Team team = new TeamBuilder().build(); + assertThrows(UnsupportedOperationException.class, () -> + Collections.unmodifiableSet(team.getTags()).remove(0)); + } + + @Test + public void isSameTeam() { + // same object -> returns true + assertTrue(TEAM_A.isSameTeam(TEAM_A)); + + // null -> returns false + assertFalse(TEAM_A.isSameTeam(null)); + + // same name, all other attributes different -> returns true + Team editedTeamA = new TeamBuilder(TEAM_A).withDesc(VALID_TEAMDESC_A).build(); + assertTrue(TEAM_A.isSameTeam(editedTeamA)); + + // different name, all other attributes same -> returns false + editedTeamA = new TeamBuilder(TEAM_A).withName(VALID_TEAMNAME_A).build(); + assertFalse(TEAM_A.isSameTeam(editedTeamA)); + + // name differs in case, all other attributes same -> returns false + Team editedTeamB = new TeamBuilder(TEAM_B).withName(VALID_TEAMNAME_A.toLowerCase()).build(); + assertFalse(TEAM_B.isSameTeam(editedTeamB)); + } + + @Test + public void equals() { + // same values -> returns true + Team teamCopy = new TeamBuilder(TEAM_C).build(); + assertTrue(TEAM_C.equals(teamCopy)); + + // same object -> returns true + assertTrue(TEAM_C.equals(TEAM_C)); + + // null -> returns false + assertFalse(TEAM_C.equals(null)); + + // different type -> returns false + assertFalse(TEAM_C.equals(5)); + + // different person -> returns false + assertFalse(TEAM_C.equals(TEAM_A)); + + // different name -> returns false + Team editedTeamA = new TeamBuilder(TEAM_A).withName(VALID_TEAMNAME_A).build(); + assertFalse(TEAM_A.equals(editedTeamA)); + + // different desc -> returns true + editedTeamA = new TeamBuilder(TEAM_A).withDesc(VALID_TEAMDESC_A).build(); + assertTrue(TEAM_A.equals(editedTeamA)); + + // different tags -> returns true + editedTeamA = new TeamBuilder(TEAM_A).withSkillTags(VALID_SKILLTAG_TEAM).build(); + assertTrue(TEAM_A.equals(editedTeamA)); + } + +} diff --git a/src/test/java/teambuilder/model/util/SampleDataUtilTest.java b/src/test/java/teambuilder/model/util/SampleDataUtilTest.java new file mode 100644 index 00000000000..a8102a3a621 --- /dev/null +++ b/src/test/java/teambuilder/model/util/SampleDataUtilTest.java @@ -0,0 +1,20 @@ +package teambuilder.model.util; + +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; + +public class SampleDataUtilTest { + @Test + public void samplePersons_samplePersons_isValid() { + Person[] persons = SampleDataUtil.getSamplePersons(); + } + + @Test + public void sampleNames_samplePersons_isValid() { + Set persons = SampleDataUtil.getNameSet(); + } +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/teambuilder/storage/JsonAdaptedPersonTest.java similarity index 71% rename from src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java rename to src/test/java/teambuilder/storage/JsonAdaptedPersonTest.java index 83b11331cdb..52d3faa0c15 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java +++ b/src/test/java/teambuilder/storage/JsonAdaptedPersonTest.java @@ -1,9 +1,9 @@ -package seedu.address.storage; +package teambuilder.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 static teambuilder.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT; +import static teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.BENSON; import java.util.ArrayList; import java.util.List; @@ -11,11 +11,11 @@ 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; +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Name; +import teambuilder.model.person.Phone; public class JsonAdaptedPersonTest { private static final String INVALID_NAME = "R@chel"; @@ -28,6 +28,7 @@ public class JsonAdaptedPersonTest { 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 String VALID_MAJOR = BENSON.getMajor().toString(); private static final List VALID_TAGS = BENSON.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList()); @@ -41,14 +42,17 @@ public void toModelType_validPersonDetails_returnsPerson() throws Exception { @Test public void toModelType_invalidName_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_MAJOR, + VALID_TAGS, 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); + JsonAdaptedPerson person = + new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_MAJOR, + VALID_TAGS, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -56,14 +60,17 @@ public void toModelType_nullName_throwsIllegalValueException() { @Test public void toModelType_invalidPhone_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_MAJOR, + VALID_TAGS, 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); + JsonAdaptedPerson person = + new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_MAJOR, + VALID_TAGS, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -71,29 +78,26 @@ public void toModelType_nullPhone_throwsIllegalValueException() { @Test public void toModelType_invalidEmail_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_MAJOR, + VALID_TAGS, 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; + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_MAJOR, + VALID_TAGS, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()); 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); + JsonAdaptedPerson person = + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_MAJOR, + VALID_TAGS, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -103,7 +107,8 @@ 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); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_MAJOR, + invalidTags, VALID_TAGS); assertThrows(IllegalValueException.class, person::toModelType); } diff --git a/src/test/java/teambuilder/storage/JsonSerializableTeamBuilderTest.java b/src/test/java/teambuilder/storage/JsonSerializableTeamBuilderTest.java new file mode 100644 index 00000000000..64cc72a2b76 --- /dev/null +++ b/src/test/java/teambuilder/storage/JsonSerializableTeamBuilderTest.java @@ -0,0 +1,48 @@ +package teambuilder.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static teambuilder.testutil.Assert.assertThrows; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; + +import teambuilder.commons.exceptions.IllegalValueException; +import teambuilder.commons.util.JsonUtil; +import teambuilder.model.TeamBuilder; +import teambuilder.model.person.exceptions.DuplicatePersonException; +import teambuilder.testutil.TypicalPersons; + +public class JsonSerializableTeamBuilderTest { + + 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"); + + @Test + public void toModelType_typicalPersonsFile_success() throws Exception { + JsonSerializableTeamBuilder dataFromFile = JsonUtil + .readJsonFile(TYPICAL_PERSONS_FILE, JsonSerializableTeamBuilder.class).get(); + TeamBuilder addressBookFromFile = dataFromFile.toModelType(); + TeamBuilder typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook(); + assertEquals(addressBookFromFile, typicalPersonsAddressBook); + } + + @Test + public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception { + JsonSerializableTeamBuilder dataFromFile = JsonUtil + .readJsonFile(INVALID_PERSON_FILE, JsonSerializableTeamBuilder.class).get(); + assertThrows(IllegalValueException.class, dataFromFile::toModelType); + } + + @Test + public void toModelType_duplicatePersons_throwsDuplicatePersonException() throws Exception { + JsonSerializableTeamBuilder dataFromFile = JsonUtil + .readJsonFile(DUPLICATE_PERSON_FILE, JsonSerializableTeamBuilder.class).get(); + assertThrows(DuplicatePersonException.class, "Operation would result in duplicate persons", + dataFromFile::toModelType); + } + +} diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/teambuilder/storage/JsonTeamBuilderStorageTest.java similarity index 73% rename from src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java rename to src/test/java/teambuilder/storage/JsonTeamBuilderStorageTest.java index ac3c3af9566..f5179d6a202 100644 --- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java +++ b/src/test/java/teambuilder/storage/JsonTeamBuilderStorageTest.java @@ -1,12 +1,12 @@ -package seedu.address.storage; +package teambuilder.storage; 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 teambuilder.testutil.Assert.assertThrows; +import static teambuilder.testutil.TypicalPersons.ALICE; +import static teambuilder.testutil.TypicalPersons.HOON; +import static teambuilder.testutil.TypicalPersons.IDA; +import static teambuilder.testutil.TypicalPersons.getTypicalAddressBook; import java.io.IOException; import java.nio.file.Path; @@ -15,11 +15,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.TeamBuilder; -public class JsonAddressBookStorageTest { +public class JsonTeamBuilderStorageTest { private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonAddressBookStorageTest"); @TempDir @@ -30,8 +30,8 @@ public void readAddressBook_nullFilePath_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> readAddressBook(null)); } - private java.util.Optional readAddressBook(String filePath) throws Exception { - return new JsonAddressBookStorage(Paths.get(filePath)).readAddressBook(addToTestDataPathIfNotNull(filePath)); + private java.util.Optional readAddressBook(String filePath) throws Exception { + return new JsonTeamBuilderStorage(Paths.get(filePath)).readAddressBook(addToTestDataPathIfNotNull(filePath)); } private Path addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) { @@ -63,26 +63,26 @@ public void readAddressBook_invalidAndValidPersonAddressBook_throwDataConversion @Test public void readAndSaveAddressBook_allInOrder_success() throws Exception { Path filePath = testFolder.resolve("TempAddressBook.json"); - AddressBook original = getTypicalAddressBook(); - JsonAddressBookStorage jsonAddressBookStorage = new JsonAddressBookStorage(filePath); + TeamBuilder original = getTypicalAddressBook(); + JsonTeamBuilderStorage jsonAddressBookStorage = new JsonTeamBuilderStorage(filePath); // Save in new file and read back jsonAddressBookStorage.saveAddressBook(original, filePath); - ReadOnlyAddressBook readBack = jsonAddressBookStorage.readAddressBook(filePath).get(); - assertEquals(original, new AddressBook(readBack)); + ReadOnlyTeamBuilder readBack = jsonAddressBookStorage.readAddressBook(filePath).get(); + assertEquals(original, new TeamBuilder(readBack)); // Modify data, overwrite exiting file, and read back original.addPerson(HOON); original.removePerson(ALICE); jsonAddressBookStorage.saveAddressBook(original, filePath); readBack = jsonAddressBookStorage.readAddressBook(filePath).get(); - assertEquals(original, new AddressBook(readBack)); + assertEquals(original, new TeamBuilder(readBack)); // Save and read without specifying file path original.addPerson(IDA); jsonAddressBookStorage.saveAddressBook(original); // file path not specified readBack = jsonAddressBookStorage.readAddressBook().get(); // file path not specified - assertEquals(original, new AddressBook(readBack)); + assertEquals(original, new TeamBuilder(readBack)); } @@ -94,9 +94,9 @@ public void saveAddressBook_nullAddressBook_throwsNullPointerException() { /** * Saves {@code addressBook} at the specified {@code filePath}. */ - private void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) { + private void saveAddressBook(ReadOnlyTeamBuilder addressBook, String filePath) { try { - new JsonAddressBookStorage(Paths.get(filePath)) + new JsonTeamBuilderStorage(Paths.get(filePath)) .saveAddressBook(addressBook, addToTestDataPathIfNotNull(filePath)); } catch (IOException ioe) { throw new AssertionError("There should not be an error writing to the file.", ioe); @@ -105,6 +105,6 @@ private void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) { @Test public void saveAddressBook_nullFilePath_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> saveAddressBook(new AddressBook(), null)); + assertThrows(NullPointerException.class, () -> saveAddressBook(new TeamBuilder(), null)); } } diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/teambuilder/storage/JsonUserPrefsStorageTest.java similarity index 94% rename from src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java rename to src/test/java/teambuilder/storage/JsonUserPrefsStorageTest.java index 16f33f4a6bb..c150998ffef 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/teambuilder/storage/JsonUserPrefsStorageTest.java @@ -1,8 +1,8 @@ -package seedu.address.storage; +package teambuilder.storage; 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 teambuilder.testutil.Assert.assertThrows; import java.io.IOException; import java.nio.file.Path; @@ -12,9 +12,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.UserPrefs; +import teambuilder.commons.core.GuiSettings; +import teambuilder.commons.exceptions.DataConversionException; +import teambuilder.model.UserPrefs; public class JsonUserPrefsStorageTest { diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/teambuilder/storage/StorageManagerTest.java similarity index 77% rename from src/test/java/seedu/address/storage/StorageManagerTest.java rename to src/test/java/teambuilder/storage/StorageManagerTest.java index 99a16548970..33159157c22 100644 --- a/src/test/java/seedu/address/storage/StorageManagerTest.java +++ b/src/test/java/teambuilder/storage/StorageManagerTest.java @@ -1,8 +1,8 @@ -package seedu.address.storage; +package teambuilder.storage; 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 teambuilder.testutil.TypicalPersons.getTypicalAddressBook; import java.nio.file.Path; @@ -10,10 +10,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import seedu.address.commons.core.GuiSettings; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; +import teambuilder.commons.core.GuiSettings; +import teambuilder.model.ReadOnlyTeamBuilder; +import teambuilder.model.TeamBuilder; +import teambuilder.model.UserPrefs; public class StorageManagerTest { @@ -24,7 +24,7 @@ public class StorageManagerTest { @BeforeEach public void setUp() { - JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(getTempFilePath("ab")); + JsonTeamBuilderStorage addressBookStorage = new JsonTeamBuilderStorage(getTempFilePath("ab")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(getTempFilePath("prefs")); storageManager = new StorageManager(addressBookStorage, userPrefsStorage); } @@ -54,10 +54,10 @@ public void addressBookReadSave() throws Exception { * {@link JsonAddressBookStorage} class. * More extensive testing of UserPref saving/reading is done in {@link JsonAddressBookStorageTest} class. */ - AddressBook original = getTypicalAddressBook(); + TeamBuilder original = getTypicalAddressBook(); storageManager.saveAddressBook(original); - ReadOnlyAddressBook retrieved = storageManager.readAddressBook().get(); - assertEquals(original, new AddressBook(retrieved)); + ReadOnlyTeamBuilder retrieved = storageManager.readAddressBook().get(); + assertEquals(original, new TeamBuilder(retrieved)); } @Test diff --git a/src/test/java/seedu/address/testutil/Assert.java b/src/test/java/teambuilder/testutil/Assert.java similarity index 97% rename from src/test/java/seedu/address/testutil/Assert.java rename to src/test/java/teambuilder/testutil/Assert.java index 9863093bd6e..b9fc6f19bb4 100644 --- a/src/test/java/seedu/address/testutil/Assert.java +++ b/src/test/java/teambuilder/testutil/Assert.java @@ -1,4 +1,4 @@ -package seedu.address.testutil; +package teambuilder.testutil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.function.Executable; diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/teambuilder/testutil/EditPersonDescriptorBuilder.java similarity index 64% rename from src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java rename to src/test/java/teambuilder/testutil/EditPersonDescriptorBuilder.java index 4584bd5044e..c02768b019a 100644 --- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java +++ b/src/test/java/teambuilder/testutil/EditPersonDescriptorBuilder.java @@ -1,16 +1,17 @@ -package seedu.address.testutil; +package teambuilder.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; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; /** * A utility class to help with building EditPersonDescriptor objects. @@ -36,7 +37,9 @@ public EditPersonDescriptorBuilder(Person person) { descriptor.setPhone(person.getPhone()); descriptor.setEmail(person.getEmail()); descriptor.setAddress(person.getAddress()); + descriptor.setMajor(person.getMajor()); descriptor.setTags(person.getTags()); + descriptor.setTeams(person.getTeams()); } /** @@ -51,7 +54,7 @@ public EditPersonDescriptorBuilder withName(String name) { * Sets the {@code Phone} of the {@code EditPersonDescriptor} that we are building. */ public EditPersonDescriptorBuilder withPhone(String phone) { - descriptor.setPhone(new Phone(phone)); + descriptor.setPhone(Phone.of(phone)); return this; } @@ -59,7 +62,7 @@ public EditPersonDescriptorBuilder withPhone(String phone) { * Sets the {@code Email} of the {@code EditPersonDescriptor} that we are building. */ public EditPersonDescriptorBuilder withEmail(String email) { - descriptor.setEmail(new Email(email)); + descriptor.setEmail(Email.of(email)); return this; } @@ -67,7 +70,15 @@ public EditPersonDescriptorBuilder withEmail(String email) { * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building. */ public EditPersonDescriptorBuilder withAddress(String address) { - descriptor.setAddress(new Address(address)); + descriptor.setAddress(Address.of(address)); + return this; + } + + /** + * Sets the {@code Major} of the {@code EditPersonDescriptor} that we are building. + */ + public EditPersonDescriptorBuilder withMajor(String major) { + descriptor.setMajor(Major.of(major)); return this; } @@ -81,6 +92,17 @@ public EditPersonDescriptorBuilder withTags(String... tags) { return this; } + /** + * Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor} + * that we are building. + */ + public EditPersonDescriptorBuilder withTeams(String... teams) { + Set tagSet = Stream.of(teams).map(Tag::new).collect(Collectors.toSet()); + descriptor.setTeams(tagSet); + return this; + } + //TODO: withTeams test + public EditPersonDescriptor build() { return descriptor; } diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/teambuilder/testutil/PersonBuilder.java similarity index 52% rename from src/test/java/seedu/address/testutil/PersonBuilder.java rename to src/test/java/teambuilder/testutil/PersonBuilder.java index 6be381d39ba..b229e4dc067 100644 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ b/src/test/java/teambuilder/testutil/PersonBuilder.java @@ -1,15 +1,16 @@ -package seedu.address.testutil; +package teambuilder.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; +import teambuilder.model.person.Address; +import teambuilder.model.person.Email; +import teambuilder.model.person.Major; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.person.Phone; +import teambuilder.model.tag.Tag; +import teambuilder.model.util.SampleDataUtil; /** * A utility class to help with building Person objects. @@ -20,22 +21,28 @@ public class PersonBuilder { 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"; + public static final String DEFAULT_MAJOR = "computer science"; private Name name; private Phone phone; private Email email; private Address address; + private Major major; private Set tags; + private Set teams; + /** * 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); + phone = Phone.of(DEFAULT_PHONE); + email = Email.of(DEFAULT_EMAIL); + address = Address.of(DEFAULT_ADDRESS); + major = Major.of(DEFAULT_MAJOR); tags = new HashSet<>(); + teams = new HashSet<>(); } /** @@ -46,7 +53,9 @@ public PersonBuilder(Person personToCopy) { phone = personToCopy.getPhone(); email = personToCopy.getEmail(); address = personToCopy.getAddress(); + major = personToCopy.getMajor(); tags = new HashSet<>(personToCopy.getTags()); + teams = new HashSet<>(personToCopy.getTeams()); } /** @@ -65,11 +74,27 @@ public PersonBuilder withTags(String ... tags) { return this; } + /** + * Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building. + */ + public PersonBuilder withTeams(String ... tags) { + this.teams = 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); + this.address = Address.of(address); + return this; + } + + /** + * Sets the {@code Major} of the {@code Major} that we are building. + */ + public PersonBuilder withMajor(String major) { + this.major = Major.of(major); return this; } @@ -77,7 +102,7 @@ public PersonBuilder withAddress(String address) { * Sets the {@code Phone} of the {@code Person} that we are building. */ public PersonBuilder withPhone(String phone) { - this.phone = new Phone(phone); + this.phone = Phone.of(phone); return this; } @@ -85,12 +110,27 @@ public PersonBuilder withPhone(String phone) { * Sets the {@code Email} of the {@code Person} that we are building. */ public PersonBuilder withEmail(String email) { - this.email = new Email(email); + this.email = Email.of(email); return this; } - public Person build() { - return new Person(name, phone, email, address, tags); + /** + * Sets the {@code Email} of the {@code Person} that we are building to be empty Email. + */ + public PersonBuilder withoutEmail() { + this.email = Email.getEmptyEmail(); + return this; } + /** + * Sets the {@code Phone} of the {@code Person} that we are building to be an emptyPhone. + */ + public PersonBuilder withoutPhone() { + this.phone = Phone.getEmptyPhone(); + return this; + } + + public Person build() { + return new Person(name, phone, email, address, major, tags, teams); + } } diff --git a/src/test/java/teambuilder/testutil/PersonUtil.java b/src/test/java/teambuilder/testutil/PersonUtil.java new file mode 100644 index 00000000000..35ec3e34570 --- /dev/null +++ b/src/test/java/teambuilder/testutil/PersonUtil.java @@ -0,0 +1,77 @@ +package teambuilder.testutil; + +import static teambuilder.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static teambuilder.logic.parser.CliSyntax.PREFIX_EMAIL; +import static teambuilder.logic.parser.CliSyntax.PREFIX_MAJOR; +import static teambuilder.logic.parser.CliSyntax.PREFIX_NAME; +import static teambuilder.logic.parser.CliSyntax.PREFIX_PHONE; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TAG; +import static teambuilder.logic.parser.CliSyntax.PREFIX_TEAM; + +import java.util.Set; + +import teambuilder.logic.commands.AddCommand; +import teambuilder.logic.commands.EditCommand.EditPersonDescriptor; +import teambuilder.model.person.Person; +import teambuilder.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().toString() + " "); + sb.append(PREFIX_EMAIL + person.getEmail().toString() + " "); + sb.append(PREFIX_ADDRESS + person.getAddress().toString() + " "); + sb.append(PREFIX_MAJOR + person.getMajor().toString() + " "); + person.getTags().stream().forEach( + s -> sb.append(PREFIX_TAG + s.tagName + " ") + ); + person.getTeams().stream().forEach( + s -> sb.append(PREFIX_TEAM + 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).append(" ")); + descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email).append(" ")); + descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address).append(" ")); + descriptor.getMajor().ifPresent(major -> sb.append(PREFIX_MAJOR).append(major).append(" ")); + if (descriptor.getTags().isPresent()) { + Set tags = descriptor.getTags().get(); + if (tags.isEmpty()) { + sb.append(PREFIX_TAG).append(" "); + } else { + tags.forEach(s -> sb.append(PREFIX_TAG).append(s.tagName).append(" ")); + } + } + if (descriptor.getTeams().isPresent()) { + Set teams = descriptor.getTeams().get(); + if (teams.isEmpty()) { + sb.append(PREFIX_TEAM).append(" "); + } else { + teams.forEach(s -> sb.append(PREFIX_TEAM).append(s.tagName).append(" ")); + } + } + return sb.toString(); + } +} diff --git a/src/test/java/seedu/address/testutil/SerializableTestClass.java b/src/test/java/teambuilder/testutil/SerializableTestClass.java similarity index 98% rename from src/test/java/seedu/address/testutil/SerializableTestClass.java rename to src/test/java/teambuilder/testutil/SerializableTestClass.java index f5a66340489..c05f5c06019 100644 --- a/src/test/java/seedu/address/testutil/SerializableTestClass.java +++ b/src/test/java/teambuilder/testutil/SerializableTestClass.java @@ -1,4 +1,4 @@ -package seedu.address.testutil; +package teambuilder.testutil; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/src/test/java/teambuilder/testutil/TeamBuilder.java b/src/test/java/teambuilder/testutil/TeamBuilder.java new file mode 100644 index 00000000000..795c92e9c82 --- /dev/null +++ b/src/test/java/teambuilder/testutil/TeamBuilder.java @@ -0,0 +1,88 @@ +package teambuilder.testutil; + +import java.util.HashSet; +import java.util.Set; + +import teambuilder.model.person.Name; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; +import teambuilder.model.util.SampleDataUtil; + +/** + * A utility class to help with building Team objects. + */ +public class TeamBuilder { + + public static final String DEFAULT_NAME = "NUS"; + + public static final String DEFAULT_DESC = "description"; + + private TeamName name; + + private Desc desc; + + private Set skillTags; + + private Set members; + + /** + * Creates a {@code TeamBuilder} with the default details. + */ + public TeamBuilder() { + name = new TeamName(DEFAULT_NAME); + desc = new Desc(DEFAULT_DESC); + skillTags = new HashSet<>(); + members = new HashSet<>(); + } + + /** + * Initializes the TeamBuilder with the data of {@code teamToCopy}. + */ + public TeamBuilder(Team teamToCopy) { + name = teamToCopy.getName(); + desc = teamToCopy.getDesc(); + skillTags = new HashSet<>(teamToCopy.getTags()); + members = new HashSet<>(teamToCopy.getMembers()); + } + + /** + * Sets the {@code name} of the {@code Team} that we are building. + */ + public TeamBuilder withName(String name) { + this.name = new TeamName(name); + return this; + } + + /** + * Sets the {@code desc} of the {@code Team} that we are building. + */ + public TeamBuilder withDesc(String desc) { + this.desc = new Desc(desc); + return this; + } + + /** + * Parses the {@code skillTags} into a {@code Set} and set it + * to the {@code Team} that we are building. + */ + public TeamBuilder withSkillTags(String ... skillTags) { + this.skillTags = SampleDataUtil.getTagSet(skillTags); + return this; + } + + /** + * Parses the {@code members} into a {@code Set} and set it + * to the {@code Team} that we are building. + */ + public TeamBuilder withMembers(String ... members) { + this.members = SampleDataUtil.getNameSet(members); + return this; + } + + public Team build() { + return new Team(name, desc, skillTags); + } + +} diff --git a/src/test/java/seedu/address/testutil/AddressBookBuilder.java b/src/test/java/teambuilder/testutil/TeamBuilderMaker.java similarity index 52% rename from src/test/java/seedu/address/testutil/AddressBookBuilder.java rename to src/test/java/teambuilder/testutil/TeamBuilderMaker.java index d53799fd110..dd5310bcce9 100644 --- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java +++ b/src/test/java/teambuilder/testutil/TeamBuilderMaker.java @@ -1,34 +1,34 @@ -package seedu.address.testutil; +package teambuilder.testutil; -import seedu.address.model.AddressBook; -import seedu.address.model.person.Person; +import teambuilder.model.TeamBuilder; +import teambuilder.model.person.Person; /** * A utility class to help with building Addressbook objects. * Example usage:
* {@code AddressBook ab = new AddressBookBuilder().withPerson("John", "Doe").build();} */ -public class AddressBookBuilder { +public class TeamBuilderMaker { - private AddressBook addressBook; + private TeamBuilder addressBook; - public AddressBookBuilder() { - addressBook = new AddressBook(); + public TeamBuilderMaker() { + addressBook = new TeamBuilder(); } - public AddressBookBuilder(AddressBook addressBook) { + public TeamBuilderMaker(TeamBuilder addressBook) { this.addressBook = addressBook; } /** * Adds a new {@code Person} to the {@code AddressBook} that we are building. */ - public AddressBookBuilder withPerson(Person person) { + public TeamBuilderMaker withPerson(Person person) { addressBook.addPerson(person); return this; } - public AddressBook build() { + public TeamBuilder build() { return addressBook; } } diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/teambuilder/testutil/TestUtil.java similarity index 77% rename from src/test/java/seedu/address/testutil/TestUtil.java rename to src/test/java/teambuilder/testutil/TestUtil.java index 896d103eb0b..6232c39246c 100644 --- a/src/test/java/seedu/address/testutil/TestUtil.java +++ b/src/test/java/teambuilder/testutil/TestUtil.java @@ -1,13 +1,13 @@ -package seedu.address.testutil; +package teambuilder.testutil; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import seedu.address.commons.core.index.Index; -import seedu.address.model.Model; -import seedu.address.model.person.Person; +import teambuilder.commons.core.index.Index; +import teambuilder.model.Model; +import teambuilder.model.person.Person; /** * A utility class for test cases. @@ -36,20 +36,20 @@ public static Path getFilePathInSandboxFolder(String fileName) { * Returns the middle index of the person in the {@code model}'s person list. */ public static Index getMidIndex(Model model) { - return Index.fromOneBased(model.getFilteredPersonList().size() / 2); + return Index.fromOneBased(model.getSortedPersonList().size() / 2); } /** * Returns the last index of the person in the {@code model}'s person list. */ public static Index getLastIndex(Model model) { - return Index.fromOneBased(model.getFilteredPersonList().size()); + return Index.fromOneBased(model.getSortedPersonList().size()); } /** * Returns the person in the {@code model}'s person list at {@code index}. */ public static Person getPerson(Model model, Index index) { - return model.getFilteredPersonList().get(index.getZeroBased()); + return model.getSortedPersonList().get(index.getZeroBased()); } } diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/teambuilder/testutil/TypicalIndexes.java similarity index 81% rename from src/test/java/seedu/address/testutil/TypicalIndexes.java rename to src/test/java/teambuilder/testutil/TypicalIndexes.java index 1e613937657..317adfa80e4 100644 --- a/src/test/java/seedu/address/testutil/TypicalIndexes.java +++ b/src/test/java/teambuilder/testutil/TypicalIndexes.java @@ -1,6 +1,6 @@ -package seedu.address.testutil; +package teambuilder.testutil; -import seedu.address.commons.core.index.Index; +import teambuilder.commons.core.index.Index; /** * A utility class containing a list of {@code Index} objects to be used in tests. diff --git a/src/test/java/teambuilder/testutil/TypicalPersons.java b/src/test/java/teambuilder/testutil/TypicalPersons.java new file mode 100644 index 00000000000..c9a2cf9c49e --- /dev/null +++ b/src/test/java/teambuilder/testutil/TypicalPersons.java @@ -0,0 +1,110 @@ +package teambuilder.testutil; + +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_MAJOR_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_MAJOR_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_NAME_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_AMY; +import static teambuilder.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static teambuilder.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import teambuilder.model.TeamBuilder; +import teambuilder.model.person.Name; +import teambuilder.model.person.Person; +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +/** + * 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") + .withMajor("computer science").withTags("Python").build(); + public static final Person BENSON = new PersonBuilder().withName("Benson Meier") + .withAddress("311, Clementi Ave 2, #02-25").withEmail("johnd@example.com").withPhone("98765432") + .withMajor("computer science").withTags("C", "PgSQL").withTeams("TeamA").build(); + public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563") + .withEmail("heinz@example.com").withAddress("wall street").withMajor("computer science").withTeams("TeamA") + .build(); + public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533") + .withEmail("cornelia@example.com").withAddress("10th street").withMajor("computer science") + .withTags("React Native").withTeams("TeamB").build(); + public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224") + .withEmail("werner@example.com").withAddress("michegan ave").withMajor("computer science") + .withTeams("TeamB").build(); + public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427") + .withEmail("lydia@example.com").withAddress("little tokyo").withMajor("computer science").withTeams("TeamC") + .build(); + public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442") + .withEmail("anna@example.com").withAddress("4th street").withMajor("computer science").build(); + + // Manually added + public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424") + .withEmail("stefan@example.com").withAddress("little india").withMajor("computer science").build(); + public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("8482131") + .withEmail("hans@example.com").withAddress("chicago ave").withMajor("computer science").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).withMajor(VALID_MAJOR_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).withMajor(VALID_MAJOR_BOB) + .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); + + public static final List IN_TEAM_A = Arrays.asList(BENSON.getName(), CARL.getName()); + + public static final List IN_TEAM_B = Arrays.asList(DANIEL.getName(), ELLE.getName()); + + public static final List IN_TEAM_C = Arrays.asList(FIONA.getName()); + + public static final Team TEAM_A = new Team( + new Team(new TeamName("TeamA"), new Desc("Project group TeamA"), new HashSet<>()), + new HashSet(IN_TEAM_A)); + public static final Team TEAM_B = new Team(new Team(new TeamName("TeamB"), new Desc("Project group TeamB"), + new HashSet(Arrays.asList(new Tag("Java"), new Tag("ReactNative")))), new HashSet<>(IN_TEAM_B)); + public static final Team TEAM_C = new Team(new Team(new TeamName("TeamC"), new Desc("Project group TeamC"), + new HashSet(Arrays.asList(new Tag("PgSQL"), new Tag("C")))), new HashSet<>(IN_TEAM_C)); + + 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 TeamBuilder getTypicalAddressBook() { + TeamBuilder ab = new TeamBuilder(); + + for (Team team : getTypicalTeams()) { + ab.addTeam(team); + } + 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)); + } + + public static List getTypicalTeams() { + return new ArrayList<>(Arrays.asList(TEAM_A, TEAM_B, TEAM_C)); + } +} diff --git a/src/test/java/teambuilder/testutil/TypicalTeams.java b/src/test/java/teambuilder/testutil/TypicalTeams.java new file mode 100644 index 00000000000..668271cd6e2 --- /dev/null +++ b/src/test/java/teambuilder/testutil/TypicalTeams.java @@ -0,0 +1,21 @@ +package teambuilder.testutil; + +import java.util.Arrays; +import java.util.HashSet; + +import teambuilder.model.tag.Tag; +import teambuilder.model.team.Desc; +import teambuilder.model.team.Team; +import teambuilder.model.team.TeamName; + +/** + * Sample teams for testing + */ +public class TypicalTeams { + public static final Team TEAM_A = new Team(new TeamName("TeamA"), new Desc("This is Team A"), + new HashSet(Arrays.asList(new Tag("Python"), new Tag("ReactNative")))); + public static final Team TEAM_B = new Team(new TeamName("TeamB"), new Desc("This is Team B"), + new HashSet(Arrays.asList(new Tag("Java"), new Tag("ReactNative")))); + public static final Team TEAM_C = new Team(new TeamName("TeamC"), new Desc("This is Team C"), + new HashSet(Arrays.asList(new Tag("PgSQL"), new Tag("C")))); +} diff --git a/src/test/java/seedu/address/ui/TestFxmlObject.java b/src/test/java/teambuilder/ui/TestFxmlObject.java similarity index 96% rename from src/test/java/seedu/address/ui/TestFxmlObject.java rename to src/test/java/teambuilder/ui/TestFxmlObject.java index 5ecd82656f2..42f42286f4f 100644 --- a/src/test/java/seedu/address/ui/TestFxmlObject.java +++ b/src/test/java/teambuilder/ui/TestFxmlObject.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package teambuilder.ui; import javafx.beans.DefaultProperty; diff --git a/src/test/java/seedu/address/ui/UiPartTest.java b/src/test/java/teambuilder/ui/UiPartTest.java similarity index 97% rename from src/test/java/seedu/address/ui/UiPartTest.java rename to src/test/java/teambuilder/ui/UiPartTest.java index 33d82d911b8..cfed9f1e1b3 100644 --- a/src/test/java/seedu/address/ui/UiPartTest.java +++ b/src/test/java/teambuilder/ui/UiPartTest.java @@ -1,8 +1,8 @@ -package seedu.address.ui; +package teambuilder.ui; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static seedu.address.testutil.Assert.assertThrows; +import static teambuilder.testutil.Assert.assertThrows; import java.net.URL; import java.nio.file.Path; @@ -11,7 +11,7 @@ import org.junit.jupiter.api.io.TempDir; import javafx.fxml.FXML; -import seedu.address.MainApp; +import teambuilder.MainApp; public class UiPartTest { diff --git a/src/test/resources/view/UiPartTest/validFile.fxml b/src/test/resources/view/UiPartTest/validFile.fxml index bab836af0db..0e0729d2c78 100644 --- a/src/test/resources/view/UiPartTest/validFile.fxml +++ b/src/test/resources/view/UiPartTest/validFile.fxml @@ -1,4 +1,4 @@ - + Hello World! diff --git a/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml b/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml index 151e09ce926..ba12f4ce9f1 100644 --- a/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml +++ b/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml @@ -1,6 +1,6 @@ - Hello World!