diff --git a/.gitignore b/.gitignore index 71c9194e8bd..b3235edc0fc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ src/main/resources/docs/ /out/ /*.iml +# VSCode files +/bin/ +/.vscode/ + # Storage/log files /data/ /config.json @@ -20,3 +24,6 @@ src/test/data/sandbox/ # MacOS custom attributes files created by Finder .DS_Store docs/_site/ + +# Ruby config files for local Jekyll server +docs/.ruby-version diff --git a/README.md b/README.md index 13f5c77403f..d253dc82443 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,23 @@ -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) +[![Java CI](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml/badge.svg)](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml) +[![codecov](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp/branch/master/graph/badge.svg?token=K13DUI69HX)](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp) + +# WorkBook (WB) ![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. +* WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications. + +* WorkBook (WB) 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, WB can get your internship management tasks done faster than traditional GUI apps. + +## Usage + +* Manage your internship applications for easier tracking! + + +## Acknowledgements +Libraries used: [JavaFX](https://openjfx.io), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5).
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+User Guide: Table of Contents with bullet points removed is reused from [@ianyong's team in 2020](https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7). +Reused [code](https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110) from CS2103T-T10-4 to parse optional arguments. + + diff --git a/build.gradle b/build.gradle index 108397716bd..348420ace46 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id 'jacoco' } -mainClassName = 'seedu.address.Main' +mainClassName = 'seedu.workbook.Main' sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -16,6 +16,10 @@ repositories { maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } +run { + enableAssertions = true +} + checkstyle { toolVersion = '10.2' } @@ -66,7 +70,7 @@ dependencies { } shadowJar { - archiveFileName = 'addressbook.jar' + archiveFileName = 'workbook.jar' } defaultTasks 'clean', 'test' diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index d618671b832..261d8e91a42 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -10,6 +10,13 @@ + + + + + + + diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1c9514e966a..a9caf452c05 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -9,51 +9,51 @@ You can reach us at the email `seer[at]comp.nus.edu.sg` ## Project team -### John Doe +### Daryl Chua - + -[[homepage](http://www.comp.nus.edu.sg/~damithch)] -[[github](https://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](https://github.com/rylzxc)] +[[portfolio](team/rylzxc.md)] -* Role: Project Advisor +* Role: Team Lead +* Responsibilities: Overall project coordination, deliverables and deadlines -### Jane Doe +### Adee Aryaa - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/adeearyaa)] +[[portfolio](team/adeearyaa.md)] -* Role: Team Lead -* Responsibilities: UI +* Role: Code Quality +* Responsibilities: Ensures that Code follows a common style and achieves maximum readability -### Johnny Doe +### Glemen Neo - + -[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)] +[[github](http://github.com/glemenneo)] [[portfolio](team/glemenneo.md)] -* Role: Developer -* Responsibilities: Data +* Role: UI/UX +* Responsibilities: Designing and implementing UI elements for new features, improving user experience by redesigning existing UI elements. -### Jean Doe +### Jacob Kwan - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/jacobkwan)] +[[portfolio](team/jacobkwan.md)] -* Role: Developer -* Responsibilities: Dev Ops + Threading +* Role: Integration +* Responsibilities: Versioning of codebase/releases and overall maintenance of the repository. -### James Doe +### Tien Yu - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/tienyu2000)] +[[portfolio](team/tienyu2000.md)] -* Role: Developer -* Responsibilities: UI +* Role: Documentation +* Responsibilities: JavaDocs to generate API documentation in HTML format diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 46eae8ee565..4277f9196e2 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -9,7 +9,11 @@ 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).
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org). +* User Guide: Table of Contents with bullet points removed is reused from [@ianyong's team in 2020](https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7). +* Reused [code](https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110) from CS2103T-T10-4 to parse optional arguments. +* Reused [code](https://github.com/se-edu/addressbook-level4/blob/master/src/main/java/seedu/address/model/VersionedAddressBook.java) from AddressBook-Level4. -------------------------------------------------------------------------------------------------------------------- @@ -73,7 +77,7 @@ The **API** of this component is specified in [`Ui.java`](https://github.com/se- ![Structure of the UI Component](images/UiClassDiagram.png) -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `InternshipListPanel`, `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) @@ -82,7 +86,7 @@ The `UI` component, * executes user commands using the `Logic` component. * listens for changes to `Model` data so that the UI can be updated with the modified data. * keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. +* depends on some classes in the `Model` component, as it displays `Internship` object residing in the `Model`. ### Logic component @@ -93,9 +97,9 @@ 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. When `Logic` is called upon to execute a command, it uses the `WorkBookParser` class to parse the user command. 1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`. -1. The command can communicate with the `Model` when it is executed (e.g. to add a person). +1. The command can communicate with the `Model` when it is executed (e.g. to add an internship). 1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call. @@ -110,7 +114,7 @@ Here are the other classes in `Logic` (omitted from the class diagram above) tha How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. +* When called upon to parse a user command, the `WorkBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `WorkBookParser` returns back as a `Command` object. * All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. ### Model component @@ -121,12 +125,12 @@ How the parsing works: The `Model` component, -* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. +* stores the work book data i.e., all `Internship` objects (which are contained in a `UniqueInternshipList` object). +* stores the currently 'selected' `Internship` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. * stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. * does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) -
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `WorkBook`, which `Internship` references. This allows `WorkBook` to only require one `Tag` object per unique tag, instead of each `Internship` needing their own `Tag` objects.
@@ -140,13 +144,13 @@ The `Model` component, The `Storage` component, -* can save both address book 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). +* can save both work book data and user preference data in json format, and read them back into corresponding objects. +* inherits from both `WorkBookStorage` 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 `seedu.workbook.commons` package. -------------------------------------------------------------------------------------------------------------------- @@ -154,41 +158,110 @@ 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 feature -#### Proposed Implementation +#### Implementation -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: +The add feature is facilitated by `AddCommand` and `AddCommandParser` classes. The `parse` method in `AddCommandParser` +checks if mandatory fields are first present. +If all are present, the new `Internship` will be added to the `UniqueInternshipList` in a sorted-by-date order. -* `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. +Below shows the class diagram of adding a new internship application into the list which automatically sorts using `SortedList`. +This takes place in the `UniqueInternshipList` as shown in the diagram below. +Some `logic` and `model` details are omitted as they are already explained in the [Architecture section](#architecture) above. -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. + + +#### Design considerations: + +**Aspect: `Stage` field:** + +* **Alternative 1 (current choice):** Not restricting to enums, (proposed: warn if input does not match general stages) + * Pros: Flexibility for user by allowing unique stages from different companies which we did not prepare for to be added. + * Cons: Will not have stage-specific tips that have been gathered for more general interview stages. + +* **Alternative 2:** Restricting to enums + * Pros: Prevent the need for user to edit previous command in the event of a typo, + * Cons: Flexibility is heavily restricted, user may encounter stages that we may not have prepared for, which may annoy the user if the user is not allowed to add the stage into the internship tracker. + +**Aspect: `DateTime` field:** + +* **Alternative 1 (current choice):** Not modularizing Time and Date + * Pros: Most stages have a date and time associated with it. Making one of the two optional takes extra effort for something that uncommon. Can be left to later stages of development. + * Cons: May not be prepared for stages without date and/or time, therefore not making the tracker flexible enough. + +* **Alternative 2:** Modularizing Time and Date + * Pros: Some stages that we may not have prepared for may omit date or time, encouraging flexibility of the tracker. + * Cons: Effort required is too high in the early stages of development whereby a functional product is prioritized. + + +### Find feature + +#### Implementation + +The find feature is facilitated by `FindCommand` and `FindCommandParser` classes. The `parse` method in `FindCommandParser` +checks if mandatory fields are first present. +If all are present, the new `UniqueInternshipList` will contain the internships that contain the keywords the user's have entered. + +Below shows the class diagram of filtering existing internship applications using keywords that are input by the user. The list will only contain internships that pass the predicate. This list automatically sorts using `SortedList`. +This takes place in the `UniqueInternshipList` as shown in the diagram below. +Some `logic` and `model` details are omitted as they are already explained in the [Architecture section](#architecture) above. + + + +#### Design considerations: + +**Aspect: Not allowing user's to find internships using more than one attribute:** + +* **Alternative 1 (current choice):** Only allowing keywords from one attribute, (an error message displayed if user inputs keywords corresponding to more than one attribute) + * Pros: Allows user to be able to filter internship applications by one attribute of their interest(e.g. Company, Role or Stage). + If user was allowed to filter by more than one attribute it will result in them being able to see internships that did not match the other attributes they have input. + + * Cons: User will not be able to filter their internship application listings by more than attribute. + +* **Alternative 2:** Allowing user to filter internships by more than one attribute + * Pros: Allows user to filter and find internships using keywords belonging to multiple attributes. + * Cons: Will result in the user being able to see internships that did not contain keywords of one of the attributes but contained another keyword of another attribute. This is possibly unwanted behaviour. + + +### Undo/Redo feature + +The undo feature allows for users to revert back to their previous undone state in the Workbook. +The redo feature complements the undo feature by allowing users to restore to its previous changed state following an undo command. + +#### Implementation + +The undo/redo mechanism is facilitated by `VersionedWorkBook`. It extends `WorkBook` with an undo/redo history, stored internally as an `workBookStateList` and `currentStatePointer`. Additionally, it implements the following operations: + +* `VersionedWorkBook#commit()` — Saves the current work book state in its history. +* `VersionedWorkBook#undo()` — Restores the previous work book state from its history. +* `VersionedWorkBook#redo()` — Restores a previously undone work book state from its history. + +These operations are exposed in the `Model` interface as `Model#commitWorkBook()`, `Model#undoWorkBook()` and `Model#redoWorkBook()` 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 `VersionedWorkBook` will be initialized with the initial work book state, and the `currentStatePointer` pointing to that single work book state. ![UndoRedoState0](images/UndoRedoState0.png) -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. +Step 2. The user executes `delete 5` command to delete the 5th internship in the work book. The `delete` command calls `Model#commitWorkBook()`, causing the modified state of the work book after the `delete 5` command executes to be saved in the `workBookStateList`, and the `currentStatePointer` is shifted to the newly inserted work book state. ![UndoRedoState1](images/UndoRedoState1.png) -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 c/COMPANY …​` to add a new internship. The `add` command also calls `Model#commitWorkBook()`, causing another modified work book state to be saved into the `workBookStateList`. ![UndoRedoState2](images/UndoRedoState2.png) -
: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#commitWorkBook()`, so the work book state will not be saved into the `workBookStateList`.
-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 internship was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoWorkBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous work book state, and restores the work book to that state. ![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 +
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial WorkBook state, then there are no previous WorkBook states to restore. The `undo` command uses `Model#canUndoWorkBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
@@ -201,20 +274,30 @@ The following sequence diagram shows how the undo operation works:
-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. +Step 5. The user now decides that undoing the added internship was a mistake, and decides to redo that action by executing the `redo` command. The `redo` command will call `Model#redoWorkBook()`, which will shift the `currentStatePointer` once to the right, pointing it to the previous undone work book state, and restores the work book to that state. + +![UndoRedoState4](images/UndoRedoState4.png) -
: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 `currentStatePointer` is at index `workBookStateList.size() - 1`, pointing to the latest work book state, then there are no undone WorkBook states to restore. The `redo` command uses `Model#canRedoWorkBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
-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. +The following sequence diagram shows how the redo operation works: -![UndoRedoState4](images/UndoRedoState4.png) +![RedoSequenceDiagram](images/RedoSequenceDiagram.png) + +
:information_source: **Note:** The lifeline for `RedoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern desktop applications follow. +
+ +Step 6. The user then decides to execute the command `list`. Commands that do not modify the work book, such as `list`, will usually not call `Model#commitWorkBook()`, `Model#undoWorkBook()` or `Model#redoWorkBook()`. Thus, the `workBookStateList` remains unchanged. ![UndoRedoState5](images/UndoRedoState5.png) +Step 7. The user executes `clear`, which calls `Model#commitWorkBook()`. Since the `currentStatePointer` is not pointing at the end of the `workBookStateList`, all work book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add c/COMPANY …​` command. This is the behavior that most modern desktop applications follow. + +![UndoRedoState6](images/UndoRedoState6.png) + The following activity diagram summarizes what happens when a user executes a new command: @@ -223,15 +306,82 @@ The following activity diagram summarizes what happens when a user executes a ne **Aspect: How undo & redo executes:** -* **Alternative 1 (current choice):** Saves the entire address book. +* **Alternative 1 (current choice):** Saves the entire work book. * Pros: Easy to implement. * Cons: May have performance issues in terms of memory usage. * **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). + * Pros: Will use less memory (e.g. for `delete`, just save the internship being deleted). * Cons: We must ensure that the implementation of each individual command are correct. +### Help window feature + +The help window has been redesigned to show all the commands supported by WB as well as examples of how to use the commands. This is to enable ease of use as users can quickly reference commands from the help window instead of having to open and refer to the UG. + +#### Implementation + +The help window is implemented in the `HelpWindow` class. The `HelpUtil` class stores all the headers and examples `String`s for the commands in a two `HashMap`s. The help window will retrieve the list of `Command`s and then builds a `HelpCard` for each command and adds it into the `GridPane` to display in the `HelpWindow`. The `HelpCard` retrieves the respective header and example `String`s using the `getCommandHeader` and `getCommandExample` methods from `HelpUtil` and shows it using two `Label`s. + +### Tips feature + +The tips feature shows curated tips for internship applications for specific application stages in order to help the user prepare for their certain deliverables, interviews and tests. The tips are currently only curated for common stages of internship applications due to the feasibility constraints. + +#### Implementation + +The tips feature is implemented in the `Model` component inside the `StageUtil` class. The list of supported stages is stored inside as a `List`. The tips are stored in a `HashMap` that maps each `Stage` object to their respective `List` of tips. The `getStageSpecificTips()` method will retrieve the list of tips for a supported stage as a `List`. + +The tips are then stored and shown inside a `TipsCard` object that extends from `UiPart` and consists of one `Hbox` housing 2 `Hbox`s with each inner `Hbox` containing a `Label`. The first `Label` shows the index while the second `Label` shows the Tip itself. + +The tips are show to the user in one of two ways depending on the UI layout. + +##### Narrow UI implementation +In the narrow UI layout, the tips can be accessed through a `tipsButton` which has a light bulb icon on the `NarrowInternshipCard` which will open the `TipsWindow`. The `TipsWindow` is a member of every `NarrowInternshipCard` object and is created when the constructor is called. + +The light bulb button will only appear if the internship application is at a supported stage, The implementation of this is through the `hasNoTips()` method from the `Stage` class that returns a boolean `hasNoTips` depending on whether the stage of the application has tips. + +If the application stage has tips and the button is pressed, the `TipsWindow` UI component of the `InternshipCard` will have its `GridPane` populated with `TipsCard` vertically after retrieving the tips using the `getStageSpecificTips()` method and building the `TipsCard` for each tip. The tips window is then opened. + +If the application stage does not have tips, the tips button will be set to hidden and the `TipsWindow` will not be populated and will be inaccessible. + +For more details on the UI implementation, please refer to the [Responsive UI](#responsive-ui-feature) section of the DG. + +##### Wide UI implementation +In the wide UI layout, the tips are shown to the right of the internship list using the `TipsPanel` that extends `UiPart`. A listener is implemented in the `WideInternshipListPanel` to check which `NarrowInternshipCard` is currently selected. + + +If the internship card currently selected is at a supported stage, the `TipsPanel` will have its `GridPane` populated with `TipCard`s vertically after retrieving the tips using the `getStageSpecificStips()` method and building the `TipCard` for each tip. + +If the internship card currently selected is not at a supported stage, the default `TipsPanel` will be shown which only has `Label` message telling the user that there are no tips for the stage yet. + +For more detail on the UI implementation, please refer to the [Responsive UI](#responsive-ui-feature) section of the DG. + +### Responsive UI feature + +Workbook had two UI layouts depending on the size of the `MainWindow`. A narrow UI layout is shown when the window is resized narrower than the 1000 pixel breakpoint and a wide UI layout is shown when the window is resized wider than the 1000 pixel breakpoint. This is to improve readability and usability on narrow and wide screens. + +#### Implementation + +The implementation starts at the `MainWindow` class. The class has two UI layouts as members, the `WideInternshipListPanel` class and the `NarrowInternshipListPanel` class that both extend `UiPart`. The two UI layout objects are instantiated on calling the constructer of `MainWindow` and are populated with the internship applications on instantiation. This is to enable fast switching between the two layouts. + +The `setWidthEventHandlers()` listener will listen to the current window width. Whenever the window width passes the breakpoint, the `internshipListPanelPlaceholder` is cleared and populated with either the `WideInternshipListPanel` or the `NarrowInternshipListPanel` depending on the window width. + +##### Narrow UI + +The narrow UI layout uses the `NarrowInternshipListPanel` and populates its `ListView` with the `InternshipCard` that extends `UiPart`. It has a tips button that can open the tips window. Other than the tips button, the implementation is very similar to AB3 with minor styling changes. + +For more details on the implementation of the tips button and tips window, refer to the [Tips section](#tips-feature) of the DG. + +##### Wide UI +The wide UI layout uses the `WideInternshipListPanel` and populates its `ListView` with the `NarrowInternshipCard` that extends `UiPart`. It differs from the `InternshipCard` in that it does not have the tips button. The implementation is very similar to the original `InternshipCard` from AB3 with minor styling changes. + +The `WideInternshipListPanel` has a `TipsPanel` beside the `ListView` that extends `UiPart`. The `TipsPanel` is contained inside a `HBox` `tipsPanelContainer` which is a member of the `WideInternshipListPanel`. + +A listener `setInternshipSelectedEventHandlers()` is implemented in the `WideInternshipListPanel` class that listens to to which `NarrowInternshipCard` is currently selected. It will call the `tipPanelBuilder()` method which takes in a `Stage` and creates a `TipsPanel` object and populates it with tips. + +For more details on the implementation of the tips button, tips window and tips panel, refer to the [Tips section](#tips-feature) of the DG. + + _{more aspects and alternatives to be added}_ ### \[Proposed\] Data archiving @@ -257,71 +407,223 @@ _{Explain here how the data archiving feature will be implemented}_ **Target user profile**: -* has a need to manage a significant number of contacts +* is a Computing student +* is looking and applying for internships +* likes to organize his/her data in one place * 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**: This app aims to be a unified platform that helps the user manage all their internship applications ### 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…​ | +|----------|-----------------------------------------------|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| +| `* * *` | student | add an internship company and role that I have applied to | keep track of which company and which roles I have applied for, especially when I have many applications | +| `* * *` | student | update an internship position that I have applied to | keep the tracker updated on the current state of my internship application | +| `* * *` | student | add an interview date and time to an internship application | track when my interview for that particular internship application is coming up | +| `* * *` | student | view the list of commands for use | familiarize myself with them and increase efficiency when performing operations on the application | +| `* * *` | student | keep track of the stage of my application | know which stages I am at for each application and thereafter what to prepare for it | +| `* * *` | student | delete an internship that I am not interested in anymore | get rid of internship applications that are not relevant to me anymore | +| `* * *` | forgetful student | sort the list of internship applications by dates | see and remember which interviews are upcoming to better prepare for them in case I have forgotten about them | +| `* * *` | student who got rejected by all the companies | clear the list of internship applications | I can start anew | +| `* * *` | student | add an expiry date and time to an application that is in the “Online Assessment” stage | keep track of when I have to complete the Online Assessment by | +| `* * *` | student who constantly changes my mind | redo an undone command | revert back the changes I had originally made | +| `* *` | easily confused student | prevent myself from adding the same internship application twice | I don't get distracted by duplicate internships | +| `* *` | forgetful student | easily access tips specific to each application based on the current stage | quickly see a list of things to prepare for an upcoming interview or deadline | +| `* *` | student | filter my internship applications according to position | view all my internship applications for that particular position that I am interested in | +| `* *` | student preparing for technical interviews | conveniently do practice questions | be better prepared for my technical interviews | +| `* *` | broke student | sort the internships based on pay | determine which applications are more worth it in this current economic state | +| `*` | student | rank all my internship applications | decide which applications that I have to focus on more | +| `*` | student | move an existing application to the "Rejection" stage and provide a reason why I got rejected | keep track of common trends or reasons for my failed applications | +| `*` | less experienced student | view some helpful resources | understand the hiring process and tech landscapes better | +| `*` | anxious student | switch to a calender view | easily see all my upcoming interviews/OAs/expiring offers | +| `*` | student | create a todo list for each internship entry | keep track of what I've done and what I've yet to do to prepare | -*{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 `WorkBook` and the **Actor** is the `user`, unless specified otherwise) + +**Use case: UC01 - Add an internship application** + +**Main Success Scenario (MSS)** + +1. User requests to add an internship. +2. WorkBook adds the internship. +3. WorkBook displays internship addition is successful. + + Use case ends. + +**Extensions** + +* 1a. The internship already exists. + + * 1a1. WorkBook shows an error message. + + Use case ends. + +* 1b. The format of given command is invalid. + * 1b1. WorkBook shows an error message. + + Use case ends. + +
+**Use case: UC02 - Delete an internship application** + +**Main Success Scenario (MSS)** -**Use case: Delete a person** +1. User requests to delete an internship. +2. WorkBook deletes the internship. +3. WorkBook displays list of internships remaining when successful. -**MSS** + Use case ends. + +**Extensions** -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 +* 1a. The list is empty. Use case ends. +* 1b. The given index is invalid. + + * 1b1. WorkBook shows an error message. + + Use case ends. + +
+**Use case: UC03 - Edit an internship application** + +**Main Success Scenario (MSS)** + +1. User requests to edit an internship. +2. WorkBook edits the internship. +3. WorkBook displays list of internships when successful. + + Use case ends. + +**Extensions** + +* 1a. The list is empty. + + * 1a1. WorkBook shows an error message. + + Use case ends. + +* 1b. The given field is invalid. + + * 1b1. WorkBook shows an error message. + + Use case ends. + +* 1c. The edited internship is identical to one in the list. + + * 1c1. WorkBook shows an error message. + + Use case ends. + +
+**Use case: UC04 - Undo a command** + +**Main Success Scenario (MSS)** + +1. User requests to undo the latest command they have executed. +2. Workbook reverts any changes made by the command and displays the previous state of the list of internship applications. + + Use case ends. + **Extensions** -* 2a. The list is empty. +* 1a. There is no previous command executed and the list is empty. - Use case ends. + * 1a1. WorkBook displays an error message that no previous command has been entered. -* 3a. The given index is invalid. + Use case ends. + +
+**Use case: UC05 - Redo a command** - * 3a1. AddressBook shows an error message. +**Main Success Scenario (MSS)** - Use case resumes at step 2. +1. User requests to redo the latest command they have undone. +2. Workbook reverts any changes made by the undo command and displays the previous state of the list of internship applications. -*{More to be added}* + Use case ends. + +**Extensions** + +* 1a. There is no previous command executed and the list is empty. + + * 1a1. WorkBook displays an error message that no commands can be redone. + + Use case ends. + +
+**Use case: UC06 - Clear list of internship applications** + +**Main Success Scenario (MSS)** + +1. User requests to clear list. +2. List is cleared. + + Use case ends. + +**Extensions** + +* 1a. The list is empty. + + * 1a1. WorkBook shows an error message. + + Use case ends. + +
+**Use case: UC07 - Display help message** + +**Main Success Scenario (MSS)** + +1. User requests for help. +2. Help message is shown. + + Use case ends. + +
+**Use case: UC08 - Exit application** + +**Main Success Scenario (MSS)** + +1. User requests to exit program. +2. WorkBook exits and closes. + + Use case ends. + +
+**Use case: UC09 - View preparatory tips based on internship stage** + +1. User requests to view preparatory tips. +2. User chooses internship stage to view preparatory tips for. +3. The preparatory tips for the internship stage is shown to the user. + + Use case ends. ### Non-Functional Requirements 1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -3. 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}* +2. Should have a startup time of at most 1 second. +3. Should be able to hold up to 200 internship applications without any noticeable sluggishness in performance for typical usage. +4. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +5. Data should be persisted locally and be in a human-readable format, for e.g `json`. +6. User interface and documentation should be intuitive enough so that new users can add an internship application within 15 minutes of installation. ### Glossary * **Mainstream OS**: Windows, Linux, Unix, OS-X -* **Private contact detail**: A contact detail that is not meant to be shared with others +* **OA/Online Assessment**: A common stage in a Software Engineering related internship application, where applicants are required to solve several theory and/or algorithmic questions under a timed and controlled environment + -------------------------------------------------------------------------------------------------------------------- @@ -340,7 +642,7 @@ testers are expected to do more *exploratory* testing. 1. Download the jar file and copy into an empty folder - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. + 1. Double-click the jar file Expected: Shows the GUI with a set of sample internship applications. The window size may not be optimum. 1. Saving window preferences @@ -349,29 +651,40 @@ testers are expected to do more *exploratory* testing. 1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained. -1. _{ more test cases …​ }_ +### Deleting an internship application -### Deleting a person - -1. Deleting a person while all persons are being shown +1. Deleting an internship application while all applications are being shown 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. + Expected: First application is deleted from the list. Details of the deleted application shown in the status message. 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. + Expected: No application is deleted. Error details shown in the status message. - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ 1. Other incorrect delete commands to try: `delete`, `delete x` (where x is larger than the list size)
Expected: Similar to previous. -1. _{ more test cases …​ }_ - ### Saving data -1. Dealing with missing/corrupted data files +1. Dealing with missing data file. + + 1. Simulate a missing data file by deleting `data/workbook.json` (if it exists). + + 1. Start `WorkBook` and it should be populated with sample data. + + 1. Execute `exit` command. + + 1. `data/workbook.json` should be saved with the sample data. + +1. Dealing with corrupted data file. + + 1. Simulate a corrupted data file by manually editing `data/workbook.json`.
Delete the `company` field from one of the internship applications. + + 1. Start `WorkBook` and it should have no data at all. + + 1. Execute `exit` command. - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ + 1. `data/workbook.json` should only contain: `{ "internships" : [] }`. -1. _{ more test cases …​ }_ diff --git a/docs/SettingUp.md b/docs/SettingUp.md index 275445bd551..96218530f67 100644 --- a/docs/SettingUp.md +++ b/docs/SettingUp.md @@ -23,7 +23,7 @@ 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 `seedu.workbook.Main` and try a few commands. 1. [Run the tests](Testing.md) to ensure they all pass. -------------------------------------------------------------------------------------------------------------------- diff --git a/docs/Testing.md b/docs/Testing.md index 8a99e82438a..a40481a3e69 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. `seedu.workbook.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. `seedu.workbook.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. `seedu.workbook.logic.LogicManagerTest` diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3716f3ca8a4..cf24216f043 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,190 +3,546 @@ 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} +
+ +-------------------------------------------------------------------------------------------------------------------- + +
+ +## 1. Introducing WorkBook + +Welcome to WorkBook! :wave: + +WorkBook is an **internship application tracker** that helps Computing students **prepare sufficiently** for their upcoming interviews to secure that internship. +This minimalistic tool allows you to effortlessly collate and easily manage all of your internship applications' progress. +Furthermore, **tips are given for relevant stages** of your internship applications to give you an edge over other applicants! + +This guide provides a step-by-step guide on how you can get started using WorkBook, gives an overview of what you can do in WorkBook and how you can best utilise it to transform your internship hunt positively. +Each documented feature introduces a potential problem you face, how it can be resolved and examples on using the feature. -* Table of Contents -{:toc} +No time to waste, let's start _Working_! :muscle: -------------------------------------------------------------------------------------------------------------------- -## Quick start +## 2. Getting started + +This section helps you get started with WorkBook. + +It consists of a step-by-step installation guide and an explanation of the key GUI elements. + +### 2.1 Installation + +1. Ensure you have [Java 11 or above](https://www.oracle.com/sg/java/technologies/downloads/#java11) installed on your computer. + +2. Download the latest `WorkBook.jar` from [here](https://github.com/AY2223S1-CS2103T-T10-3/tp/releases/). + +3. Copy the downloaded `WorkBook.jar` to a folder of your choice. + +4. Using your command terminal: + 1. Navigate to the folder where you placed your WorkBook at. + 2. Run: `java -jar WorkBook.jar`.
The GUI, as shown below in one of the two layouts, should appear within seconds.
+ +
-1. Ensure you have Java `11` or above installed in your Computer. +| Wide Layout | Narrow Layout | +|:------------------------------:|:-------------------------------------:| +| ![wide layout](images/Ui2.png) | ![narrow layout](images/UiNarrow.png) | -1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases). +5. Tell WorkBook what you want to do by typing your command in `Enter command here...` at the top of the application and pressing Enter on your keyboard to execute it. -1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook. +6. Before diving right into using WorkBook, familiarise yourself with the [things to note](#4-things-to-note) to not hinder your tracking process! -1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png) +
-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: +### 2.1 Understanding WorkBook's GUI - * **`list`** : Lists all contacts. +Below shows the main elements of WorkBook's GUI, in wide and narrow layouts. - * **`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. +For the narrow layout, everything else is the same except for the labelled light bulb icon, which displays tips. - * **`delete`**`3` : Deletes the 3rd contact shown in the current list. +| Wide Layout | +|:--------------------------------------:| +| ![wide layout](images/AnnotatedUi.png) | - * **`clear`** : Deletes all contacts. +
- * **`exit`** : Exits the app. +| Narrow Layout | +|:------------------------------------------------------:| +| ![narrow layout](images/AnnotatedUiNarrowBulbOnly.png) | -1. Refer to the [Features](#features) below for details of each command. -------------------------------------------------------------------------------------------------------------------- +## 3. Exploring our guide -## Features +**Information Box**
+**:information_source: Info:** Provides extra information that is useful +
+ +**Warning Box** +
+**:exclamation: Warning: Important messages** +
+ +**Tip Box** +
+**:bulb: Tip:** Provides pointers to enhance your experience using the application +
+ +**Highlights**
+`commands` or `PARAMETERS` + +-------------------------------------------------------------------------------------------------------------------- -**:information_source: Notes about the command format:**
+## 4. Things to note + +This section describes important information for you to take note of before and while using WorkBook. In order to make WorkBook work best for you, do familiarise yourself with the items in this section. + +### 4.1 Notes about the command format: * 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`. + e.g. in `add c/COMPANY`, `COMPANY` is a parameter which can be used as `add c/Meta`. * 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`. + e.g `c/COMPANY [t/TAG]` can be used as `c/Meta t/unattainable` or as `c/Meta`. * 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. + e.g. `[t/TAG]…​` can be omitted, used once: `t/unattainable`, or multiple times: `t/unattainable t/AWS`. * Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. + e.g. if the command specifies `c/COMPANY s/STAGE`, `s/STAGE c/COMPANY` 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.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken. +* If a parameter is expected only once in the command, but you specified it multiple times, only the last occurrence of the parameter will be taken.
+ e.g. if you specify `r/Frontend r/Backend`, only `r/Backend` will be taken. * Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`. +### 4.2 Parameter-specific behaviour + +* Whenever `[d/DATETIME]` is specified as a parameter, you should input it in the format `dd-MMM-yyy hh:mm` where `y` is year, `M` is month, `d` is day, `h` is hour in the 24-hour format and `m` is minutes.
+ e.g. October 2 2022 5:00pm should be inputted as `02-Oct-2022 17:00`. + * Month is not case-sensitive + +### 4.3 Behaviour of sorted internship applications + +* The list of applications are sorted downwards from the closest upcoming application to furthest. +* Those with no `DATETIME` attached to it will be placed below those with upcoming dates. +* Applications in the past (i.e. `DATETIME` is past current time) will be placed at the bottom of the list, sorted downwards as well from the most recently passed. +* An example is shown below: +![SortExample](images/SortExample.png) + +
+ +### 4.4 Responsive UI when resizing window + +* The UI will change dynamically depending on the window width. + +* If the window width is too small, WorkBook will switch to a narrow layout for a better UX. + +* Otherwise, WorkBook will be in the wide layout which has an extra right panel for displaying tips. + +| Wide Layout | +|:--------------------------------------:| +| Resize the window to a wider width to get this layout | +| ![wide layout](images/AnnotatedUi.png) | + +
+ +| Narrow Layout | +|:------------------------------------------------------:| +| Resize the window to a narrower width to get this layout | +| ![narrow layout](images/AnnotatedUiNarrowBulbOnly.png) | + + + +## 5. What you can do + +| Your action | Command format
e.g. Example command (If applicable) | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Add** | `add c/COMPANY r/ROLE s/STAGE [d/DATETIME] [e/COMPANY_EMAIL] [l/LANGUAGE TAG]… [t/TAG]…​`
e.g., `add c/Bytedance r/Backend Engineer s/Online Assessment d/24-Sep-2022 15:00 t/high pay l/Javascript` | +| **Edit** | `edit INDEX [c/COMPANY] [d/DATETIME] [e/COMPANY_EMAIL] [r/ROLE] [l/LANGUAGE TAG]… [t/TAG]…​​`
e.g.,`edit 2 c/Meta e/hr@meta.com` | +| **Find** | `find [c/COMPANY] [r/ROLE] [s/STAGE]`
e.g., `find c/Meta` | +| **Delete** | `delete INDEX`
e.g., `delete 3` | +| **List** | `list` | +| **Undo** | `undo` | +| **Redo** | `redo` | +| **Clear** | `clear` | +| **Help** | `help` | +| **Exit** | `exit` | + +
+**:information_source: Note:**
+* Commands without examples are considered trivial and can be executed by inputting the command without additional parameters. +* Commands are **case-sensitive**! +
-### Viewing help : `help` +### 5.1. Adding your internship application -Shows a message explaning how to access the help page. +Have you taken the first step to apply for that internship you've always wanted? +Or do you want to start keeping track of the different internship applications you have?
-![help message](images/helpMessage.png) +This command satisfies the above, allowing you to add your internship applications to the list and track all of them. +WorkBook also removes the hassle of sorting your internship applications manually by automating it for you! -Format: `help` +Simply follow the command format below to add the relevant details into WorkBook! +Format: `add c/COMPANY r/ROLE s/STAGE [d/DATETIME] [e/COMPANY_EMAIL] [l/LANGUAGE TAG]…​ [t/TAG]…​` -### Adding a person: `add` +Example: `add c/Meta r/Web Developer s/Application Sent d/20-Oct-2022 10:00 l/Java e/metaHires@meta.com`

+What you will see: -Adds a person to the address book. +| What you will see | +|:------------------------------------------------:| +| ![AddCommandResult](images/AddCommandResult.png) | -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​` -
:bulb: **Tip:** -A person can have any number of tags (including 0) +
+**:bulb: Tip:** The date and time you provide could represent multiple things:
+ * The date and time it happened + * The deadline of the corresponding `Stage`
-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` +
+**:exclamation: Caution** +* adding DateTime like `d/24-Sep-2022 24:00` will be read as `d/25-Sep-2022 00:00` +
-### Listing all persons : `list` +Other examples: +* `add c/Shopback r/Blockchain Developer s/Technical Interview` +* `add c/Bytedance r/Backend Engineer s/Online Assessment d/24-Sep-2022 15:00 t/high pay l/Java l/Python` -Shows a list of all persons in the address book. +### 5.2. Editing your internship application -Format: `list` +WorkBook allows you to seamlessly update fields of respective internship applications with this command. + +A good time to use this command is to update the stage of your application so that WorkBook can give you relevant tips and reminders! + +Format: `edit INDEX [c/COMPANY] [r/ROLE] [s/STAGE] [d/DATETIME] [e/COMPANY_EMAIL] [l/LANGUAGE TAG] [t/TAG]…​` + +* Edits the internship at the specified `INDEX`, which **must be**: + * A positive number (1, 2, 3, …​). + * Within the number range of your list of internship applications. +* At least one of the optional fields **must** be provided. -### Editing a person : `edit` +Example: `edit 2 s/Technical Interview d/28-Dec-2022 08:00` -Edits an existing person in the address book. +What you'll see before and after executing the command:
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…​` +| State | What you will see | +|------------|---------------------------------------------| +| **Before** | ![Before edit](images/EditCommandInput.png) | +| **After** | ![After edit](images/EditCommandResult.png) | -* 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 + +
+**:exclamation: Caution**: Adding of tags is not cumulative: When editing tags, the existing tags of the internship will be **removed**. +
+ +
+**:bulb: Tip:** As adding of tags is not cumulative, you can remove all the internship’s tags by typing `t/` without specifying any tags after it. +
-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. +Other examples: +* `edit 2 l/golang t/`: Adds `golang` as the only language tag for the second internship and clears all existing tags. + +### 5.3. Listing all existing internship applications + +Lists all of your internship applications in WorkBook in a [sorted order](#43-behaviour-of-sorted-internship-applications). + +
+**:bulb: Tip:** Your most recent upcoming internship application will be at the top of the list! +
+ +Format: `list` -### Locating persons by name: `find` +### 5.4. Viewing tips for your applications: -Finds persons whose names contain any of the given keywords. +For some application stages, we have included a list of useful tips to help you prepare for and ace the deliverables. -Format: `find KEYWORD [MORE_KEYWORDS]` +Below are the application stages that we have included tips for. -* The search is case-insensitive. e.g `hans` will match `Hans` -* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -* Only the name is searched. -* Only full words will be matched e.g. `Han` will not match `Hans` -* Persons matching at least one keyword will be returned (i.e. `OR` search). - e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` +| Application Stage | +|------------------------| +| `Application Sent` | +| `Online Assessment` | +| `Technical Interview` | +| `Behavioral Interview` | +| `Phone Interview` | +| `Rejected` | + +If WorkBook is in the [narrow layout](#44-responsive-ui-when-resizing-window), simply click on the light bulb icon to view the tips for that application. A window will appear showing all the tips for that application. + +| Light Bulb Button | Tips Window | +|:-----------------------------------------------:|:-------------------------------------:| +| ![light bulb button](images/ClickLightBulb.png) | ![tips window](images/TipsWindow.png) | + +To view the tips in the [wide layout](#44-responsive-ui-when-resizing-window), simply click and select the application you would like to view the tips for. The tips will appear in the right panel. + +### 5.5. Finding your internships + +If you wanted to view all your internship applications corresponding to a particular company, stage or role, +then this command is for you!
+ +It can find internships whose company, role or stage names contain all the respective keywords. + +Format: `find c/COMPANY | r/ROLE | s/STAGE` + +* Displays a list of internships that match all the keywords. + +
+**:bulb: Tip:**
+* Case does not matter e.g. `meta` will match `Meta`. +* Order of the keywords does not matter e.g. `Jane Street` will match `Street Jane`. +
+ +
+**:exclamation: Caution**
+* Only full words will be matched e.g. `met` will not match `Meta`. +* Exactly one attribute can be searched for either Company, Role or Stage. +* If you input keywords for more than one prefix it will result in an invalid command e.g. `find c/Meta s/Interview` will not be accepted +
+ + +
Examples: -* `find John` returns `john` and `John Doe` -* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png) +* `find r/Engineer` returns `Software Engineer` and `Backend Engineer`: + +| Before | After | +|:-------------------------------------------:|:-----------------------------------------:| +| ![before layout](images/BeforeFindRole.png) | ![after layout](images/AfterFindRole.png) | + -### Deleting a person : `delete` +### 5.6. Deleting your internship application -Deletes the specified person from the address book. +If you want to remove an internship application then this command +deletes the specified internship application from WorkBook. Format: `delete INDEX` -* Deletes the person at the specified `INDEX`. -* The index refers to the index number shown in the displayed person list. -* The index **must be a positive integer** 1, 2, 3, …​ +* Deletes the internship at the specified `INDEX`, which **must be**: + * A positive number (1, 2, 3, …​). + * Within the number range of your list of internship applications. Examples: -* `list` followed by `delete 2` deletes the 2nd person in the address book. -* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command. +* `list` followed by `delete 2` deletes the 2nd internship application in WorkBook. +* `find Meta` followed by `delete 1` deletes the 1st internship application within the results of the `find` command. -### Clearing all entries : `clear` +### 5.7. Clearing your existing internship applications -Clears all entries from the address book. +Be it getting ready for a new internship application cycle or wanting to do a general spring-cleaning of your +list of internship applications in WorkBook, this command is the one for you! + +Use this command to clear all the applications you've previously saved in WorkBook. Format: `clear` -### Exiting the program : `exit` +Example: +* `clear` removes all internship applications in the WorkBook. + +
+**:bulb: Tip:** If you cleared your internship applications by mistake, fret not as you can easily undo this! +
+ +### 5.8. Undoing your previous command + +What if you accidentally made a mistake and performed a wrong undoable command? +Workbook can help you to undo your changes after performing an +undesirable undoable command and restore itself to the +previous version! + +WorkBook keeps track of all your previous undoable commands and its current version, allowing you to `undo` as many times +to restore any desired state of your WorkBook. + +Format: `undo` +* Undo the previous undoable command. +* You can perform the `undo` command as many times as the number of tracked Workbook versions +i.e. stacking 2 undo commands sequentially will revert the WorkBook back 2 +versions ago, assuming you performed at least 2 undoable commands previously! +* When you perform an undoable command, it will be stacked on top of the +previous undoable command in the stack. The `undo` command will undo the first undoable command at the +top of the stack. + +* If you have not executed an undoable command previously, the WorkBook will remain in its current version +and return an error message: "No previous changes to undo!". + +![UndoFailure](images/UndoFailure.png) + +
+ +**:information_source: Note:**
+You can only undo undoable commands! +* `add` +* `edit` +* `delete` +* `clear` +* `redo` +
+ +Examples: +* `add c/Meta r/Frontend Engineer s/Application Sent d/29-Oct-2022 12:00 e/hrmonkey@example.com` followed by `undo` will +display the WorkBook version without the added internship. +* `edit 1 s/Behavioural Interview e/hr@meta.com` followed by `clear` and then `undo` will undo the +clearing of the Workbook. The edited stage and email address of the first internship will remain in the +displayed WorkBook version. +* `delete 2` followed by `list` and then `undo` will restore the WorkBook to its version prior to the +`delete 2` command as the `list` command is not an undoable command and does not create a new +version of the WorkBook. +* `edit 2 l/golang t/` followed by `delete 1` and then 2 consecutive `undo` commands will first restore the +WorkBook to its version before the `delete 1` command, and then the version before the `edit` command. + +What you'll see before and after executing the command:
+ +| State | What you will see | +|--------------------------------------------------|----------------------------------------| +| **Before** | ![BeforeEdit](images/BeforeEdit.png) | +| **After executing command `edit 2 l/golang t/`** | ![AfterEdit](images/AfterEdit.png) | +| **After executing command `delete 1`** | ![AfterDelete](images/AfterDelete.png) | +| **After executing command: `undo`** | ![AfterUndo1](images/AfterUndo1.png) | +| **After executing command: `undo`** | ![AfterUndo2](images/AfterUndo2.png) | + +
+ +**:bulb: Tip:**
+* If you have undone your previous undoable command by mistake, fret not as you can easily redo this +to reapply the initial changes! +* Performing multiple `undo` commands may confuse you as to which undoable command you are +undoing and how your WorkBook currently looks like! +* Tracked WorkBook versions will reset once you `exit` the application! + +
+ +### 5.9. Redoing your previous command + +Now, what if you mistakenly performed an `undo` command? +Workbook can help you to redo your changes after performing +an undesirable `undo` command and restore itself to the version before that! + +WorkBook keeps track of all your previous undoable commands and its current version, +allowing the `redo` command to be performed as many times to reverse the +`undo` commands you have performed! + +Format: `redo` +* Redo the previous `undo` command. +* You can perform the redo command as many times as the number of undone versions in the Workbook's tracked versions +i.e. stacking 2 redo commands sequentially will revert the WorkBook back to its version 2 + `undo` commands ago, assuming that you performed at least 2 `undo` commands previously. +* When you perform an `undo` command, it will be stacked on top of the +previous `undo` command in the stack. The `redo` command will redo the first `undo` command at the +top of the stack. +* If you have not executed a previous `undo` command, the WorkBook will remain in its current state + and return an error message: "No more commands to redo!". + +![RedoFailure](images/RedoFailure.png) + +Examples: +* `add c/Meta r/Frontend Engineer s/Application Sent d/29-Oct-2022 12:00 e/hrmonkey@example.com` followed by `undo` +and then `redo` will restore the WorkBook version with the added internship. +* `edit 1 s/Behavioural Interview e/hr@visa.com` followed by `clear` will create 2 new WorkBook versions. +If you perform 2 consecutive `undo` commands, the WorkBook will be restored to the version before both +`edit` and `clear` commands. When you perform a `redo` command now, +the WorkBook version will contain the edited stage and email for the first internship. + +
+ + +| State | What you will see | +|----------------------------------------------------------------------------|------------------------------------------| +| **After executing command `edit 1 s/Behavioural Interview e/hr@visa.com`** | ![AfterEdit](images/RedoAfterEdit.png) | +| **After executing command `clear`** | ![AfterClear](images/RedoAfterClear.png) | +| **After executing command: `undo`** | ![AfterUndo1](images/RedoAfterUndo1.png) | +| **After executing command: `undo`** | ![AfterUndo2](images/RedoAfterUndo2.png) | +| **After executing command: `redo`** | ![AfterRedo](images/RedoAfterRedo.png) | + +
+ +**:bulb: Tip:**
+* If you have redone your previous undo command by mistake, fret not as you can easily undo this again +to remove the initial changes! +* Performing multiple `redo` commands may confuse you as to which `undo` command you are +redoing and how your WorkBook currently looks like! +* Tracked WorkBook versions will reset once you `exit` the application! +
+ +### 5.10. Viewing help + +This shows a summary of the commands as well as a link to this User Guide. + +Format: `help` + +### 5.11. Exiting the program Exits the program. Format: `exit` -### Saving the data +-------------------------------------------------------------------------------------------------------------------- + +## 6. Managing your data + +### 6.1. Saving + +Conveniently, any inputted command that changes any part of your internship application is **automatically saved**! +Hence, you need not worry about pressing ctrl + s on your keyboard everytime you update your list of internship applications. -AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. +### 6.2. Editing -### Editing the data file +All of your internship applications are saved in a JSON file under the `data` subfolder. +You are free to update any internship application directly by editing that JSON file. -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. +
+ +**:information_source: JSON?:**
+* JSON stands for JavaScript Object Notation, learn how to edit the file [here](https://www.softwaretestinghelp.com/how-to-open-a-json-file/)! + +
: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. +If your changes to the data file makes its format invalid, WorkBook will discard all data and start with an empty data file at the next run.
-### Archiving data files `[coming in v2.0]` +-------------------------------------------------------------------------------------------------------------------- + +## 7. Frequently asked questions + +**Q**: How do I transfer my data to another Computer?
+**A**: [Install](#2-get-started) the app in the other computer, copy and override the JSON file in the new `data` subfolder, and you are done! -_Details coming soon ..._ +**Q**: How do I change the theme of WorkBook?
+**A**: It is not possible as of now, but will be coming soon! -------------------------------------------------------------------------------------------------------------------- -## FAQ +## 8. Prefix summary -**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. +| Prefix | Symbolizes | +|--------|--------------| +| **n/** | Company Name | +| **s/** | Stage | +| **r/** | Role | +| **d/** | DateTime | +| **e/** | Email | +| **l/** | Language Tag | +| **t/** | Tag | -------------------------------------------------------------------------------------------------------------------- -## 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` +## 9. Glossary + +| Term | Description | +|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| Graphical User Interface (GUI) | GUI allows user to interact with an application through graphics such as icons, menu, etc. | +| Command Line Interface (CLI) | CLI allows user to use text as commands to be executed by an application. | +| Command | Instruction typed by the user for WorkBook to execute. | +| Parameter | A component of a command for the user to input information. For WorkBook's context, this refers to the internship application details. | +| Prefix | An abbreviation for the name of the parameter. Prefix should be entered before the actual parameter in a command and always ends with a slash (/). | +| Alphanumeric | Characters that are either a number or a letter. | +| Subfolder | A folder within a folder. | + diff --git a/docs/_config.yml b/docs/_config.yml index 6bd245d8f4e..f89a3c8a47c 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,4 +1,4 @@ -title: "AB-3" +title: "WorkBook" theme: minima header_pages: @@ -8,7 +8,12 @@ header_pages: markdown: kramdown -repository: "se-edu/addressbook-level3" +# Solution reused from https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/179/commits/aec461182c194c9ca2c67d7c407fcabb376191ff +kramdown: + parse_block_html: true + + +repository: "AY2223S1-CS2103T-T10-3/tp" github_icon: "images/github-icon.png" plugins: diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss index 0d3f6e80ced..14f69525d72 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: "WorkBook"; font-size: 32px; } } diff --git a/docs/_sass/minima/_layout.scss b/docs/_sass/minima/_layout.scss index ca99f981701..272eee5d882 100644 --- a/docs/_sass/minima/_layout.scss +++ b/docs/_sass/minima/_layout.scss @@ -261,3 +261,11 @@ width: calc(50% - (#{$spacing-unit} / 2)); } } + +/** + * Table of Contents with bullet points removed + * Reused from https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7 + */ + .toc-no-bullet-points ul, .toc-no-bullet-points ol { + list-style-type: none; +} diff --git a/docs/diagrams/AddCommandClassDiagram.puml b/docs/diagrams/AddCommandClassDiagram.puml new file mode 100644 index 00000000000..938f316f2c0 --- /dev/null +++ b/docs/diagrams/AddCommandClassDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor UI_COLOR_T4 +skinparam classBackgroundColor UI_COLOR +show members + +package Model <>{ +Class "<>\nModel" as Model +Class ModelManager +Class VersionedWorkBook +Class Internship +Class UniqueInternshipList { +internalList: ObservableList +sortedInternalList: SortedList +} +Class WorkBook +} + +package Logic { +Class AddCommandParser { +parse(String): AddCommand +} +Class AddCommand +Class CommandResult +Class "{abstract}\nCommand" as Command +} + +Class HiddenOutside #FFFFFF +HiddenOutside .> AddCommand + +AddCommandParser ..> AddCommand : produces > +AddCommand -up-|> Command +Command .> CommandResult : produces > + +Command ...> Model + +ModelManager .up.|> Model +VersionedWorkBook -up-|> WorkBook +ModelManager --> "1 " VersionedWorkBook + +WorkBook *--> "1 " UniqueInternshipList +UniqueInternshipList --> "~* all" Internship +@enduml diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index ef81d18c337..b91b2dbda00 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -13,13 +13,13 @@ activate ui UI_COLOR ui -[UI_COLOR]> logic : execute("delete 1") activate logic LOGIC_COLOR -logic -[LOGIC_COLOR]> model : deletePerson(p) +logic -[LOGIC_COLOR]> model : deleteInternship(1) activate model MODEL_COLOR model -[MODEL_COLOR]-> logic deactivate model -logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook) +logic -[LOGIC_COLOR]> storage : saveWorkBook(WorkBook) activate storage STORAGE_COLOR storage -[STORAGE_COLOR]> storage : Save to file diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml index 5731f9cbaa1..bc443f07ff9 100644 --- a/docs/diagrams/BetterModelClassDiagram.puml +++ b/docs/diagrams/BetterModelClassDiagram.puml @@ -4,18 +4,21 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -AddressBook *-right-> "1" UniquePersonList -AddressBook *-right-> "1" UniqueTagList -UniqueTagList -[hidden]down- UniquePersonList -UniqueTagList -[hidden]down- UniquePersonList +WorkBook *-right-> "1" UniqueInternshipList +WorkBook *-right-> "1" UniqueTagList +UniqueTagList -[hidden]down- UniqueInternshipList +UniqueTagList -[hidden]down- UniqueInternshipList UniqueTagList *-right-> "*" Tag -UniquePersonList -right-> Person +UniqueInternshipList -right-> Internship + +Internship -up-> "*" Tag + +Internship *--> Company +Internship *--> Role +Internship *--> Email +Internship *--> Stage +Internship *--> DateTime -Person -up-> "*" Tag -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address @enduml diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml index 6a6b23a006f..8d5b06de90c 100644 --- a/docs/diagrams/CommitActivityDiagram.puml +++ b/docs/diagrams/CommitActivityDiagram.puml @@ -1,14 +1,15 @@ @startuml + +skinparam ActivityBackgroundColor yellow start :User executes command; '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 WorkBook]) + :Purge redundant states; + :Save WorkBook to workBookStateList; else ([else]) endif stop diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml index 1dc2311b245..9ffb2717a56 100644 --- a/docs/diagrams/DeleteSequenceDiagram.puml +++ b/docs/diagrams/DeleteSequenceDiagram.puml @@ -3,7 +3,7 @@ box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":WorkBookParser" as AddressBookParser LOGIC_COLOR participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR participant ":CommandResult" as CommandResult LOGIC_COLOR @@ -48,7 +48,7 @@ deactivate AddressBookParser LogicManager -> DeleteCommand : execute() activate DeleteCommand -DeleteCommand -> Model : deletePerson(1) +DeleteCommand -> Model : deleteInternship(1) activate Model Model --> DeleteCommand diff --git a/docs/diagrams/FindCommandDiagram.puml b/docs/diagrams/FindCommandDiagram.puml new file mode 100644 index 00000000000..4e3db8fc295 --- /dev/null +++ b/docs/diagrams/FindCommandDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor UI_COLOR_T4 +skinparam classBackgroundColor UI_COLOR +show members + +package Model <>{ +Class "<>\nModel" as Model +Class ModelManager +Class VersionedWorkBook +Class Internship +Class UniqueInternshipList { +internalList: ObservableList +sortedInternalList: SortedList +} +Class WorkBook +} + +package Logic { +Class FindCommandParser { +parse(String): FindCommand +} +Class FindCommand +Class CommandResult +Class "{abstract}\nCommand" as Command +} + +Class HiddenOutside #FFFFFF +HiddenOutside .> FindCommand + +FindCommandParser ..> FindCommand : produces > +FindCommand -up-|> Command +Command .> CommandResult : produces > + +Command ...> Model + +ModelManager .up.|> Model +VersionedWorkBook -up-|> WorkBook +ModelManager --> "1 " VersionedWorkBook + +WorkBook *--> "1 " UniqueInternshipList +UniqueInternshipList --> "~* all" Internship +@enduml diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml index d4193173e18..ba4f8a25c70 100644 --- a/docs/diagrams/LogicClassDiagram.puml +++ b/docs/diagrams/LogicClassDiagram.puml @@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR package Logic { -Class AddressBookParser +Class WorkBookParser Class XYZCommand Class CommandResult Class "{abstract}\nCommand" as Command @@ -27,8 +27,8 @@ Class HiddenOutside #FFFFFF HiddenOutside ..> Logic LogicManager .right.|> Logic -LogicManager -right->"1" AddressBookParser -AddressBookParser ..> XYZCommand : creates > +LogicManager -right->"1" WorkBookParser +WorkBookParser ..> XYZCommand : creates > XYZCommand -up-|> Command LogicManager .left.> Command : executes > diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index 4439108973a..7dc857b4ff2 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -5,19 +5,20 @@ skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR Package Model <>{ -Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook +Class "<>\nReadOnlyWorkBook" as ReadOnlyWorkBook Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs Class "<>\nModel" as Model -Class AddressBook +Class WorkBook Class ModelManager Class UserPrefs -Class UniquePersonList -Class Person -Class Address +Class UniqueInternshipList +Class Internship +Class Company +Class DateTime +Class Role +Class Stage Class Email -Class Name -Class Phone Class Tag } @@ -25,26 +26,27 @@ Class Tag Class HiddenOutside #FFFFFF HiddenOutside ..> Model -AddressBook .up.|> ReadOnlyAddressBook +WorkBook .up.|> ReadOnlyWorkBook ModelManager .up.|> Model Model .right.> ReadOnlyUserPrefs -Model .left.> ReadOnlyAddressBook -ModelManager -left-> "1" AddressBook +Model .left.> ReadOnlyWorkBook +ModelManager -left-> "1" WorkBook ModelManager -right-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs -AddressBook *--> "1" UniquePersonList -UniquePersonList --> "~* all" Person -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address -Person *--> "*" Tag +WorkBook *--> "1" UniqueInternshipList +UniqueInternshipList --> "~* all" Internship +Internship *--> Company +Internship *--> DateTime +Internship *--> Role +Internship *--> Stage +Internship *--> Email +Internship *--> "*" Tag -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email +Company -[hidden]right-> Role +Role -[hidden]right-> Stage +Stage -[hidden]right-> DateTime -ModelManager -->"~* filtered" Person +ModelManager -->"~* filtered" Internship @enduml diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml index 0c7424de6e0..bf317f91c46 100644 --- a/docs/diagrams/ParserClasses.puml +++ b/docs/diagrams/ParserClasses.puml @@ -9,7 +9,7 @@ Class XYZCommand package "Parser classes"{ Class "<>\nParser" as Parser -Class AddressBookParser +Class WorkBookParser Class XYZCommandParser Class CliSyntax Class ParserUtil @@ -19,12 +19,12 @@ Class Prefix } Class HiddenOutside #FFFFFF -HiddenOutside ..> AddressBookParser +HiddenOutside ..> WorkBookParser -AddressBookParser .down.> XYZCommandParser: creates > +WorkBookParser .down.> XYZCommandParser: creates > XYZCommandParser ..> XYZCommand : creates > -AddressBookParser ..> Command : returns > +WorkBookParser ..> Command : returns > XYZCommandParser .up.|> Parser XYZCommandParser ..> ArgumentMultimap XYZCommandParser ..> ArgumentTokenizer diff --git a/docs/diagrams/RedoSequenceDiagram.puml b/docs/diagrams/RedoSequenceDiagram.puml new file mode 100644 index 00000000000..09ef6881267 --- /dev/null +++ b/docs/diagrams/RedoSequenceDiagram.puml @@ -0,0 +1,53 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":WorkBookParser" as WorkBookParser LOGIC_COLOR +participant "r:RedoCommand" as RedoCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":VersionedWorkBook" as VersionedWorkBook MODEL_COLOR +end box +[-> LogicManager : execute(redo) +activate LogicManager + +LogicManager -> WorkBookParser : parseCommand(redo) +activate WorkBookParser + +create RedoCommand +WorkBookParser -> RedoCommand +activate RedoCommand + +RedoCommand --> WorkBookParser +deactivate RedoCommand + +WorkBookParser --> LogicManager : r +deactivate WorkBookParser + +LogicManager -> RedoCommand : execute() +activate RedoCommand + +RedoCommand -> Model : redoWorkBook() +activate Model + +Model -> VersionedWorkBook : redo() +activate VersionedWorkBook + +VersionedWorkBook -> VersionedWorkBook :resetData(ReadOnlyWorkBook) +VersionedWorkBook --> Model : +deactivate VersionedWorkBook + +Model --> RedoCommand +deactivate Model + +RedoCommand --> LogicManager : result +deactivate RedoCommand +RedoCommand -[hidden]-> LogicManager : result +destroy RedoCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 760305e0e58..f6fdd08d43e 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -14,11 +14,11 @@ Class JsonUserPrefsStorage Class "<>\nStorage" as Storage Class StorageManager -package "AddressBook Storage" #F4F6F6{ -Class "<>\nAddressBookStorage" as AddressBookStorage -Class JsonAddressBookStorage -Class JsonSerializableAddressBook -Class JsonAdaptedPerson +package "Workbook Storage" #F4F6F6{ +Class "<>\nWorkBookStorage" as WorkBookStorage +Class JsonWorkBookStorage +Class JsonSerializableWorkBook +Class JsonAdaptedInternship Class JsonAdaptedTag } @@ -29,15 +29,15 @@ HiddenOutside ..> Storage StorageManager .up.|> Storage StorageManager -up-> "1" UserPrefsStorage -StorageManager -up-> "1" AddressBookStorage +StorageManager -up-> "1" WorkBookStorage Storage -left-|> UserPrefsStorage -Storage -right-|> AddressBookStorage +Storage -right-|> WorkBookStorage JsonUserPrefsStorage .up.|> UserPrefsStorage -JsonAddressBookStorage .up.|> AddressBookStorage -JsonAddressBookStorage ..> JsonSerializableAddressBook -JsonSerializableAddressBook --> "*" JsonAdaptedPerson -JsonAdaptedPerson --> "*" JsonAdaptedTag +JsonWorkBookStorage .up.|> WorkBookStorage +JsonWorkBookStorage ..> JsonSerializableWorkBook +JsonSerializableWorkBook --> "*" JsonAdaptedInternship +JsonAdaptedInternship --> "*" JsonAdaptedTag @enduml diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 95473d5aa19..8544800ec40 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -11,8 +11,8 @@ Class UiManager Class MainWindow Class HelpWindow Class ResultDisplay -Class PersonListPanel -Class PersonCard +Class InternshipListPanel +Class InternshipCard Class StatusBarFooter Class CommandBox } @@ -32,26 +32,26 @@ UiManager .left.|> Ui UiManager -down-> "1" MainWindow MainWindow *-down-> "1" CommandBox MainWindow *-down-> "1" ResultDisplay -MainWindow *-down-> "1" PersonListPanel +MainWindow *-down-> "1" InternshipListPanel MainWindow *-down-> "1" StatusBarFooter MainWindow --> "0..1" HelpWindow -PersonListPanel -down-> "*" PersonCard +InternshipListPanel -down-> "*" InternshipCard MainWindow -left-|> UiPart ResultDisplay --|> UiPart CommandBox --|> UiPart -PersonListPanel --|> UiPart -PersonCard --|> UiPart +InternshipListPanel --|> UiPart +InternshipCard --|> UiPart StatusBarFooter --|> UiPart HelpWindow --|> UiPart -PersonCard ..> Model +InternshipCard ..> Model UiManager -right-> Logic MainWindow -left-> Logic -PersonListPanel -[hidden]left- HelpWindow +InternshipListPanel -[hidden]left- HelpWindow HelpWindow -[hidden]left- CommandBox CommandBox -[hidden]left- ResultDisplay ResultDisplay -[hidden]left- StatusBarFooter diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml index 96e30744d24..b65cc413135 100644 --- a/docs/diagrams/UndoRedoState0.puml +++ b/docs/diagrams/UndoRedoState0.puml @@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000 title Initial state package States { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab2:WorkBook__" } State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 hide State2 hide State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State1 @end diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml index 01fcb9b2b96..93f533da3ef 100644 --- a/docs/diagrams/UndoRedoState1.puml +++ b/docs/diagrams/UndoRedoState1.puml @@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000 title After command "delete 5" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab2:WorkBook__" } State1 -[hidden]right-> State2 @@ -16,7 +16,7 @@ State2 -[hidden]right-> State3 hide State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State2 @end diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml index bccc230a5d1..2fbdc3805df 100644 --- a/docs/diagrams/UndoRedoState2.puml +++ b/docs/diagrams/UndoRedoState2.puml @@ -3,18 +3,18 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title After command "add n/David" +title After command "add..." package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab2:WorkBook__" } State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State3 @end diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml index ea29c9483e4..8c44a969e01 100644 --- a/docs/diagrams/UndoRedoState3.puml +++ b/docs/diagrams/UndoRedoState3.puml @@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000 title After command "undo" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab2:WorkBook__" } State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State2 @end diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml index 1b784cece80..aec3b309ee2 100644 --- a/docs/diagrams/UndoRedoState4.puml +++ b/docs/diagrams/UndoRedoState4.puml @@ -3,18 +3,18 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title After command "list" +title After command "redo" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab2:WorkBook__" } State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" -Pointer -up-> State2 +Pointer -up-> State3 @end diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml index 88927be32bc..358e2fe7b03 100644 --- a/docs/diagrams/UndoRedoState5.puml +++ b/docs/diagrams/UndoRedoState5.puml @@ -3,19 +3,18 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title After command "clear" +title After command "list" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab3:AddressBook__" + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab2:WorkBook__" } State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" -Pointer -up-> State3 -note right on link: State ab2 deleted. +Pointer -up-> State2 @end diff --git a/docs/diagrams/UndoRedoState6.puml b/docs/diagrams/UndoRedoState6.puml new file mode 100644 index 00000000000..d9c98be4a26 --- /dev/null +++ b/docs/diagrams/UndoRedoState6.puml @@ -0,0 +1,21 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "clear" + +package States <> { + class State1 as "__ab0:WorkBook__" + class State2 as "__ab1:WorkBook__" + class State3 as "__ab3:WorkBook__" +} + +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 + +class Pointer as "Current State" + +Pointer -up-> State3 +note right on link: State ab2 deleted. +@end diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml index 410aab4e412..15bb723eb91 100644 --- a/docs/diagrams/UndoSequenceDiagram.puml +++ b/docs/diagrams/UndoSequenceDiagram.puml @@ -3,42 +3,42 @@ box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":WorkBookParser" as WorkBookParser LOGIC_COLOR participant "u:UndoCommand" as UndoCommand LOGIC_COLOR end box box Model MODEL_COLOR_T1 participant ":Model" as Model MODEL_COLOR -participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR +participant ":VersionedWorkBook" as VersionedWorkBook MODEL_COLOR end box [-> LogicManager : execute(undo) activate LogicManager -LogicManager -> AddressBookParser : parseCommand(undo) -activate AddressBookParser +LogicManager -> WorkBookParser : parseCommand(undo) +activate WorkBookParser create UndoCommand -AddressBookParser -> UndoCommand +WorkBookParser -> UndoCommand activate UndoCommand -UndoCommand --> AddressBookParser +UndoCommand --> WorkBookParser deactivate UndoCommand -AddressBookParser --> LogicManager : u -deactivate AddressBookParser +WorkBookParser --> LogicManager : u +deactivate WorkBookParser LogicManager -> UndoCommand : execute() activate UndoCommand -UndoCommand -> Model : undoAddressBook() +UndoCommand -> Model : undoWorkBook() activate Model -Model -> VersionedAddressBook : undo() -activate VersionedAddressBook +Model -> VersionedWorkBook : undo() +activate VersionedWorkBook -VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook) -VersionedAddressBook --> Model : -deactivate VersionedAddressBook +VersionedWorkBook -> VersionedWorkBook :resetData(ReadOnlyWorkBook) +VersionedWorkBook --> Model : +deactivate VersionedWorkBook Model --> UndoCommand deactivate Model diff --git a/docs/images/AddCommandClassDiagram.png b/docs/images/AddCommandClassDiagram.png new file mode 100644 index 00000000000..15787e43b24 Binary files /dev/null and b/docs/images/AddCommandClassDiagram.png differ diff --git a/docs/images/AddCommandResult.png b/docs/images/AddCommandResult.png new file mode 100644 index 00000000000..0f9fd0e9402 Binary files /dev/null and b/docs/images/AddCommandResult.png differ diff --git a/docs/images/AfterDelete.png b/docs/images/AfterDelete.png new file mode 100644 index 00000000000..8265d1e4802 Binary files /dev/null and b/docs/images/AfterDelete.png differ diff --git a/docs/images/AfterEdit.png b/docs/images/AfterEdit.png new file mode 100644 index 00000000000..cd3f11640d3 Binary files /dev/null and b/docs/images/AfterEdit.png differ diff --git a/docs/images/AfterFindRole.png b/docs/images/AfterFindRole.png new file mode 100644 index 00000000000..2c65d52cc7c Binary files /dev/null and b/docs/images/AfterFindRole.png differ diff --git a/docs/images/AfterRedoStack.png b/docs/images/AfterRedoStack.png new file mode 100644 index 00000000000..4585b4a7731 Binary files /dev/null and b/docs/images/AfterRedoStack.png differ diff --git a/docs/images/AfterUndo1.png b/docs/images/AfterUndo1.png new file mode 100644 index 00000000000..d010d0b87b7 Binary files /dev/null and b/docs/images/AfterUndo1.png differ diff --git a/docs/images/AfterUndo2.png b/docs/images/AfterUndo2.png new file mode 100644 index 00000000000..e40317486b4 Binary files /dev/null and b/docs/images/AfterUndo2.png differ diff --git a/docs/images/AfterUndoStack.png b/docs/images/AfterUndoStack.png new file mode 100644 index 00000000000..02ef3bb4209 Binary files /dev/null and b/docs/images/AfterUndoStack.png differ diff --git a/docs/images/AnnotatedUi.png b/docs/images/AnnotatedUi.png new file mode 100644 index 00000000000..0fce15be828 Binary files /dev/null and b/docs/images/AnnotatedUi.png differ diff --git a/docs/images/AnnotatedUiNarrow.png b/docs/images/AnnotatedUiNarrow.png new file mode 100644 index 00000000000..05fd1e2ca21 Binary files /dev/null and b/docs/images/AnnotatedUiNarrow.png differ diff --git a/docs/images/AnnotatedUiNarrowBulbOnly.png b/docs/images/AnnotatedUiNarrowBulbOnly.png new file mode 100644 index 00000000000..f807230ba63 Binary files /dev/null and b/docs/images/AnnotatedUiNarrowBulbOnly.png differ diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 2f1346869d0..db4ed0390d9 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/BeforeEdit.png b/docs/images/BeforeEdit.png new file mode 100644 index 00000000000..dcd7c000c5d Binary files /dev/null and b/docs/images/BeforeEdit.png differ diff --git a/docs/images/BeforeFindRole.png b/docs/images/BeforeFindRole.png new file mode 100644 index 00000000000..4f0867a929a Binary files /dev/null and b/docs/images/BeforeFindRole.png differ diff --git a/docs/images/BeforeRedoStack.png b/docs/images/BeforeRedoStack.png new file mode 100644 index 00000000000..4a0fc5a9ae1 Binary files /dev/null and b/docs/images/BeforeRedoStack.png differ diff --git a/docs/images/BeforeUndoStack.png b/docs/images/BeforeUndoStack.png new file mode 100644 index 00000000000..326ea029194 Binary files /dev/null and b/docs/images/BeforeUndoStack.png differ diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png index 1ec62caa2a5..1bf9821d9b3 100644 Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ diff --git a/docs/images/ClickLightBulb.png b/docs/images/ClickLightBulb.png new file mode 100644 index 00000000000..d704f42c0f0 Binary files /dev/null and b/docs/images/ClickLightBulb.png differ diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png index c08c13f5c8b..5d684e02aa4 100644 Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png index fa327b39618..58c3582268f 100644 Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ diff --git a/docs/images/EditCommandInput.png b/docs/images/EditCommandInput.png new file mode 100644 index 00000000000..b8a6826e363 Binary files /dev/null and b/docs/images/EditCommandInput.png differ diff --git a/docs/images/EditCommandResult.png b/docs/images/EditCommandResult.png new file mode 100644 index 00000000000..2f4d6314fd2 Binary files /dev/null and b/docs/images/EditCommandResult.png differ diff --git a/docs/images/FindCommandDiagram.png b/docs/images/FindCommandDiagram.png new file mode 100644 index 00000000000..267524e7ce3 Binary files /dev/null and b/docs/images/FindCommandDiagram.png differ diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png index 9e9ba9f79e5..804a9c5794d 100644 Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png index 04070af60d8..cf9497ede11 100644 Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png index e7b4c8880cd..a38d7d03653 100644 Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ diff --git a/docs/images/RedoAfterClear.png b/docs/images/RedoAfterClear.png new file mode 100644 index 00000000000..344cd2d7c24 Binary files /dev/null and b/docs/images/RedoAfterClear.png differ diff --git a/docs/images/RedoAfterEdit.png b/docs/images/RedoAfterEdit.png new file mode 100644 index 00000000000..29a7b8d0182 Binary files /dev/null and b/docs/images/RedoAfterEdit.png differ diff --git a/docs/images/RedoAfterRedo.png b/docs/images/RedoAfterRedo.png new file mode 100644 index 00000000000..a29a7f28711 Binary files /dev/null and b/docs/images/RedoAfterRedo.png differ diff --git a/docs/images/RedoAfterUndo1.png b/docs/images/RedoAfterUndo1.png new file mode 100644 index 00000000000..75184aa5246 Binary files /dev/null and b/docs/images/RedoAfterUndo1.png differ diff --git a/docs/images/RedoAfterUndo2.png b/docs/images/RedoAfterUndo2.png new file mode 100644 index 00000000000..f6010a23d1a Binary files /dev/null and b/docs/images/RedoAfterUndo2.png differ diff --git a/docs/images/RedoFailure.png b/docs/images/RedoFailure.png new file mode 100644 index 00000000000..fa4973b7a22 Binary files /dev/null and b/docs/images/RedoFailure.png differ diff --git a/docs/images/RedoSequenceDiagram.png b/docs/images/RedoSequenceDiagram.png new file mode 100644 index 00000000000..a0f9e609c6b Binary files /dev/null and b/docs/images/RedoSequenceDiagram.png differ diff --git a/docs/images/ResponsiveUi.gif b/docs/images/ResponsiveUi.gif new file mode 100644 index 00000000000..60f72e6a47f Binary files /dev/null and b/docs/images/ResponsiveUi.gif differ diff --git a/docs/images/SortExample.png b/docs/images/SortExample.png new file mode 100644 index 00000000000..50708d31d8a Binary files /dev/null and b/docs/images/SortExample.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index 2533a5c1af0..189e6a2bfc1 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/TipsPanel.png b/docs/images/TipsPanel.png new file mode 100644 index 00000000000..e1546648414 Binary files /dev/null and b/docs/images/TipsPanel.png differ diff --git a/docs/images/TipsWindow.png b/docs/images/TipsWindow.png new file mode 100644 index 00000000000..3ab7711077a Binary files /dev/null and b/docs/images/TipsWindow.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..959b9a4308b 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/Ui2.png b/docs/images/Ui2.png new file mode 100644 index 00000000000..b7cd4885d45 Binary files /dev/null and b/docs/images/Ui2.png differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 785e04dbab4..885cb4bc2e9 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/UiNarrow.png b/docs/images/UiNarrow.png new file mode 100644 index 00000000000..705fcc2e4b2 Binary files /dev/null and b/docs/images/UiNarrow.png differ diff --git a/docs/images/UndoFailure.png b/docs/images/UndoFailure.png new file mode 100644 index 00000000000..aee4e8ff06c Binary files /dev/null and b/docs/images/UndoFailure.png differ diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png index 8f7538cd884..2f5418b587d 100644 Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png index df9908d0948..c98bd31baf9 100644 Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png index 36519c1015b..72ee283bd03 100644 Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png index 19959d01712..88fbac7d134 100644 Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png index 4c623e4f2c5..a3fa3c4a204 100644 Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png index 84ad2afa6bd..c0094d44dff 100644 Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ diff --git a/docs/images/UndoRedoState6.png b/docs/images/UndoRedoState6.png new file mode 100644 index 00000000000..0907b6a9989 Binary files /dev/null and b/docs/images/UndoRedoState6.png differ diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png index 6addcd3a8d9..0ec900adc25 100644 Binary files a/docs/images/UndoSequenceDiagram.png and b/docs/images/UndoSequenceDiagram.png differ diff --git a/docs/images/adeearyaa.png b/docs/images/adeearyaa.png new file mode 100644 index 00000000000..f89833af8e9 Binary files /dev/null and b/docs/images/adeearyaa.png differ diff --git a/docs/images/glemenneo.png b/docs/images/glemenneo.png new file mode 100644 index 00000000000..5a89dd29ea8 Binary files /dev/null and b/docs/images/glemenneo.png differ diff --git a/docs/images/jacobkwan.png b/docs/images/jacobkwan.png new file mode 100644 index 00000000000..cb41da9376b Binary files /dev/null and b/docs/images/jacobkwan.png differ diff --git a/docs/images/rylzxc.png b/docs/images/rylzxc.png new file mode 100644 index 00000000000..a0e1540a66a Binary files /dev/null and b/docs/images/rylzxc.png differ diff --git a/docs/images/tienyu2000.png b/docs/images/tienyu2000.png new file mode 100644 index 00000000000..e7a1d3c1ec8 Binary files /dev/null and b/docs/images/tienyu2000.png differ diff --git a/docs/index.md b/docs/index.md index 7601dbaad0d..fd9dabdda29 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,19 +1,26 @@ --- layout: page -title: AddressBook Level-3 +title: WorkBook --- -[![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) +[![Java CI](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml/badge.svg)](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml) +[![codecov](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp/branch/master/graph/badge.svg?token=K13DUI69HX)](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp) ![Ui](images/Ui.png) -**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). +* WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications. -* 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. +* WorkBook (WB) 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, WB can get your internship management tasks done faster than traditional GUI apps. + +* If you are interested in using WorkBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). +* If you are interested about developing WorkBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. **Acknowledgements** -* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5) +* Libraries used: [JavaFX](https://openjfx.io), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5). +* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org). +* User Guide: Table of Contents with bullet points removed is reused from [@ianyong's team in 2020](https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7). +* Reused [code](https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110) from CS2103T-T10-4 to parse optional arguments. +* Reused [code](https://github.com/se-edu/addressbook-level4/blob/master/src/main/java/seedu/address/model/VersionedAddressBook.java) from AddressBook-Level4 + diff --git a/docs/team/adeearyaa.md b/docs/team/adeearyaa.md new file mode 100644 index 00000000000..99d2608bf0c --- /dev/null +++ b/docs/team/adeearyaa.md @@ -0,0 +1,51 @@ +--- +layout: page +title: Adee Aryaa's Project Portfolio Page +--- + +## Project: WorkBook + +### Overview + +WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, 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, WB can get your internship management tasks done faster than traditional GUI apps. + +### Summary of contributions + +#### Code contributed + +This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=adeearyaa&breakdown=true) + +#### Enhancements implemented +- New Feature: [Find](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/87): Added the find function which allows internships to be displayed and filtered according to keywords. +- New Feature: [Standardized user's inputs](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/81): Converting the user's input for attributes to a standardized pascal case format. + + +#### Contributions to User Guide +- Added the Glossary. +- Added the summary of prefixes. +- Added the value proposition. +- Improved the tone of the user guide to make it more appealing to readers. +- Added boxes categorized according to tips, good to know and warning categories +- PR for the addition of the features above: [User Guide Changes](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/150) +- Added the implementation of the find command to the User Guide: [Find User Guide](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/97) +- Added images to the user guide to make it more clear for users: [Images User Guide](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/164) + +#### Contributions to Developer Guide +- Added user stories: [Update User Stories](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/31) +- Added use cases: [Update Use Cases](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/75) +- Added Find Command's implementation: [Find Command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/179) + +#### Contributions to team-based tasks +- [Testing](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/81): Added attributes for internships and test code. +- [Another example of adding test files](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/87/commits/f02d66f84d1029f6460cebe3fd6778676b394df2) +- Refactoring attributes of AB3 : [Deleting Phone Attribute](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/64) +- Refactoring attributes of AB3 : [Deleting address attribute](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/55) +- Refactoring attributes of AB3 : [Making email field optional](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/66) + +#### Review/mentoring contributions +- Reviewed a few PRs made by my teammates. +- Merged a few PRs as well. + +#### Contributions beyond the project team +- Reported an above average amount of bugs in the PE-D(12) +- Asked questions on the forum which ended up helping others who were in the same situation. diff --git a/docs/team/glemenneo.md b/docs/team/glemenneo.md new file mode 100644 index 00000000000..bbce5deb073 --- /dev/null +++ b/docs/team/glemenneo.md @@ -0,0 +1,42 @@ +--- +layout: page +title: Glemen Neo's Project Portfolio Page +--- + +## Project: WorkBook + +### Overview + +WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, 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, WB can get your internship management tasks done faster than traditional GUI apps. + +### Summary of contributions + +- Principle UI/UX engineer, implemented almost all UI changes from AB3 to WB. + +#### Code contributed + +This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=glemenneo&breakdown=true) + +#### Enhancements implemented + +- [Help Window](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/56): Redesigned Help window with summary of commands. +- [Internship Card](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/88): Redesigned Internship card to better fit WB. +- [Responsive UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/92): Implemented Responsive UI that switches between narrow and wide UI formats depending on window width. +- [Narrow UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/88): Implemented the Tips window and Tips button for narrow UI format. +- [Wide UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/92): Implemented the Tips panel for wide UI format. + +#### Contributions to User Guide + +- [Refactoring](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/30): Updated UG from AB3 to WB by refactoring to provide the skeleton for other to add on. +- [Edit Command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/42): Added section on Edit command. +- [Tips and Responsive UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/56): Added sections on and accessing Tips and Responsive UI. + +#### Contributions to Developer Guide + +- [User Stories and Use Cases](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/77): Added User Stories and Use Cases for Tips. +- [Help Window](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/177): Added section on Help window. +- [Tips and Responsive UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/169): Added section on Tips button, Tips window, Tips panel and Responsive UI. + +#### Contributions to team-based tasks + +- [Refactoring](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/30): Refactored UG from AB3 to WB by to provide the skeleton for other to add on. diff --git a/docs/team/jacobkwan.md b/docs/team/jacobkwan.md new file mode 100644 index 00000000000..cf4d637b6d1 --- /dev/null +++ b/docs/team/jacobkwan.md @@ -0,0 +1,44 @@ +--- +layout: page +title: Jacob Kwan's Project Portfolio Page +--- + +## Project: WorkBook + +### Overview + +WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, 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, WB can get your internship management tasks done faster than traditional GUI apps. + +#### Code contributed + +This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=jacobkwan&breakdown=true) + +#### Enhancements implemented +- [New Feature: Default WorkBook state of having internship applications sorted by date](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/83) +- [New Feature: Adding Language Tags](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/89) + +#### Contributions to User Guide +- Overall refinement of tone and structure +- [Miscellaneous bug fixing](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/167) +- [Usage of `delete`](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/38) +- [Command summary](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/100/files) + +#### Contributions to Developer Guide +- [Added instructions for manual testing](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/173) +- NFRs +- Glossary + +#### Contributions to team-based tasks +- [Refactoring](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/53): Changed project structure, class names and variable names to fit our product. +- Documentation: Utilised local Jekyll server to improve iteration speed for everyone + - Instead of merging and deploying buggy/incorrectly formatted markdown, I can simply checkout teammates' branches to verify the correctness of more complex markdown elements + - [Example PR review](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/170) + +#### Review/mentoring contributions +- Integration: Managed team repo, handled releases. +- Reviewed a bulk of the pull requests (45+) to maintain code quality and initiate discussions where applicable. + - [Example of a non trivial PR review](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/87) + - [Another example](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/152) + +#### Contributions beyond the project team +- Reported an above average number of bugs in the [PE-D](https://github.com/jacobkwan/ped/issues) (12) 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/rylzxc.md b/docs/team/rylzxc.md new file mode 100644 index 00000000000..1d6d162e917 --- /dev/null +++ b/docs/team/rylzxc.md @@ -0,0 +1,62 @@ +--- +layout: page +title: Daryl Chua's Project Portfolio Page +--- + +## Project: WorkBook + +### Overview + +WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, 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, WB can get your internship management tasks done faster than traditional GUI apps. + +### Summary of contributions + +#### Role in team + +Team lead: Overall in charge of the project, setting direction, keeping to deadlines and making important design decisions for the project. + +#### Code contributed +This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=rylzxc&breakdown=true) + +#### Enhancements implemented +- New Feature: Adding [Date and Time field](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/65) for each internship application +- New Feature: Adding [Stage field](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/58) to track internship application progress + +#### Contributions to User Guide +- Overall tone, language and structure coordination +- Introduce [numbering to table of contents](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/151) +- Contribute to documenting: + - ['Introducing WorkBook' & 'Getting Started'](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/153) + - ['Parameter-specific behaviour' & 'Behaviour of sorted internship applications'](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/145) + - ['Add' & 'Edit' commands](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/165) + - ['Managing your data' & 'Frequently Asked Questions'](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/145) + +#### Contributions to Developer Guide +- [`Add` command feature description, design considerations and class diagram](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/162) +- [Update user stories](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/76) +- [Use-case documentation](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/32/files) contributions to: + - Add an internship application + - Delete an internship application + - Edit an internship application + - Clear list of internship applications + - Display help message + - Exit application + +#### Contributions to team-based tasks + +* Set-up team repo +* Maintain issue tracker & manage milestones +* Release management +* Liaise with professor and tutor to clarify tasks requirements + +#### Review/mentoring contributions + +* Jacob and I vet PRs, giving as much constructive feedback as possible before merging into the team repo + +#### Contributions beyond the project team + +* Aided in the [CATcher forums on Markdown styling](https://github.com/CATcher-org/CATcher/issues/1023) +* Aided in solving [JUnit with Gradle](https://github.com/nus-cs2103-AY2223S1/forum/issues/79) issue in IntelliJ configuration error for iP +* Aided in [answering quiz related question](https://github.com/nus-cs2103-AY2223S1/forum/issues/6) +* Aided in [answering iP related issues](https://github.com/nus-cs2103-AY2223S1/forum/issues/82) +* Aided in [OOP suggestion](https://github.com/nus-cs2103-AY2223S1/forum/issues/180) diff --git a/docs/team/tienyu2000.md b/docs/team/tienyu2000.md new file mode 100644 index 00000000000..882858322c2 --- /dev/null +++ b/docs/team/tienyu2000.md @@ -0,0 +1,147 @@ +--- +layout: page +title: Tien's Project Portfolio Page +--- + +## Project: Workbook + +### Overview + +WorkBook is an internship application tracker that helps Computing students prepare sufficiently +for their upcoming interviews to secure that internship. We also ensure that you never miss an +interview or an application deadline ever again! +Workbook is optimized for fast typists and utilizes a Command Line Interface (CLI) style while +still having the benefits of a Graphical User Interface (GUI). + +### Summary of Contributions + +#### Code contributed +Code contributions for the project: [RepoSense Link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=tienyu2000&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-09-16&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + +#### Enhancements implemented + +- Major enhancement: added the ability to `undo` previous undoable command + - What it does: allows the user to undo previous undoable commands one at a time. + - Justification: This feature significantly improves the product by providing the user with a convenient way to rectify mistakes in commands. + - Highlights: This enhancement affected existing commands and was challenging to implement as it required changes to existing commands. + +- Major enhancement: added the ability to `redo` previous `undo` command + - What it does: allows the user to redo previous undo commands one at a time. + - Justification: This feature significantly improves the product by providing the user with a convenient way to rectify mistakes in undo commands. + +- Minor enhancement: added a delete command + - What it does: allow the user to delete an existing internship application + - Justification: This feature allows the user to remove an existing internship application from the WorkBook. + + +#### Contributions to User Guide +Added the implementation of the following commands to the User Guide: +- `undo` : [Undoing a command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/154) +- `redo`: [Redoing a command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/154) + +#### Contributions to Developer Guide +- Outlined the design of the application +- `Undo` and `Redo` command [feature implementation, design considerations, +sequence diagrams, state diagrams and activity diagrams](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/98) +- Use-case documentation contributions to UC06 - [Redo a command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/79) +- User-stories documentation contributions to: + - As a student who constantly changes my mind, I want to [redo an undone command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/79) so that I can revert + back the changes I had originally made. + + + +#### Contributions to team-based tasks +- Updated [UML diagrams](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/98) in Developer's Guide + +#### Contributions beyond the project team +[PE-D bugs reported in other team's products](https://github.com/tienyu2000/ped/issues) + +
+ +#### Contributions to User Guide (Extracts) + +1. Feature description + + #### Undoing your previous command + What if you accidentally made a mistake and performed a wrong undoable command? +Workbook can help you to undo your changes after performing an +undesirable undoable command and restore itself to the +previous version! + + WorkBook keeps track of all your previous undoable commands and its current version, allowing you to `undo` as many times +to restore any desired state of your WorkBook. + + Format: `undo` + * Undo the previous undoable command. + * You can perform the `undo` command as many times as the number of tracked Workbook versions + i.e. stacking 2 undo commands sequentially will revert the WorkBook back 2 + versions ago, assuming you performed at least 2 undoable commands previously! + * When you perform an undoable command, it will be stacked on top of the + previous undoable command in the stack. The `undo` command will undo the first undoable command at the + top of the stack. + * If you have not executed an undoable command previously, the WorkBook will remain in its current version + and return an error message: "No previous changes to undo!". + + +2. Screenshot images + + + ![AfterUndo1](../images/AfterUndo1.png) + +
+ +#### Contributions to Developer Guide (Extracts) + +1. Undo/Redo Feature + + The undo feature allows for users to revert back to their previous undone state in the Workbook. +The redo feature complements the undo feature by allowing users to restore to its previous changed state following an undo command. + +2. Implementation + + The undo/redo mechanism is facilitated by `VersionedWorkBook`. It extends `WorkBook` with an undo/redo history, stored internally as an `workBookStateList` and `currentStatePointer`. Additionally, it implements the following operations: + + * `VersionedWorkBook#commit()` — Saves the current work book state in its history. + * `VersionedWorkBook#undo()` — Restores the previous work book state from its history. + * `VersionedWorkBook#redo()` — Restores a previously undone work book state from its history. + + These operations are exposed in the `Model` interface as `Model#commitWorkBook()`, `Model#undoWorkBook()` and `Model#redoWorkBook()` 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 `VersionedWorkBook` will be initialized with the initial work book state, and the `currentStatePointer` pointing to that single work book state. + + Step 2. The user executes `delete 5` command to delete the 5th internship in the work book. The `delete` command calls `Model#commitWorkBook()`, causing the modified state of the work book after the `delete 5` command executes to be saved in the `workBookStateList`, and the `currentStatePointer` is shifted to the newly inserted work book state. + + Step 3. The user executes `add c/COMPANY …​` to add a new internship. The `add` command also calls `Model#commitWorkBook()`, causing another modified work book state to be saved into the `workBookStateList`. + + Step 4. The user now decides that adding the internship was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoWorkBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous work book state, and restores the work book to that state. + + Step 5. The user now decides that undoing the added internship was a mistake, and decides to redo that action by executing the `redo` command. The `redo` command will call `Model#redoWorkBook()`, which will shift the `currentStatePointer` once to the right, pointing it to the previous undone work book state, and restores the work book to that state. + + Step 6. The user then decides to execute the command `list`. Commands that do not modify the work book, such as `list`, will usually not call `Model#commitWorkBook()`, `Model#undoWorkBook()` or `Model#redoWorkBook()`. Thus, the `workBookStateList` remains unchanged. + + Step 7. The user executes `clear`, which calls `Model#commitWorkBook()`. Since the `currentStatePointer` is not pointing at the end of the `workBookStateList`, all work book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add c/COMPANY …​` command. This is the behavior that most modern desktop applications follow. + + Design considerations: + + **Aspect: How undo & redo executes:** + + * **Alternative 1 (current choice):** Saves the entire work book. + * Pros: Easy to implement. + * Cons: May have performance issues in terms of memory usage. + + * **Alternative 2:** Individual command knows how to undo/redo by + itself. + * Pros: Will use less memory (e.g. for `delete`, just save the internship being deleted). + * Cons: We must ensure that the implementation of each individual command are correct. + + +3. UML diagrams + +![UndoRedoState6](../images/UndoRedoState6.png) + + +![UndoSequenceDiagram](../images/UndoSequenceDiagram.png) + + diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java deleted file mode 100644 index 1deb3a1e469..00000000000 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ /dev/null @@ -1,13 +0,0 @@ -package seedu.address.commons.core; - -/** - * Container for user visible messages. - */ -public class Messages { - - public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; - public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; - public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; - public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; - -} diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java deleted file mode 100644 index 92cd8fa605a..00000000000 --- a/src/main/java/seedu/address/logic/Logic.java +++ /dev/null @@ -1,50 +0,0 @@ -package seedu.address.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; - -/** - * API of the Logic component - */ -public interface Logic { - /** - * Executes the command and returns the result. - * @param commandText The command as entered by the user. - * @return the result of the command execution. - * @throws CommandException If an error occurs during command execution. - * @throws ParseException If an error occurs during parsing. - */ - CommandResult execute(String commandText) throws CommandException, ParseException; - - /** - * Returns the AddressBook. - * - * @see seedu.address.model.Model#getAddressBook() - */ - ReadOnlyAddressBook getAddressBook(); - - /** Returns an unmodifiable view of the filtered list of persons */ - ObservableList getFilteredPersonList(); - - /** - * Returns the user prefs' address book file path. - */ - Path getAddressBookFilePath(); - - /** - * Returns the user prefs' GUI settings. - */ - GuiSettings getGuiSettings(); - - /** - * Set the user prefs' GUI settings. - */ - void setGuiSettings(GuiSettings guiSettings); -} 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/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java deleted file mode 100644 index 02fd256acba..00000000000 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -package seedu.address.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; - -/** - * Deletes a person identified using it's displayed index from the address book. - */ -public class DeleteCommand extends Command { - - public static final String COMMAND_WORD = "delete"; - - public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Deletes the person identified by the index number used in the displayed person list.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; - - public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; - - private final Index targetIndex; - - public DeleteCommand(Index targetIndex) { - this.targetIndex = targetIndex; - } - - @Override - public CommandResult execute(Model model) throws CommandException { - requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); - - if (targetIndex.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - Person personToDelete = lastShownList.get(targetIndex.getZeroBased()); - model.deletePerson(personToDelete); - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); - } - - @Override - 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 - } -} diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java deleted file mode 100644 index 7e36114902f..00000000000 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ /dev/null @@ -1,226 +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 static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import seedu.address.commons.core.Messages; -import seedu.address.commons.core.index.Index; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; -import seedu.address.model.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; - -/** - * Edits the details of an existing person in the address book. - */ -public class EditCommand extends Command { - - public static final String COMMAND_WORD = "edit"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified " - + "by the index number used in the displayed person list. " - + "Existing values will be overwritten by the input values.\n" - + "Parameters: INDEX (must be a positive integer) " - + "[" + PREFIX_NAME + "NAME] " - + "[" + PREFIX_PHONE + "PHONE] " - + "[" + PREFIX_EMAIL + "EMAIL] " - + "[" + PREFIX_ADDRESS + "ADDRESS] " - + "[" + PREFIX_TAG + "TAG]...\n" - + "Example: " + COMMAND_WORD + " 1 " - + PREFIX_PHONE + "91234567 " - + PREFIX_EMAIL + "johndoe@example.com"; - - 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."; - - private final Index index; - private final EditPersonDescriptor editPersonDescriptor; - - /** - * @param index of the person in the filtered person list to edit - * @param editPersonDescriptor details to edit the person with - */ - public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) { - requireNonNull(index); - requireNonNull(editPersonDescriptor); - - this.index = index; - this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor); - } - - @Override - public CommandResult execute(Model model) throws CommandException { - requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); - - if (index.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); - - if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); - } - - model.setPerson(personToEdit, editedPerson); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); - } - - /** - * 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; - - Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName()); - Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); - Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); - Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); - Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); - - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); - } - - @Override - public boolean equals(Object other) { - // short circuit if same object - if (other == this) { - return true; - } - - // instanceof handles nulls - if (!(other instanceof EditCommand)) { - return false; - } - - // state check - EditCommand e = (EditCommand) other; - 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. - */ - public static class EditPersonDescriptor { - private Name name; - private Phone phone; - private Email email; - private Address address; - private Set tags; - - public EditPersonDescriptor() {} - - /** - * 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); - setTags(toCopy.tags); - } - - /** - * Returns true if at least one field is edited. - */ - public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); - } - - public void setName(Name name) { - this.name = name; - } - - public Optional getName() { - return Optional.ofNullable(name); - } - - public void setPhone(Phone phone) { - this.phone = phone; - } - - public Optional getPhone() { - return Optional.ofNullable(phone); - } - - public void setEmail(Email email) { - this.email = email; - } - - public Optional getEmail() { - return Optional.ofNullable(email); - } - - public void setAddress(Address address) { - this.address = address; - } - - public Optional
getAddress() { - return Optional.ofNullable(address); - } - - /** - * 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. - */ - public Optional> getTags() { - return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); - } - - @Override - public boolean equals(Object other) { - // short circuit if same object - if (other == this) { - return true; - } - - // instanceof handles nulls - if (!(other instanceof EditPersonDescriptor)) { - return false; - } - - // state check - EditPersonDescriptor e = (EditPersonDescriptor) other; - - return getName().equals(e.getName()) - && getPhone().equals(e.getPhone()) - && getEmail().equals(e.getEmail()) - && getAddress().equals(e.getAddress()) - && getTags().equals(e.getTags()); - } - } -} diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java deleted file mode 100644 index d6b19b0a0de..00000000000 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; - -import seedu.address.commons.core.Messages; -import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; - -/** - * Finds and lists all persons in address book 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" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; - - private final NameContainsKeywordsPredicate predicate; - - public FindCommand(NameContainsKeywordsPredicate 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.getFilteredPersonList().size())); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof FindCommand // instanceof handles nulls - && predicate.equals(((FindCommand) other).predicate)); // state check - } -} diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java deleted file mode 100644 index 84be6ad2596..00000000000 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; - -import seedu.address.model.Model; - -/** - * Lists all persons in the address book to the user. - */ -public class ListCommand extends Command { - - public static final String COMMAND_WORD = "list"; - - public static final String MESSAGE_SUCCESS = "Listed all persons"; - - - @Override - public CommandResult execute(Model model) { - requireNonNull(model); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(MESSAGE_SUCCESS); - } -} diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java deleted file mode 100644 index 3b8bfa035e8..00000000000 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; - -import java.util.Set; -import java.util.stream.Stream; - -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; -import seedu.address.model.tag.Tag; - -/** - * Parses input arguments and creates a new AddCommand object - */ -public class AddCommandParser implements Parser { - - /** - * Parses the given {@code String} of arguments in the context of the AddCommand - * and returns an AddCommand object for execution. - * @throws ParseException if the user input does not conform the expected format - */ - public AddCommand parse(String args) throws ParseException { - ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); - - if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL) - || !argMultimap.getPreamble().isEmpty()) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); - } - - Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); - Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); - Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); - Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()); - Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); - - Person person = new Person(name, phone, email, address, tagList); - - return new AddCommand(person); - } - - /** - * Returns true if none of the prefixes contains empty {@code Optional} values in the given - * {@code ArgumentMultimap}. - */ - private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { - return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); - } - -} diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java deleted file mode 100644 index 75b1a9bf119..00000000000 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ /dev/null @@ -1,15 +0,0 @@ -package seedu.address.logic.parser; - -/** - * Contains Command Line Interface (CLI) syntax definitions common to multiple commands - */ -public class CliSyntax { - - /* Prefix definitions */ - public static final Prefix PREFIX_NAME = new Prefix("n/"); - public static final Prefix PREFIX_PHONE = new Prefix("p/"); - public static final Prefix PREFIX_EMAIL = new Prefix("e/"); - public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); - public static final Prefix PREFIX_TAG = new Prefix("t/"); - -} diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java deleted file mode 100644 index 845644b7dea..00000000000 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ /dev/null @@ -1,82 +0,0 @@ -package seedu.address.logic.parser; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.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.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; - -/** - * Parses input arguments and creates a new EditCommand object - */ -public class EditCommandParser implements Parser { - - /** - * Parses the given {@code String} of arguments in the context of the EditCommand - * and returns an EditCommand object for execution. - * @throws ParseException if the user input does not conform the expected format - */ - public EditCommand parse(String args) throws ParseException { - requireNonNull(args); - ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); - - Index index; - - try { - index = ParserUtil.parseIndex(argMultimap.getPreamble()); - } catch (ParseException pe) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); - } - - EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor(); - if (argMultimap.getValue(PREFIX_NAME).isPresent()) { - editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get())); - } - if (argMultimap.getValue(PREFIX_PHONE).isPresent()) { - editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get())); - } - if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { - editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); - } - if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { - editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); - } - parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); - - if (!editPersonDescriptor.isAnyFieldEdited()) { - throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); - } - - return new EditCommand(index, editPersonDescriptor); - } - - /** - * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty. - * If {@code tags} contain only one element which is an empty string, it will be parsed into a - * {@code Set} containing zero tags. - */ - private Optional> parseTagsForEdit(Collection tags) throws ParseException { - assert tags != null; - - if (tags.isEmpty()) { - return Optional.empty(); - } - Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags; - return Optional.of(ParserUtil.parseTags(tagSet)); - } - -} diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java deleted file mode 100644 index 4fb71f23103..00000000000 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ /dev/null @@ -1,33 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.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; - -/** - * Parses input arguments and creates a new FindCommand object - */ -public class FindCommandParser 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 FindCommand parse(String args) throws ParseException { - String trimmedArgs = args.trim(); - if (trimmedArgs.isEmpty()) { - throw new ParseException( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); - } - - String[] nameKeywords = trimmedArgs.split("\\s+"); - - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); - } - -} diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java deleted file mode 100644 index 1a943a0781a..00000000000 --- a/src/main/java/seedu/address/model/AddressBook.java +++ /dev/null @@ -1,120 +0,0 @@ -package seedu.address.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; - -/** - * Wraps all data at the address-book level - * Duplicates are not allowed (by .isSamePerson comparison) - */ -public class AddressBook implements ReadOnlyAddressBook { - - private final UniquePersonList persons; - - /* - * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication - * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html - * - * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication - * among constructors. - */ - { - persons = new UniquePersonList(); - } - - public AddressBook() {} - - /** - * Creates an AddressBook using the Persons in the {@code toBeCopied} - */ - public AddressBook(ReadOnlyAddressBook toBeCopied) { - this(); - resetData(toBeCopied); - } - - //// list overwrite operations - - /** - * Replaces the contents of the person list with {@code persons}. - * {@code persons} must not contain duplicate persons. - */ - public void setPersons(List persons) { - this.persons.setPersons(persons); - } - - /** - * Resets the existing data of this {@code AddressBook} with {@code newData}. - */ - public void resetData(ReadOnlyAddressBook newData) { - requireNonNull(newData); - - setPersons(newData.getPersonList()); - } - - //// person-level operations - - /** - * Returns true if a person with the same identity as {@code person} exists in the address book. - */ - public boolean hasPerson(Person person) { - requireNonNull(person); - return persons.contains(person); - } - - /** - * Adds a person to the address book. - * The person must not already exist in the address book. - */ - public void addPerson(Person p) { - persons.add(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. - */ - public void setPerson(Person target, Person editedPerson) { - requireNonNull(editedPerson); - - persons.setPerson(target, editedPerson); - } - - /** - * Removes {@code key} from this {@code AddressBook}. - * {@code key} must exist in the address book. - */ - public void removePerson(Person key) { - persons.remove(key); - } - - //// util methods - - @Override - public String toString() { - return persons.asUnmodifiableObservableList().size() + " persons"; - // TODO: refine later - } - - @Override - public ObservableList getPersonList() { - return persons.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)); - } - - @Override - public int hashCode() { - return persons.hashCode(); - } -} 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/Address.java b/src/main/java/seedu/address/model/person/Address.java deleted file mode 100644 index 60472ca22a0..00000000000 --- a/src/main/java/seedu/address/model/person/Address.java +++ /dev/null @@ -1,57 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's address in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)} - */ -public class Address { - - public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank"; - - /* - * The first character of the address must not be a whitespace, - * otherwise " " (a blank string) becomes a valid input. - */ - public static final String VALIDATION_REGEX = "[^\\s].*"; - - public final String value; - - /** - * Constructs an {@code Address}. - * - * @param address A valid address. - */ - public Address(String address) { - requireNonNull(address); - checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); - value = address; - } - - /** - * Returns true if a given string is a valid email. - */ - public static boolean isValidAddress(String test) { - return test.matches(VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Address // instanceof handles nulls - && value.equals(((Address) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java deleted file mode 100644 index 79244d71cf7..00000000000 --- a/src/main/java/seedu/address/model/person/Name.java +++ /dev/null @@ -1,59 +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 name in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} - */ -public class Name { - - public static final String MESSAGE_CONSTRAINTS = - "Names should only contain alphanumeric characters and spaces, and it should not be blank"; - - /* - * The first character of the address must not be a whitespace, - * otherwise " " (a blank string) becomes a valid input. - */ - public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; - - public final String fullName; - - /** - * Constructs a {@code Name}. - * - * @param name A valid name. - */ - public Name(String name) { - requireNonNull(name); - checkArgument(isValidName(name), MESSAGE_CONSTRAINTS); - fullName = name; - } - - /** - * Returns true if a given string is a valid name. - */ - public static boolean isValidName(String test) { - return test.matches(VALIDATION_REGEX); - } - - - @Override - public String toString() { - return fullName; - } - - @Override - 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 - } - - @Override - public int hashCode() { - return fullName.hashCode(); - } - -} 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/Person.java b/src/main/java/seedu/address/model/person/Person.java deleted file mode 100644 index 8ff1d83fe89..00000000000 --- a/src/main/java/seedu/address/model/person/Person.java +++ /dev/null @@ -1,123 +0,0 @@ -package seedu.address.model.person; - -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import seedu.address.model.tag.Tag; - -/** - * Represents a Person in the address book. - * Guarantees: details are present and not null, field values are validated, immutable. - */ -public class Person { - - // Identity fields - private final Name name; - private final Phone phone; - private final Email email; - - // Data fields - private final Address address; - private final Set tags = new HashSet<>(); - - /** - * Every field must be present and not null. - */ - public Person(Name name, Phone phone, Email email, Address address, Set tags) { - requireAllNonNull(name, phone, email, address, tags); - this.name = name; - this.phone = phone; - this.email = email; - this.address = address; - this.tags.addAll(tags); - } - - public Name getName() { - return name; - } - - public Phone getPhone() { - return phone; - } - - public Email getEmail() { - return email; - } - - public Address getAddress() { - return address; - } - - /** - * Returns an immutable tag set, which throws {@code UnsupportedOperationException} - * if modification is attempted. - */ - public Set getTags() { - return Collections.unmodifiableSet(tags); - } - - /** - * Returns true if both persons have the same name. - * This defines a weaker notion of equality between two persons. - */ - public boolean isSamePerson(Person otherPerson) { - if (otherPerson == this) { - return true; - } - - return otherPerson != null - && otherPerson.getName().equals(getName()); - } - - /** - * Returns true if both persons have the same identity and data fields. - * This defines a stronger notion of equality between two persons. - */ - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - - if (!(other instanceof Person)) { - return false; - } - - Person otherPerson = (Person) other; - return otherPerson.getName().equals(getName()) - && otherPerson.getPhone().equals(getPhone()) - && otherPerson.getEmail().equals(getEmail()) - && otherPerson.getAddress().equals(getAddress()) - && otherPerson.getTags().equals(getTags()); - } - - @Override - public int hashCode() { - // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append(getName()) - .append("; Phone: ") - .append(getPhone()) - .append("; Email: ") - .append(getEmail()) - .append("; Address: ") - .append(getAddress()); - - Set tags = getTags(); - if (!tags.isEmpty()) { - builder.append("; Tags: "); - tags.forEach(builder::append); - } - return builder.toString(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java deleted file mode 100644 index 872c76b382f..00000000000 --- a/src/main/java/seedu/address/model/person/Phone.java +++ /dev/null @@ -1,53 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's phone number in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)} - */ -public class Phone { - - - public static final String MESSAGE_CONSTRAINTS = - "Phone numbers should only contain numbers, and it should be at least 3 digits long"; - public static final String VALIDATION_REGEX = "\\d{3,}"; - public final String value; - - /** - * Constructs a {@code Phone}. - * - * @param phone A valid phone number. - */ - public Phone(String phone) { - requireNonNull(phone); - checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS); - value = phone; - } - - /** - * Returns true if a given string is a valid phone number. - */ - public static boolean isValidPhone(String test) { - return test.matches(VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Phone // instanceof handles nulls - && value.equals(((Phone) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java deleted file mode 100644 index 0fee4fe57e6..00000000000 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ /dev/null @@ -1,137 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; - -import java.util.Iterator; -import java.util.List; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import seedu.address.model.person.exceptions.DuplicatePersonException; -import seedu.address.model.person.exceptions.PersonNotFoundException; - -/** - * A list of persons that enforces uniqueness between its elements and does not allow nulls. - * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of - * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is - * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so - * as to ensure that the person with exactly the same fields will be removed. - * - * Supports a minimal set of list operations. - * - * @see Person#isSamePerson(Person) - */ -public class UniquePersonList implements Iterable { - - private final ObservableList internalList = FXCollections.observableArrayList(); - private final ObservableList internalUnmodifiableList = - FXCollections.unmodifiableObservableList(internalList); - - /** - * Returns true if the list contains an equivalent person as the given argument. - */ - public boolean contains(Person toCheck) { - requireNonNull(toCheck); - return internalList.stream().anyMatch(toCheck::isSamePerson); - } - - /** - * Adds a person to the list. - * The person must not already exist in the list. - */ - public void add(Person toAdd) { - requireNonNull(toAdd); - if (contains(toAdd)) { - throw new DuplicatePersonException(); - } - internalList.add(toAdd); - } - - /** - * Replaces the person {@code target} in the list with {@code editedPerson}. - * {@code target} must exist in the list. - * The person identity of {@code editedPerson} must not be the same as another existing person in the list. - */ - public void setPerson(Person target, Person editedPerson) { - requireAllNonNull(target, editedPerson); - - int index = internalList.indexOf(target); - if (index == -1) { - throw new PersonNotFoundException(); - } - - if (!target.isSamePerson(editedPerson) && contains(editedPerson)) { - throw new DuplicatePersonException(); - } - - internalList.set(index, editedPerson); - } - - /** - * Removes the equivalent person from the list. - * The person must exist in the list. - */ - public void remove(Person toRemove) { - requireNonNull(toRemove); - if (!internalList.remove(toRemove)) { - throw new PersonNotFoundException(); - } - } - - public void setPersons(UniquePersonList replacement) { - requireNonNull(replacement); - internalList.setAll(replacement.internalList); - } - - /** - * Replaces the contents of this list with {@code persons}. - * {@code persons} must not contain duplicate persons. - */ - public void setPersons(List persons) { - requireAllNonNull(persons); - if (!personsAreUnique(persons)) { - throw new DuplicatePersonException(); - } - - internalList.setAll(persons); - } - - /** - * Returns the backing list as an unmodifiable {@code ObservableList}. - */ - public ObservableList asUnmodifiableObservableList() { - return internalUnmodifiableList; - } - - @Override - public Iterator iterator() { - return internalList.iterator(); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof UniquePersonList // instanceof handles nulls - && internalList.equals(((UniquePersonList) other).internalList)); - } - - @Override - public int hashCode() { - return internalList.hashCode(); - } - - /** - * Returns true if {@code persons} contains only unique persons. - */ - private boolean personsAreUnique(List persons) { - for (int i = 0; i < persons.size() - 1; i++) { - for (int j = i + 1; j < persons.size(); j++) { - if (persons.get(i).isSamePerson(persons.get(j))) { - return false; - } - } - } - return true; - } -} diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java deleted file mode 100644 index d7290f59442..00000000000 --- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java +++ /dev/null @@ -1,11 +0,0 @@ -package seedu.address.model.person.exceptions; - -/** - * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same - * identity). - */ -public class DuplicatePersonException extends RuntimeException { - public DuplicatePersonException() { - super("Operation would result in duplicate persons"); - } -} diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java deleted file mode 100644 index fa764426ca7..00000000000 --- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java +++ /dev/null @@ -1,6 +0,0 @@ -package seedu.address.model.person.exceptions; - -/** - * Signals that the operation is unable to find the specified person. - */ -public class PersonNotFoundException extends RuntimeException {} diff --git a/src/main/java/seedu/address/model/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/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java deleted file mode 100644 index 4599182b3f9..00000000000 --- a/src/main/java/seedu/address/storage/AddressBookStorage.java +++ /dev/null @@ -1,45 +0,0 @@ -package seedu.address.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; - -/** - * Represents a storage for {@link seedu.address.model.AddressBook}. - */ -public interface AddressBookStorage { - - /** - * Returns the file path of the data file. - */ - Path getAddressBookFilePath(); - - /** - * Returns AddressBook data as a {@link ReadOnlyAddressBook}. - * 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; - - /** - * @see #getAddressBookFilePath() - */ - Optional readAddressBook(Path filePath) throws DataConversionException, IOException; - - /** - * Saves the given {@link ReadOnlyAddressBook} 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; - - /** - * @see #saveAddressBook(ReadOnlyAddressBook) - */ - void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException; - -} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java deleted file mode 100644 index a6321cec2ea..00000000000 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ /dev/null @@ -1,109 +0,0 @@ -package seedu.address.storage; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; -import seedu.address.model.tag.Tag; - -/** - * Jackson-friendly version of {@link Person}. - */ -class JsonAdaptedPerson { - - public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!"; - - private final String name; - private final String phone; - private final String email; - private final String address; - private final List tagged = new ArrayList<>(); - - /** - * Constructs a {@code JsonAdaptedPerson} with the given person details. - */ - @JsonCreator - public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, - @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tagged") List tagged) { - this.name = name; - this.phone = phone; - this.email = email; - this.address = address; - if (tagged != null) { - this.tagged.addAll(tagged); - } - } - - /** - * Converts a given {@code Person} into this class for Jackson use. - */ - public JsonAdaptedPerson(Person source) { - name = source.getName().fullName; - phone = source.getPhone().value; - email = source.getEmail().value; - address = source.getAddress().value; - tagged.addAll(source.getTags().stream() - .map(JsonAdaptedTag::new) - .collect(Collectors.toList())); - } - - /** - * Converts this Jackson-friendly adapted person object into the model's {@code Person} object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted person. - */ - public Person toModelType() throws IllegalValueException { - final List personTags = new ArrayList<>(); - for (JsonAdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - - if (name == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName())); - } - if (!Name.isValidName(name)) { - throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS); - } - final Name modelName = new Name(name); - - if (phone == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName())); - } - if (!Phone.isValidPhone(phone)) { - throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS); - } - final Phone modelPhone = new Phone(phone); - - if (email == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName())); - } - if (!Email.isValidEmail(email)) { - throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS); - } - final Email modelEmail = new Email(email); - - if (address == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName())); - } - if (!Address.isValidAddress(address)) { - throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS); - } - final Address modelAddress = new Address(address); - - final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); - } - -} diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java deleted file mode 100644 index dfab9daaa0d..00000000000 --- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java +++ /dev/null @@ -1,80 +0,0 @@ -package seedu.address.storage; - -import static java.util.Objects.requireNonNull; - -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.commons.exceptions.IllegalValueException; -import seedu.address.commons.util.FileUtil; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.ReadOnlyAddressBook; - -/** - * A class to access AddressBook data stored as a json file on the hard disk. - */ -public class JsonAddressBookStorage implements AddressBookStorage { - - private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class); - - private Path filePath; - - public JsonAddressBookStorage(Path filePath) { - this.filePath = filePath; - } - - public Path getAddressBookFilePath() { - return filePath; - } - - @Override - public Optional readAddressBook() throws DataConversionException { - return readAddressBook(filePath); - } - - /** - * Similar to {@link #readAddressBook()}. - * - * @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 { - requireNonNull(filePath); - - Optional jsonAddressBook = JsonUtil.readJsonFile( - filePath, JsonSerializableAddressBook.class); - if (!jsonAddressBook.isPresent()) { - return Optional.empty(); - } - - try { - return Optional.of(jsonAddressBook.get().toModelType()); - } catch (IllegalValueException ive) { - logger.info("Illegal values found in " + filePath + ": " + ive.getMessage()); - throw new DataConversionException(ive); - } - } - - @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { - saveAddressBook(addressBook, filePath); - } - - /** - * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}. - * - * @param filePath location of the data. Cannot be null. - */ - public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException { - requireNonNull(addressBook); - requireNonNull(filePath); - - FileUtil.createIfMissing(filePath); - JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath); - } - -} 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/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java deleted file mode 100644 index beda8bd9f11..00000000000 --- a/src/main/java/seedu/address/storage/Storage.java +++ /dev/null @@ -1,32 +0,0 @@ -package seedu.address.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; - -/** - * API of the Storage component - */ -public interface Storage extends AddressBookStorage, UserPrefsStorage { - - @Override - Optional readUserPrefs() throws DataConversionException, IOException; - - @Override - void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException; - - @Override - Path getAddressBookFilePath(); - - @Override - Optional readAddressBook() throws DataConversionException, IOException; - - @Override - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; - -} diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java deleted file mode 100644 index 6cfa0162164..00000000000 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ /dev/null @@ -1,78 +0,0 @@ -package seedu.address.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; - -/** - * Manages storage of AddressBook data in local storage. - */ -public class StorageManager implements Storage { - - private static final Logger logger = LogsCenter.getLogger(StorageManager.class); - private AddressBookStorage addressBookStorage; - private UserPrefsStorage userPrefsStorage; - - /** - * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}. - */ - public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) { - this.addressBookStorage = addressBookStorage; - this.userPrefsStorage = userPrefsStorage; - } - - // ================ UserPrefs methods ============================== - - @Override - public Path getUserPrefsFilePath() { - return userPrefsStorage.getUserPrefsFilePath(); - } - - @Override - public Optional readUserPrefs() throws DataConversionException, IOException { - return userPrefsStorage.readUserPrefs(); - } - - @Override - public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException { - userPrefsStorage.saveUserPrefs(userPrefs); - } - - - // ================ AddressBook methods ============================== - - @Override - public Path getAddressBookFilePath() { - return addressBookStorage.getAddressBookFilePath(); - } - - @Override - public Optional readAddressBook() throws DataConversionException, IOException { - return readAddressBook(addressBookStorage.getAddressBookFilePath()); - } - - @Override - 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 { - saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath()); - } - - @Override - public void saveAddressBook(ReadOnlyAddressBook 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/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java deleted file mode 100644 index 7fc927bc5d9..00000000000 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ /dev/null @@ -1,77 +0,0 @@ -package seedu.address.ui; - -import java.util.Comparator; - -import javafx.fxml.FXML; -import javafx.scene.control.Label; -import javafx.scene.layout.FlowPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; -import seedu.address.model.person.Person; - -/** - * An UI component that displays information of a {@code Person}. - */ -public class PersonCard extends UiPart { - - private static final String FXML = "PersonListCard.fxml"; - - /** - * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. - * As a consequence, UI elements' variable names cannot be set to such keywords - * or an exception will be thrown by JavaFX during runtime. - * - * @see The issue on AddressBook level 4 - */ - - public final Person person; - - @FXML - private HBox cardPane; - @FXML - private Label name; - @FXML - private Label id; - @FXML - private Label phone; - @FXML - private Label address; - @FXML - private Label email; - @FXML - private FlowPane tags; - - /** - * Creates a {@code PersonCode} with the given {@code Person} and index to display. - */ - public PersonCard(Person person, int displayedIndex) { - super(FXML); - this.person = person; - id.setText(displayedIndex + ". "); - name.setText(person.getName().fullName); - phone.setText(person.getPhone().value); - address.setText(person.getAddress().value); - email.setText(person.getEmail().value); - person.getTags().stream() - .sorted(Comparator.comparing(tag -> tag.tagName)) - .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); - } - - @Override - public boolean equals(Object other) { - // short circuit if same object - if (other == this) { - return true; - } - - // instanceof handles nulls - if (!(other instanceof PersonCard)) { - return false; - } - - // state check - PersonCard card = (PersonCard) other; - return id.getText().equals(card.id.getText()) - && person.equals(card.person); - } -} diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java deleted file mode 100644 index f4c501a897b..00000000000 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ /dev/null @@ -1,49 +0,0 @@ -package seedu.address.ui; - -import java.util.logging.Logger; - -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.layout.Region; -import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; - -/** - * Panel containing the list of persons. - */ -public class PersonListPanel extends UiPart { - private static final String FXML = "PersonListPanel.fxml"; - private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); - - @FXML - private ListView personListView; - - /** - * Creates a {@code PersonListPanel} with the given {@code ObservableList}. - */ - public PersonListPanel(ObservableList personList) { - super(FXML); - personListView.setItems(personList); - personListView.setCellFactory(listView -> new PersonListViewCell()); - } - - /** - * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. - */ - class PersonListViewCell extends ListCell { - @Override - protected void updateItem(Person person, boolean empty) { - super.updateItem(person, empty); - - if (empty || person == null) { - setGraphic(null); - setText(null); - } else { - setGraphic(new PersonCard(person, getIndex() + 1).getRoot()); - } - } - } - -} diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/seedu/workbook/AppParameters.java similarity index 93% rename from src/main/java/seedu/address/AppParameters.java rename to src/main/java/seedu/workbook/AppParameters.java index ab552c398f3..f90f76a8d70 100644 --- a/src/main/java/seedu/address/AppParameters.java +++ b/src/main/java/seedu/workbook/AppParameters.java @@ -1,4 +1,4 @@ -package seedu.address; +package seedu.workbook; 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 seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.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/seedu/workbook/Main.java similarity index 97% rename from src/main/java/seedu/address/Main.java rename to src/main/java/seedu/workbook/Main.java index 052a5068631..82b6d177581 100644 --- a/src/main/java/seedu/address/Main.java +++ b/src/main/java/seedu/workbook/Main.java @@ -1,4 +1,4 @@ -package seedu.address; +package seedu.workbook; import javafx.application.Application; diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/workbook/MainApp.java similarity index 67% rename from src/main/java/seedu/address/MainApp.java rename to src/main/java/seedu/workbook/MainApp.java index 4133aaa0151..4d3ee4327ee 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/workbook/MainApp.java @@ -1,4 +1,4 @@ -package seedu.address; +package seedu.workbook; 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 seedu.workbook.commons.core.Config; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.commons.core.Version; +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.commons.util.ConfigUtil; +import seedu.workbook.commons.util.StringUtil; +import seedu.workbook.logic.Logic; +import seedu.workbook.logic.LogicManager; +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.ReadOnlyUserPrefs; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.util.SampleDataUtil; +import seedu.workbook.storage.JsonUserPrefsStorage; +import seedu.workbook.storage.JsonWorkBookStorage; +import seedu.workbook.storage.Storage; +import seedu.workbook.storage.StorageManager; +import seedu.workbook.storage.UserPrefsStorage; +import seedu.workbook.storage.WorkBookStorage; +import seedu.workbook.ui.Ui; +import seedu.workbook.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, 4, 1, true); private static final Logger logger = LogsCenter.getLogger(MainApp.class); @@ -48,7 +48,7 @@ public class MainApp extends Application { @Override public void init() throws Exception { - logger.info("=============================[ Initializing AddressBook ]==========================="); + logger.info("=============================[ Initializing WorkBook ]==========================="); super.init(); AppParameters appParameters = AppParameters.parse(getParameters()); @@ -56,8 +56,8 @@ public void init() throws Exception { UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath()); UserPrefs userPrefs = initPrefs(userPrefsStorage); - AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath()); - storage = new StorageManager(addressBookStorage, userPrefsStorage); + WorkBookStorage workBookStorage = new JsonWorkBookStorage(userPrefs.getWorkBookFilePath()); + storage = new StorageManager(workBookStorage, userPrefsStorage); initLogging(config); @@ -69,25 +69,25 @@ 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 work book and {@code userPrefs}.
+ * The data from the sample work book will be used instead if {@code storage}'s work book is not found, + * or an empty work book will be used instead if errors occur when reading {@code storage}'s work book. */ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { - Optional addressBookOptional; - ReadOnlyAddressBook initialData; + Optional workBookOptional; + ReadOnlyWorkBook initialData; try { - addressBookOptional = storage.readAddressBook(); - if (!addressBookOptional.isPresent()) { - logger.info("Data file not found. Will be starting with a sample AddressBook"); + workBookOptional = storage.readWorkBook(); + if (!workBookOptional.isPresent()) { + logger.info("Data file not found. Will be starting with a sample WorkBook"); } - initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook); + initialData = workBookOptional.orElseGet(SampleDataUtil::getSampleWorkBook); } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Data file not in the correct format. Will be starting with an empty WorkBook"); + initialData = new WorkBook(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Problem while reading from the file. Will be starting with an empty WorkBook"); + initialData = new WorkBook(); } return new ModelManager(initialData, userPrefs); @@ -151,7 +151,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { + "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with an empty WorkBook"); initializedPrefs = new UserPrefs(); } @@ -167,13 +167,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { @Override public void start(Stage primaryStage) { - logger.info("Starting AddressBook " + MainApp.VERSION); + logger.info("Starting WorkBook " + MainApp.VERSION); ui.start(primaryStage); } @Override public void stop() { - logger.info("============================ [ Stopping Address Book ] ============================="); + logger.info("============================ [ Stopping Work Book ] ============================="); try { storage.saveUserPrefs(model.getUserPrefs()); } catch (IOException e) { diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/workbook/commons/core/Config.java similarity index 97% rename from src/main/java/seedu/address/commons/core/Config.java rename to src/main/java/seedu/workbook/commons/core/Config.java index 91145745521..63b9001631d 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/seedu/workbook/commons/core/Config.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.workbook.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/seedu/workbook/commons/core/GuiSettings.java similarity index 98% rename from src/main/java/seedu/address/commons/core/GuiSettings.java rename to src/main/java/seedu/workbook/commons/core/GuiSettings.java index ba33653be67..53c7c5e8644 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/seedu/workbook/commons/core/GuiSettings.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.workbook.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/seedu/workbook/commons/core/LogsCenter.java similarity index 97% rename from src/main/java/seedu/address/commons/core/LogsCenter.java rename to src/main/java/seedu/workbook/commons/core/LogsCenter.java index 431e7185e76..0c1bf219a26 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/seedu/workbook/commons/core/LogsCenter.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.workbook.commons.core; import java.io.IOException; import java.util.Arrays; @@ -18,7 +18,7 @@ public class LogsCenter { private static final int MAX_FILE_COUNT = 5; private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB - private static final String LOG_FILE = "addressbook.log"; + private static final String LOG_FILE = "workbook.log"; private static Level currentLogLevel = Level.INFO; private static final Logger logger = LogsCenter.getLogger(LogsCenter.class); private static FileHandler fileHandler; diff --git a/src/main/java/seedu/workbook/commons/core/Messages.java b/src/main/java/seedu/workbook/commons/core/Messages.java new file mode 100644 index 00000000000..d9ea0952786 --- /dev/null +++ b/src/main/java/seedu/workbook/commons/core/Messages.java @@ -0,0 +1,13 @@ +package seedu.workbook.commons.core; + +/** + * Container for user visible messages. + */ +public class Messages { + + public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; + public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; + public static final String MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX = "The internship index provided is invalid"; + public static final String MESSAGE_INTERNSHIPS_LISTED_OVERVIEW = "%1$d internships listed!"; + +} diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/workbook/commons/core/Version.java similarity index 98% rename from src/main/java/seedu/address/commons/core/Version.java rename to src/main/java/seedu/workbook/commons/core/Version.java index 12142ec1e32..48e15d96cb7 100644 --- a/src/main/java/seedu/address/commons/core/Version.java +++ b/src/main/java/seedu/workbook/commons/core/Version.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.workbook.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/seedu/workbook/commons/core/index/Index.java similarity index 88% rename from src/main/java/seedu/address/commons/core/index/Index.java rename to src/main/java/seedu/workbook/commons/core/index/Index.java index 19536439c09..db4f996b6ba 100644 --- a/src/main/java/seedu/address/commons/core/index/Index.java +++ b/src/main/java/seedu/workbook/commons/core/index/Index.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core.index; +package seedu.workbook.commons.core.index; /** * Represents a zero-based or one-based index. @@ -33,6 +33,8 @@ public int getOneBased() { /** * Creates a new {@code Index} using a zero-based index. + * @param zeroBasedIndex Index from a zero-based indexing. + * @return Index */ public static Index fromZeroBased(int zeroBasedIndex) { return new Index(zeroBasedIndex); @@ -40,6 +42,8 @@ public static Index fromZeroBased(int zeroBasedIndex) { /** * Creates a new {@code Index} using a one-based index. + * @param oneBasedIndex Index from a one-based indexing + * @return Index */ public static Index fromOneBased(int oneBasedIndex) { return new Index(oneBasedIndex - 1); diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/workbook/commons/exceptions/DataConversionException.java similarity index 84% rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java rename to src/main/java/seedu/workbook/commons/exceptions/DataConversionException.java index 1f689bd8e3f..7b3e3387146 100644 --- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java +++ b/src/main/java/seedu/workbook/commons/exceptions/DataConversionException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.workbook.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/seedu/workbook/commons/exceptions/IllegalValueException.java similarity index 92% rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java rename to src/main/java/seedu/workbook/commons/exceptions/IllegalValueException.java index 19124db485c..105c7def179 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/seedu/workbook/commons/exceptions/IllegalValueException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.workbook.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/seedu/workbook/commons/util/AppUtil.java similarity index 80% rename from src/main/java/seedu/address/commons/util/AppUtil.java rename to src/main/java/seedu/workbook/commons/util/AppUtil.java index 87aa89c0326..550cb890cb5 100644 --- a/src/main/java/seedu/address/commons/util/AppUtil.java +++ b/src/main/java/seedu/workbook/commons/util/AppUtil.java @@ -1,9 +1,9 @@ -package seedu.address.commons.util; +package seedu.workbook.commons.util; import static java.util.Objects.requireNonNull; import javafx.scene.image.Image; -import seedu.address.MainApp; +import seedu.workbook.MainApp; /** * A container for App specific utility functions @@ -20,7 +20,7 @@ public static Image getImage(String imagePath) { /** * Checks that {@code condition} is true. Used for validating arguments to methods. - * + * @param condition Boolean condition to be checked. * @throws IllegalArgumentException if {@code condition} is false. */ public static void checkArgument(Boolean condition) { @@ -31,7 +31,8 @@ public static void checkArgument(Boolean condition) { /** * Checks that {@code condition} is true. Used for validating arguments to methods. - * + * @param condition Boolean condition to be checked. + * @param errorMessage Error message returned if {@code condition} is false. * @throws IllegalArgumentException with {@code errorMessage} if {@code condition} is false. */ public static void checkArgument(Boolean condition, String errorMessage) { diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/workbook/commons/util/CollectionUtil.java similarity index 84% rename from src/main/java/seedu/address/commons/util/CollectionUtil.java rename to src/main/java/seedu/workbook/commons/util/CollectionUtil.java index eafe4dfd681..26b50a93ff6 100644 --- a/src/main/java/seedu/address/commons/util/CollectionUtil.java +++ b/src/main/java/seedu/workbook/commons/util/CollectionUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.workbook.commons.util; import static java.util.Objects.requireNonNull; @@ -20,6 +20,7 @@ public static void requireAllNonNull(Object... items) { /** * Throws NullPointerException if {@code items} or any element of {@code items} is null. + * @param items Items of type Collection */ public static void requireAllNonNull(Collection items) { requireNonNull(items); @@ -28,6 +29,8 @@ public static void requireAllNonNull(Collection items) { /** * Returns true if {@code items} contain any elements that are non-null. + * @param items Items of type Object + * @return Boolean value checking for non-null items */ public static boolean isAnyNonNull(Object... items) { return items != null && Arrays.stream(items).anyMatch(Objects::nonNull); diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/workbook/commons/util/ConfigUtil.java similarity index 77% rename from src/main/java/seedu/address/commons/util/ConfigUtil.java rename to src/main/java/seedu/workbook/commons/util/ConfigUtil.java index f7f8a2bd44c..a41c1f93577 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/seedu/workbook/commons/util/ConfigUtil.java @@ -1,11 +1,11 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.commons.core.Config; +import seedu.workbook.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/seedu/workbook/commons/util/FileUtil.java similarity index 74% rename from src/main/java/seedu/address/commons/util/FileUtil.java rename to src/main/java/seedu/workbook/commons/util/FileUtil.java index b1e2767cdd9..8d45a904898 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/seedu/workbook/commons/util/FileUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.workbook.commons.util; import java.io.IOException; import java.nio.file.Files; @@ -18,7 +18,7 @@ public static boolean isFileExists(Path file) { } /** - * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)}, + * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths #get(String)}, * otherwise returns false. * @param path A string representing the file path. Cannot be null. */ @@ -32,7 +32,8 @@ public static boolean isValidPath(String path) { } /** - * Creates a file if it does not exist along with its missing parent directories. + * Creates a file if it does not exist. + * @param file File to be created. * @throws IOException if the file or directory cannot be created. */ public static void createIfMissing(Path file) throws IOException { @@ -43,6 +44,8 @@ public static void createIfMissing(Path file) throws IOException { /** * Creates a file if it does not exist along with its missing parent directories. + * @param file File to be created. + * @throws IOException if the file or directory cannot be created. */ public static void createFile(Path file) throws IOException { if (Files.exists(file)) { @@ -56,6 +59,8 @@ public static void createFile(Path file) throws IOException { /** * Creates parent directories of file if it has a parent directory + * @param file File to create parent directories. + * @throws IOException if the file or directory cannot be created. */ public static void createParentDirsOfFile(Path file) throws IOException { Path parentDir = file.getParent(); @@ -66,7 +71,9 @@ public static void createParentDirsOfFile(Path file) throws IOException { } /** - * Assumes file exists + * Reads from a file that exists. + * @param file File to be read from. + * @throws IOException if the file does not exist. */ public static String readFromFile(Path file) throws IOException { return new String(Files.readAllBytes(file), CHARSET); @@ -75,6 +82,9 @@ public static String readFromFile(Path file) throws IOException { /** * Writes given string to a file. * Will create the file if it does not exist yet. + * @param file File to be written to. + * @param content String to write to file. + * @throws IOException if the file or directory cannot be created. */ public static void writeToFile(Path file, String content) throws IOException { Files.write(file, content.getBytes(CHARSET)); diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/workbook/commons/util/JsonUtil.java similarity index 97% rename from src/main/java/seedu/address/commons/util/JsonUtil.java rename to src/main/java/seedu/workbook/commons/util/JsonUtil.java index 8ef609f055d..f20b2b36940 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/seedu/workbook/commons/util/JsonUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.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/seedu/workbook/commons/util/StringUtil.java similarity index 76% rename from src/main/java/seedu/address/commons/util/StringUtil.java rename to src/main/java/seedu/workbook/commons/util/StringUtil.java index 61cc8c9a1cb..719c5489007 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/workbook/commons/util/StringUtil.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package seedu.workbook.commons.util; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static seedu.workbook.commons.util.AppUtil.checkArgument; import java.io.PrintWriter; import java.io.StringWriter; @@ -65,4 +65,22 @@ public static boolean isNonZeroUnsignedInteger(String s) { return false; } } + + /** + * Converts a String to PascalCase but with whitespace preserved. + */ + public static String toPascalCase(String roleName) { + char[] chars = roleName.toLowerCase().toCharArray(); + boolean isNotWhitespace = false; + for (int i = 0; i < chars.length; i++) { + if (!isNotWhitespace && Character.isLetter(chars[i])) { + chars[i] = Character.toUpperCase(chars[i]); + isNotWhitespace = true; + + } else if (Character.isWhitespace(chars[i])) { + isNotWhitespace = false; + } + } + return String.valueOf(chars); + } } diff --git a/src/main/java/seedu/workbook/logic/Logic.java b/src/main/java/seedu/workbook/logic/Logic.java new file mode 100644 index 00000000000..54a8397805d --- /dev/null +++ b/src/main/java/seedu/workbook/logic/Logic.java @@ -0,0 +1,44 @@ +package seedu.workbook.logic; + +import java.nio.file.Path; + +import javafx.collections.ObservableList; +import seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.logic.commands.CommandResult; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.internship.Internship; + +/** + * API of the Logic component + */ +public interface Logic { + /** + * Executes the command and returns the result. + * @param commandText The command as entered by the user. + * @return the result of the command execution. + * @throws CommandException If an error occurs during command execution. + * @throws ParseException If an error occurs during parsing. + */ + CommandResult execute(String commandText) throws CommandException, ParseException; + + /** + * Returns the WorkBook. + * + * @see seedu.workbook.model.Model#getWorkBook() + */ + ReadOnlyWorkBook getWorkBook(); + + /** Returns an unmodifiable view of the filtered list of internships */ + ObservableList getFilteredInternshipList(); + + /** Returns the user prefs' work book file path. */ + Path getWorkBookFilePath(); + + /** Returns the user prefs' GUI settings. */ + GuiSettings getGuiSettings(); + + /** Set the user prefs' GUI settings. */ + void setGuiSettings(GuiSettings guiSettings); +} diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/workbook/logic/LogicManager.java similarity index 56% rename from src/main/java/seedu/address/logic/LogicManager.java rename to src/main/java/seedu/workbook/logic/LogicManager.java index 9d9c6d15bdc..9933a9ee340 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/workbook/logic/LogicManager.java @@ -1,21 +1,21 @@ -package seedu.address.logic; +package seedu.workbook.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 seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.logic.commands.Command; +import seedu.workbook.logic.commands.CommandResult; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.logic.parser.WorkBookParser; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.Model; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.storage.Storage; /** * The main LogicManager of the app. @@ -26,7 +26,7 @@ public class LogicManager implements Logic { private final Model model; private final Storage storage; - private final AddressBookParser addressBookParser; + private final WorkBookParser workBookParser; /** * Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}. @@ -34,7 +34,7 @@ public class LogicManager implements Logic { public LogicManager(Model model, Storage storage) { this.model = model; this.storage = storage; - addressBookParser = new AddressBookParser(); + workBookParser = new WorkBookParser(); } @Override @@ -42,11 +42,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE logger.info("----------------[USER COMMAND][" + commandText + "]"); CommandResult commandResult; - Command command = addressBookParser.parseCommand(commandText); + Command command = workBookParser.parseCommand(commandText); commandResult = command.execute(model); try { - storage.saveAddressBook(model.getAddressBook()); + storage.saveWorkBook(model.getWorkBook()); } catch (IOException ioe) { throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); } @@ -55,18 +55,18 @@ public CommandResult execute(String commandText) throws CommandException, ParseE } @Override - public ReadOnlyAddressBook getAddressBook() { - return model.getAddressBook(); + public ReadOnlyWorkBook getWorkBook() { + return model.getWorkBook(); } @Override - public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); + public ObservableList getFilteredInternshipList() { + return model.getFilteredInternshipList(); } @Override - public Path getAddressBookFilePath() { - return model.getAddressBookFilePath(); + public Path getWorkBookFilePath() { + return model.getWorkBookFilePath(); } @Override diff --git a/src/main/java/seedu/workbook/logic/commands/AddCommand.java b/src/main/java/seedu/workbook/logic/commands/AddCommand.java new file mode 100644 index 00000000000..ac4fcebf5fe --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/AddCommand.java @@ -0,0 +1,92 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.workbook.model.internship.util.StageUtil.stagesWithTipsToString; + +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.model.Model; +import seedu.workbook.model.internship.Internship; + +/** + * Adds an Internship to WorkBook. + */ +public class AddCommand extends Command { + + /** Command word to execute the add command */ + public static final String COMMAND_WORD = "add"; + + /** Help message to execute the add command */ + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an internship application to WorkBook.\n" + + "Parameters: " + + PREFIX_COMPANY + "COMPANY " + + PREFIX_ROLE + "ROLE " + + PREFIX_STAGE + "STAGE " + + "[" + PREFIX_DATETIME + "DATE AND TIME] " + + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_LANGUAGE_TAG + "PROGRAMMING LANGUAGE]... " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_COMPANY + "Meta " + + PREFIX_ROLE + "Software Engineer " + + PREFIX_STAGE + "Interview " + + PREFIX_DATETIME + "10-Dec-2022 12:10 " + + PREFIX_EMAIL + "hr@meta.com " + + PREFIX_LANGUAGE_TAG + "javascript " + + PREFIX_TAG + "MANGA " + + PREFIX_TAG + "frontend"; + + /** Message string displaying successful execution of the add command */ + public static final String MESSAGE_SUCCESS = "New internship application added: %1$s, " + + "check out some tips for the stage!"; + + /** Message string displaying successful execution of the add command, but stage is not in our pre-defined list */ + public static final String MESSAGE_SUCCESS_STAGE_NO_TIPS = "New internship application added: %1$s.\n" + + "However, do you mean " + stagesWithTipsToString() + " for the Stage? \nWe curated " + + "some nifty tips for those stages!"; + + /** Message string displaying error message for unsuccessful execution of the add command for a duplicate */ + public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship application already exists in WorkBook"; + + /** Internship to be added to work book */ + private final Internship toAdd; + + /** + * Creates an AddCommand to add the specified {@code Internship} + */ + public AddCommand(Internship internship) { + requireNonNull(internship); + toAdd = internship; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasInternship(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP); + } + + model.addInternship(toAdd); + model.commitWorkBook(); + + if (toAdd.stageHasNoTips()) { + return new CommandResult(String.format(MESSAGE_SUCCESS_STAGE_NO_TIPS, toAdd)); + } else { + 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/workbook/logic/commands/ClearCommand.java b/src/main/java/seedu/workbook/logic/commands/ClearCommand.java new file mode 100644 index 00000000000..a08930dd70f --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/ClearCommand.java @@ -0,0 +1,26 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; + +import seedu.workbook.model.Model; +import seedu.workbook.model.WorkBook; + +/** + * Clears the WorkBook. + */ +public class ClearCommand extends Command { + + /** Command word to execute the clear command */ + public static final String COMMAND_WORD = "clear"; + + /** Message string displaying successful execution of the clear command */ + public static final String MESSAGE_SUCCESS = "Work book has been cleared!"; + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.setWorkBook(new WorkBook()); + model.commitWorkBook(); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/workbook/logic/commands/Command.java similarity index 78% rename from src/main/java/seedu/address/logic/commands/Command.java rename to src/main/java/seedu/workbook/logic/commands/Command.java index 64f18992160..84e263777d7 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/seedu/workbook/logic/commands/Command.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands; +package seedu.workbook.logic.commands; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.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/seedu/workbook/logic/commands/CommandResult.java similarity index 97% rename from src/main/java/seedu/address/logic/commands/CommandResult.java rename to src/main/java/seedu/workbook/logic/commands/CommandResult.java index 92f900b7916..68e7523796d 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/workbook/logic/commands/CommandResult.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package seedu.workbook.logic.commands; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/seedu/workbook/logic/commands/DeleteCommand.java b/src/main/java/seedu/workbook/logic/commands/DeleteCommand.java new file mode 100644 index 00000000000..df5894a38bb --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/DeleteCommand.java @@ -0,0 +1,58 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import seedu.workbook.commons.core.Messages; +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.model.Model; +import seedu.workbook.model.internship.Internship; + +/** + * Deletes a internship identified using it's displayed index from the WorkBook. + */ +public class DeleteCommand extends Command { + + /** Command word to execute the delete command */ + public static final String COMMAND_WORD = "delete"; + + /** Help message to execute the delete command */ + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the internship identified by the index number used in the displayed internship list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + /** Message string displaying successful execution of the delete command */ + public static final String MESSAGE_DELETE_INTERNSHIP_SUCCESS = "Deleted Internship: %1$s"; + + /** Index of internship to be deleted */ + private final Index targetIndex; + + public DeleteCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredInternshipList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); + } + + Internship internshipToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteInternship(internshipToDelete); + model.commitWorkBook(); + return new CommandResult(String.format(MESSAGE_DELETE_INTERNSHIP_SUCCESS, internshipToDelete)); + } + + @Override + 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 + } +} diff --git a/src/main/java/seedu/workbook/logic/commands/EditCommand.java b/src/main/java/seedu/workbook/logic/commands/EditCommand.java new file mode 100644 index 00000000000..2105f47c066 --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/EditCommand.java @@ -0,0 +1,287 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import seedu.workbook.commons.core.Messages; +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.commons.util.CollectionUtil; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.model.Model; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.tag.Tag; + +/** + * Edits the details of an existing internship in the WorkBook. + */ +public class EditCommand extends Command { + + /** Command word to execute the edit command */ + public static final String COMMAND_WORD = "edit"; + + /** Help message to execute the edit command */ + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the internship identified " + + "by the index number used in the displayed internship list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_COMPANY + "COMPANY] " + + "[" + PREFIX_ROLE + "ROLE] " + + "[" + PREFIX_STAGE + "STAGE] " + + "[" + PREFIX_DATETIME + "DATE AND TIME] " + + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_LANGUAGE_TAG + "PROGRAMMING LANGUAGE]... " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_EMAIL + "johndoe@example.com"; + + /** Message string displaying successful execution of the edit command */ + public static final String MESSAGE_EDIT_INTERNSHIP_SUCCESS = "Edited Internship: %1$s"; + + /** + * Message string displaying error message for unsuccessful execution of the edit command + * for invalid input field + */ + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; + + /** + * Message string displaying error message for unsuccessful execution of the edit command + * for a duplicate internship + */ + public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship already exists in the work book."; + + /** Index of the internship to be edited */ + private final Index index; + + /** Description of edit */ + private final EditInternshipDescriptor editInternshipDescriptor; + + /** + * Updates an indexed internship in the filtered internship list. + * @param index of the internship in the filtered internship list to edit + * @param editInternshipDescriptor details to edit the internship with + */ + public EditCommand(Index index, EditInternshipDescriptor editInternshipDescriptor) { + requireNonNull(index); + requireNonNull(editInternshipDescriptor); + + this.index = index; + this.editInternshipDescriptor = new EditInternshipDescriptor(editInternshipDescriptor); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredInternshipList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); + } + + Internship internshipToEdit = lastShownList.get(index.getZeroBased()); + Internship editedInternship = createEditedInternship(internshipToEdit, editInternshipDescriptor); + + if (!internshipToEdit.isSameInternship(editedInternship) && model.hasInternship(editedInternship)) { + throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP); + } + + model.setInternship(internshipToEdit, editedInternship); + // Doesnt make sense to me to reset the filtering after editing an internship + // its not that hard to just type list + + // model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS); + model.commitWorkBook(); + return new CommandResult(String.format(MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship)); + } + + /** + * Creates and returns a {@code Internship} with the details of + * {@code internshipToEdit} edited with {@code editInternshipDescriptor}. + */ + private static Internship createEditedInternship(Internship internshipToEdit, + EditInternshipDescriptor editInternshipDescriptor) { + assert internshipToEdit != null; + + Company updatedCompany = editInternshipDescriptor.getCompany().orElse(internshipToEdit.getCompany()); + Role updatedRole = editInternshipDescriptor.getRole().orElse(internshipToEdit.getRole()); + Email updatedEmail = editInternshipDescriptor.getEmail().orElse(internshipToEdit.getEmail()); + Stage updatedStage = editInternshipDescriptor.getStage().orElse(internshipToEdit.getStage()); + DateTime updatedDateTime = editInternshipDescriptor.getDate().orElse(internshipToEdit.getDateTime()); + Set updatedLanguageTags = editInternshipDescriptor.getLanguageTags() + .orElse(internshipToEdit.getLanguageTags()); + Set updatedTags = editInternshipDescriptor.getTags().orElse(internshipToEdit.getTags()); + + return new Internship(updatedCompany, updatedRole, + updatedEmail, updatedStage, updatedDateTime, updatedLanguageTags, updatedTags); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditCommand)) { + return false; + } + + // state check + EditCommand e = (EditCommand) other; + return index.equals(e.index) + && editInternshipDescriptor.equals(e.editInternshipDescriptor); + } + + /** + * Stores the details to edit the internship with. Each non-empty field value + * will replace the corresponding field value of the internship. + */ + public static class EditInternshipDescriptor { + private Company company; + private Role role; + private Email email; + private Stage stage; + private DateTime dateTime; + private Set languageTags; + private Set tags; + + public EditInternshipDescriptor() { + } + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditInternshipDescriptor(EditInternshipDescriptor toCopy) { + setCompany(toCopy.company); + setRole(toCopy.role); + setEmail(toCopy.email); + setStage(toCopy.stage); + setDate(toCopy.dateTime); + setLanguageTags(toCopy.languageTags); + setTags(toCopy.tags); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(company, role, email, stage, dateTime, languageTags, tags); + } + + public void setCompany(Company company) { + this.company = company; + } + + public Optional getCompany() { + return Optional.ofNullable(company); + } + + public void setRole(Role role) { + this.role = role; + } + + public Optional getRole() { + return Optional.ofNullable(role); + } + + public void setEmail(Email email) { + this.email = email; + } + + public Optional getEmail() { + return Optional.ofNullable(email); + } + public void setStage(Stage stage) { + this.stage = stage; + } + + public Optional getStage() { + return Optional.ofNullable(stage); + } + + public void setDate(DateTime dateTime) { + this.dateTime = dateTime; + } + + public Optional getDate() { + return Optional.ofNullable(dateTime); + } + + /** + * Sets {@code languageTags} to this object's {@code languageTags}. + * A defensive copy of {@code languageTags} is used internally. + */ + public void setLanguageTags(Set languageTags) { + this.languageTags = (languageTags != null) ? new HashSet<>(languageTags) : null; + } + + /** + * Returns an unmodifiable language tag set, which throws + * {@code UnsupportedOperationException} if modification is attempted. + * Returns {@code Optional#empty()} if {@code tags} is null. + */ + public Optional> getLanguageTags() { + return (languageTags != null) ? Optional.of(Collections.unmodifiableSet(languageTags)) : Optional.empty(); + } + + + /** + * 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. + */ + public Optional> getTags() { + return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditInternshipDescriptor)) { + return false; + } + + // state check + EditInternshipDescriptor e = (EditInternshipDescriptor) other; + + return getCompany().equals(e.getCompany()) + && getRole().equals(e.getRole()) + && getEmail().equals(e.getEmail()) + && getStage().equals(e.getStage()) + && getDate().equals(e.getDate()) + && getLanguageTags().equals(e.getLanguageTags()) + && getTags().equals(e.getTags()); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/workbook/logic/commands/ExitCommand.java similarity index 59% rename from src/main/java/seedu/address/logic/commands/ExitCommand.java rename to src/main/java/seedu/workbook/logic/commands/ExitCommand.java index 3dd85a8ba90..a365f428ed6 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/seedu/workbook/logic/commands/ExitCommand.java @@ -1,15 +1,17 @@ -package seedu.address.logic.commands; +package seedu.workbook.logic.commands; -import seedu.address.model.Model; +import seedu.workbook.model.Model; /** * Terminates the program. */ public class ExitCommand extends Command { + /** Command word to execute the exit command */ public static final String COMMAND_WORD = "exit"; - public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ..."; + /** Message string displaying successful execution of the exit command */ + public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting WorkBook as requested ..."; @Override public CommandResult execute(Model model) { diff --git a/src/main/java/seedu/workbook/logic/commands/FindCommand.java b/src/main/java/seedu/workbook/logic/commands/FindCommand.java new file mode 100644 index 00000000000..ea0c9cf41a4 --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/FindCommand.java @@ -0,0 +1,54 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; + +import java.util.function.Predicate; + +import seedu.workbook.commons.core.Messages; +import seedu.workbook.model.Model; +import seedu.workbook.model.internship.Internship; + +/** + * Finds and lists all internships in WorkBook whose company, role or stage name contains + * any of the argument keywords. + * Keyword matching is case insensitive. + */ +public class FindCommand extends Command { + + /** Command word to execute the find command */ + public static final String COMMAND_WORD = "find"; + + /** Help message to execute the find command */ + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Finds all internships either by Company, Role or Stage using their respective prefix and " + + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" + + "Parameters: " + PREFIX_COMPANY + "COMPANY " + + "| " + PREFIX_ROLE + "ROLE " + + "| " + PREFIX_STAGE + "STAGE\n" + + "Example: " + COMMAND_WORD + " " + PREFIX_COMPANY + "Meta"; + + /** Keyword to search for */ + private final Predicate predicate; + + public FindCommand(Predicate predicate) { + this.predicate = predicate; + } + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredInternshipList(predicate); + return new CommandResult( + String.format(Messages.MESSAGE_INTERNSHIPS_LISTED_OVERVIEW, model.getFilteredInternshipList().size())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof FindCommand // instanceof handles nulls + && predicate.equals(((FindCommand) other).predicate)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/workbook/logic/commands/HelpCommand.java similarity index 67% rename from src/main/java/seedu/address/logic/commands/HelpCommand.java rename to src/main/java/seedu/workbook/logic/commands/HelpCommand.java index bf824f91bd0..07a5eaa9d6a 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/seedu/workbook/logic/commands/HelpCommand.java @@ -1,17 +1,20 @@ -package seedu.address.logic.commands; +package seedu.workbook.logic.commands; -import seedu.address.model.Model; +import seedu.workbook.model.Model; /** * Format full help instructions for every command for display. */ public class HelpCommand extends Command { + /** Command word to execute the help command */ public static final String COMMAND_WORD = "help"; + /** Help message to execute the help command */ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" + "Example: " + COMMAND_WORD; + /** Message string displaying successful execution of the help command */ public static final String SHOWING_HELP_MESSAGE = "Opened help window."; @Override diff --git a/src/main/java/seedu/workbook/logic/commands/ListCommand.java b/src/main/java/seedu/workbook/logic/commands/ListCommand.java new file mode 100644 index 00000000000..8533139e6da --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/ListCommand.java @@ -0,0 +1,26 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS; + +import seedu.workbook.model.Model; + +/** + * Lists all internships in the WorkBook to the user. + */ +public class ListCommand extends Command { + + /** Command word to execute the list command */ + public static final String COMMAND_WORD = "list"; + + /** Message string displaying successful execution of the list command */ + public static final String MESSAGE_SUCCESS = "Listed all internships"; + + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/workbook/logic/commands/RedoCommand.java b/src/main/java/seedu/workbook/logic/commands/RedoCommand.java new file mode 100644 index 00000000000..2aebb63c19b --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/RedoCommand.java @@ -0,0 +1,38 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS; + +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.model.Model; + +/** + * Reverts the {@code model}'s WorkBook to its previously undone state. + */ +public class RedoCommand extends Command { + + /** Command word to execute the redo command */ + public static final String COMMAND_WORD = "redo"; + + /** Message string displaying successful execution of the redo command */ + public static final String MESSAGE_SUCCESS = "Redo success!"; + + /** + * Message string displaying error message for unsuccessful execution of the redo command + * for a WorkBook with no commands to redo + */ + public static final String MESSAGE_FAILURE = "No more commands to redo!"; + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (!model.canRedoWorkBook()) { + throw new CommandException(MESSAGE_FAILURE); + } + + model.redoWorkBook(); + model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/workbook/logic/commands/UndoCommand.java b/src/main/java/seedu/workbook/logic/commands/UndoCommand.java new file mode 100644 index 00000000000..06eeda631fb --- /dev/null +++ b/src/main/java/seedu/workbook/logic/commands/UndoCommand.java @@ -0,0 +1,37 @@ +package seedu.workbook.logic.commands; + +import static java.util.Objects.requireNonNull; + +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.model.Model; + +/** + * Reverts the {@code model}'s WorkBook to its previous state. + */ +public class UndoCommand extends Command { + + /** Command word to execute the undo command */ + public static final String COMMAND_WORD = "undo"; + + /** Message string displaying successful execution of the undo command */ + public static final String MESSAGE_SUCCESS = "Undo previous changes successful!"; + + /** + * Message string displaying error message for unsuccessful execution of the undo command + * for an unmodified WorkBook + */ + public static final String MESSAGE_NO_CHANGES = "No previous changes to undo!"; + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (!model.canUndoWorkBook()) { + throw new CommandException(MESSAGE_NO_CHANGES); + } + + model.undoWorkBook(); + model.updateFilteredInternshipList(Model.PREDICATE_SHOW_ALL_INTERNSHIPS); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/workbook/logic/commands/exceptions/CommandException.java similarity index 89% rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java rename to src/main/java/seedu/workbook/logic/commands/exceptions/CommandException.java index a16bd14f2cd..e872c9ef6ac 100644 --- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java +++ b/src/main/java/seedu/workbook/logic/commands/exceptions/CommandException.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands.exceptions; +package seedu.workbook.logic.commands.exceptions; /** * Represents an error which occurs during execution of a {@link Command}. diff --git a/src/main/java/seedu/workbook/logic/parser/AddCommandParser.java b/src/main/java/seedu/workbook/logic/parser/AddCommandParser.java new file mode 100644 index 00000000000..f2473fd5d69 --- /dev/null +++ b/src/main/java/seedu/workbook/logic/parser/AddCommandParser.java @@ -0,0 +1,89 @@ +package seedu.workbook.logic.parser; + +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.workbook.model.internship.DateTime.EMPTY_DATETIME; +import static seedu.workbook.model.internship.Email.EMPTY_EMAIL; + +import java.util.Set; +import java.util.stream.Stream; + +import seedu.workbook.logic.commands.AddCommand; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.logic.parser.util.CheckedFunction; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.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_COMPANY, PREFIX_ROLE, + PREFIX_EMAIL, PREFIX_STAGE, PREFIX_DATETIME, PREFIX_LANGUAGE_TAG, PREFIX_TAG); + + if (!arePrefixesPresent(argMultimap, PREFIX_COMPANY, PREFIX_ROLE, PREFIX_STAGE) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + + Company company = ParserUtil.parseCompany(argMultimap.getValue(PREFIX_COMPANY).get()); + Role role = ParserUtil.parseRole(argMultimap.getValue(PREFIX_ROLE).get()); + Email email = parseOptionalEmail(PREFIX_EMAIL, argMultimap, ParserUtil::parseEmail); + Stage stage = ParserUtil.parseStage(argMultimap.getValue(PREFIX_STAGE).get()); + DateTime dateTime = parseOptionalDateTime(PREFIX_DATETIME, argMultimap, ParserUtil::parseDateTime); + Set languageTagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_LANGUAGE_TAG)); + Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); + + Internship internship = new Internship(company, role, email, stage, dateTime, languageTagList, tagList); + + return new AddCommand(internship); + } + + /** + * 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()); + } + + // Adapted and changed from CS2103T-T10-4 + // https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110 + private DateTime parseOptionalDateTime(Prefix prefix, ArgumentMultimap argMultimap, + CheckedFunction parserFn) throws ParseException { + if (argMultimap.getValue(prefix).isPresent()) { + return parserFn.apply(argMultimap.getValue(prefix).get()); + } + return EMPTY_DATETIME; + } + + // Adapted and changed from CS2103T-T10-4 + // https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110 + private Email parseOptionalEmail(Prefix prefix, ArgumentMultimap argMultimap, + CheckedFunction parserFn) throws ParseException { + if (argMultimap.getValue(prefix).isPresent()) { + return parserFn.apply(argMultimap.getValue(prefix).get()); + } + return EMPTY_EMAIL; + } + +} diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/workbook/logic/parser/ArgumentMultimap.java similarity index 98% rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java rename to src/main/java/seedu/workbook/logic/parser/ArgumentMultimap.java index 954c8e18f8e..477b3a8999d 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java +++ b/src/main/java/seedu/workbook/logic/parser/ArgumentMultimap.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package seedu.workbook.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/seedu/workbook/logic/parser/ArgumentTokenizer.java similarity index 92% rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java rename to src/main/java/seedu/workbook/logic/parser/ArgumentTokenizer.java index 5c9aebfa488..102608d87b6 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java +++ b/src/main/java/seedu/workbook/logic/parser/ArgumentTokenizer.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package seedu.workbook.logic.parser; import java.util.ArrayList; import java.util.Arrays; @@ -28,6 +28,17 @@ public static ArgumentMultimap tokenize(String argsString, Prefix... prefixes) { return extractArguments(argsString, positions); } + /** + * Returns the number of prefixes that the user has input in argsString. + * + * @param argsString Arguments string of the form: {@code preamble value value ...} + * @param prefixes Prefixes to find in the arguments string. + * @return Returns the number of prefixes. + */ + public static int numberOfPrefixes(String argsString, Prefix... prefixes) { + return findAllPrefixPositions(argsString, prefixes).size(); + } + /** * Finds all zero-based prefix positions in the given arguments string. * @@ -41,6 +52,8 @@ private static List findAllPrefixPositions(String argsString, Pr .collect(Collectors.toList()); } + + /** * {@see findAllPrefixPositions} */ diff --git a/src/main/java/seedu/workbook/logic/parser/CliSyntax.java b/src/main/java/seedu/workbook/logic/parser/CliSyntax.java new file mode 100644 index 00000000000..bba53f3bcb7 --- /dev/null +++ b/src/main/java/seedu/workbook/logic/parser/CliSyntax.java @@ -0,0 +1,17 @@ +package seedu.workbook.logic.parser; + +/** + * Contains Command Line Interface (CLI) syntax definitions common to multiple commands + */ +public class CliSyntax { + + /* Prefix definitions */ + public static final Prefix PREFIX_COMPANY = new Prefix("c/"); + public static final Prefix PREFIX_ROLE = new Prefix("r/"); + public static final Prefix PREFIX_EMAIL = new Prefix("e/"); + public static final Prefix PREFIX_STAGE = new Prefix("s/"); + public static final Prefix PREFIX_DATETIME = new Prefix("d/"); + public static final Prefix PREFIX_LANGUAGE_TAG = new Prefix("l/"); + public static final Prefix PREFIX_TAG = new Prefix("t/"); + +} diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/workbook/logic/parser/DeleteCommandParser.java similarity index 73% rename from src/main/java/seedu/address/logic/parser/DeleteCommandParser.java rename to src/main/java/seedu/workbook/logic/parser/DeleteCommandParser.java index 522b93081cc..083e6287de9 100644 --- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java +++ b/src/main/java/seedu/workbook/logic/parser/DeleteCommandParser.java @@ -1,10 +1,10 @@ -package seedu.address.logic.parser; +package seedu.workbook.logic.parser; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.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 seedu.workbook.commons.core.index.Index; +import seedu.workbook.logic.commands.DeleteCommand; +import seedu.workbook.logic.parser.exceptions.ParseException; /** * Parses input arguments and creates a new DeleteCommand object diff --git a/src/main/java/seedu/workbook/logic/parser/EditCommandParser.java b/src/main/java/seedu/workbook/logic/parser/EditCommandParser.java new file mode 100644 index 00000000000..90028fa17e9 --- /dev/null +++ b/src/main/java/seedu/workbook/logic/parser/EditCommandParser.java @@ -0,0 +1,94 @@ +package seedu.workbook.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.logic.commands.EditCommand; +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.tag.Tag; + +/** + * Parses input arguments and creates a new EditCommand object + */ +public class EditCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the + * EditCommand and returns an EditCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public EditCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_COMPANY, PREFIX_ROLE, + PREFIX_EMAIL, PREFIX_STAGE, PREFIX_DATETIME, PREFIX_LANGUAGE_TAG, PREFIX_TAG); + + Index index; + + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); + } + + EditInternshipDescriptor editInternshipDescriptor = new EditInternshipDescriptor(); + if (argMultimap.getValue(PREFIX_COMPANY).isPresent()) { + editInternshipDescriptor.setCompany(ParserUtil.parseCompany(argMultimap.getValue(PREFIX_COMPANY).get())); + } + if (argMultimap.getValue(PREFIX_ROLE).isPresent()) { + editInternshipDescriptor.setRole(ParserUtil.parseRole(argMultimap.getValue(PREFIX_ROLE).get())); + } + if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { + editInternshipDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); + } + if (argMultimap.getValue(PREFIX_STAGE).isPresent()) { + editInternshipDescriptor.setStage(ParserUtil.parseStage(argMultimap.getValue(PREFIX_STAGE).get())); + } + + if (argMultimap.getValue(PREFIX_DATETIME).isPresent()) { + editInternshipDescriptor.setDate(ParserUtil.parseDateTime(argMultimap.getValue(PREFIX_DATETIME).get())); + } + + parseTagsForEdit(argMultimap.getAllValues(PREFIX_LANGUAGE_TAG)) + .ifPresent(editInternshipDescriptor::setLanguageTags); + + parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editInternshipDescriptor::setTags); + + if (!editInternshipDescriptor.isAnyFieldEdited()) { + throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); + } + + return new EditCommand(index, editInternshipDescriptor); + } + + /** + * Parses {@code Collection tags} into a {@code Set} if + * {@code tags} is non-empty. + * If {@code tags} contain only one element which is an empty string, it will be + * parsed into a {@code Set} containing zero tags. + */ + private Optional> parseTagsForEdit(Collection tags) throws ParseException { + assert tags != null; + + if (tags.isEmpty()) { + return Optional.empty(); + } + Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags; + return Optional.of(ParserUtil.parseTags(tagSet)); + } + +} diff --git a/src/main/java/seedu/workbook/logic/parser/FindCommandParser.java b/src/main/java/seedu/workbook/logic/parser/FindCommandParser.java new file mode 100644 index 00000000000..7755bbb9b3e --- /dev/null +++ b/src/main/java/seedu/workbook/logic/parser/FindCommandParser.java @@ -0,0 +1,78 @@ +package seedu.workbook.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; + +import java.util.Arrays; + +import seedu.workbook.logic.commands.FindCommand; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate; +import seedu.workbook.model.internship.RoleContainsKeywordsPredicate; +import seedu.workbook.model.internship.StageContainsKeywordsPredicate; + +/** + * Parses input arguments and creates a new FindCommand object + */ +public class FindCommandParser 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 FindCommand parse(String args) throws ParseException { + requireNonNull(args); + + + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_COMPANY, PREFIX_ROLE, + PREFIX_STAGE); + + int numberOfPrefixes = ArgumentTokenizer.numberOfPrefixes(args, PREFIX_COMPANY, PREFIX_ROLE, + PREFIX_STAGE); + + if (!argMultimap.getPreamble().isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + + } else if (numberOfPrefixes > 1) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + + } else if (argMultimap.getValue(PREFIX_COMPANY).isPresent()) { + String arguments = argMultimap.getValue(PREFIX_COMPANY).get(); + if (arguments.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + String[] companyNameKeywords = arguments.split("\\s+"); + return new FindCommand(new CompanyContainsKeywordsPredicate(Arrays.asList(companyNameKeywords))); + + } else if (argMultimap.getValue(PREFIX_STAGE).isPresent()) { + String arguments = argMultimap.getValue(PREFIX_STAGE).get(); + if (arguments.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + String[] stageKeywords = arguments.split("\\s+"); + return new FindCommand(new StageContainsKeywordsPredicate(Arrays.asList(stageKeywords))); + + } else if (argMultimap.getValue(PREFIX_ROLE).isPresent()) { + String arguments = argMultimap.getValue(PREFIX_ROLE).get(); + if (arguments.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + String[] roleKeywords = arguments.split("\\s+"); + return new FindCommand(new RoleContainsKeywordsPredicate(Arrays.asList(roleKeywords))); + + } else { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + } +} diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/workbook/logic/parser/Parser.java similarity index 72% rename from src/main/java/seedu/address/logic/parser/Parser.java rename to src/main/java/seedu/workbook/logic/parser/Parser.java index d6551ad8e3f..210efac3b52 100644 --- a/src/main/java/seedu/address/logic/parser/Parser.java +++ b/src/main/java/seedu/workbook/logic/parser/Parser.java @@ -1,7 +1,7 @@ -package seedu.address.logic.parser; +package seedu.workbook.logic.parser; -import seedu.address.logic.commands.Command; -import seedu.address.logic.parser.exceptions.ParseException; +import seedu.workbook.logic.commands.Command; +import seedu.workbook.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/seedu/workbook/logic/parser/ParserUtil.java similarity index 51% rename from src/main/java/seedu/address/logic/parser/ParserUtil.java rename to src/main/java/seedu/workbook/logic/parser/ParserUtil.java index b117acb9c55..8b281125dd2 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/workbook/logic/parser/ParserUtil.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package seedu.workbook.logic.parser; import static java.util.Objects.requireNonNull; @@ -6,14 +6,15 @@ 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 seedu.workbook.commons.core.index.Index; +import seedu.workbook.commons.util.StringUtil; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.tag.Tag; /** * Contains utility methods used for parsing strings in the various *Parser classes. @@ -36,49 +37,35 @@ public static Index parseIndex(String oneBasedIndex) throws ParseException { } /** - * Parses a {@code String name} into a {@code Name}. + * Parses a {@code String company} into a {@code Company}. * Leading and trailing whitespaces will be trimmed. * - * @throws ParseException if the given {@code name} is invalid. + * @throws ParseException if the given {@code company} is invalid. */ - public static Name parseName(String name) throws ParseException { - requireNonNull(name); - String trimmedName = name.trim(); - if (!Name.isValidName(trimmedName)) { - throw new ParseException(Name.MESSAGE_CONSTRAINTS); + public static Company parseCompany(String company) throws ParseException { + requireNonNull(company); + String trimmedCompany = company.trim(); + if (!Company.isValidCompany(trimmedCompany)) { + throw new ParseException(Company.MESSAGE_CONSTRAINTS); } - return new Name(trimmedName); + return new Company(trimmedCompany); } /** - * Parses a {@code String phone} into a {@code Phone}. + * Parses a {@code String role} into a {@code Role}. * Leading and trailing whitespaces will be trimmed. * - * @throws ParseException if the given {@code phone} is invalid. + * @throws ParseException if the given {@code role} is invalid. */ - public static Phone parsePhone(String phone) throws ParseException { - requireNonNull(phone); - String trimmedPhone = phone.trim(); - if (!Phone.isValidPhone(trimmedPhone)) { - throw new ParseException(Phone.MESSAGE_CONSTRAINTS); + public static Role parseRole(String role) throws ParseException { + requireNonNull(role); + String trimmedRole = role.trim(); + if (!Role.isValidRole(trimmedRole)) { + throw new ParseException(Role.MESSAGE_CONSTRAINTS); } - return new Phone(trimmedPhone); + return new Role(trimmedRole); } - /** - * Parses a {@code String address} into an {@code Address}. - * Leading and trailing whitespaces will be trimmed. - * - * @throws ParseException if the given {@code address} is invalid. - */ - public static Address parseAddress(String address) throws ParseException { - requireNonNull(address); - String trimmedAddress = address.trim(); - if (!Address.isValidAddress(trimmedAddress)) { - throw new ParseException(Address.MESSAGE_CONSTRAINTS); - } - return new Address(trimmedAddress); - } /** * Parses a {@code String email} into an {@code Email}. @@ -95,18 +82,45 @@ public static Email parseEmail(String email) throws ParseException { return new Email(trimmedEmail); } + /** + * Parses a {@code String stage} into an {@code Stage}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code stage} is invalid. + */ + public static Stage parseStage(String stage) throws ParseException { + requireNonNull(stage); + String trimmedStage = stage.trim(); + if (!Stage.isValidStage(trimmedStage)) { + throw new ParseException(Stage.MESSAGE_CONSTRAINTS); + } + return new Stage(trimmedStage); + } + + /** + * Parses a {@code String date} into a {@code DateTime}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code dateTime} is invalid. + */ + public static DateTime parseDateTime(String dateTime) throws ParseException { + requireNonNull(dateTime); + String trimmedDateTime = dateTime.trim(); + if (!DateTime.isValidDateTime(trimmedDateTime)) { + throw new ParseException(DateTime.MESSAGE_CONSTRAINTS); + } + return new DateTime(trimmedDateTime); + } + /** * Parses a {@code String tag} into a {@code Tag}. * Leading and trailing whitespaces will be trimmed. * * @throws ParseException if the given {@code tag} is invalid. */ - public static Tag parseTag(String tag) throws ParseException { + public static Tag parseTag(String tag) { requireNonNull(tag); String trimmedTag = tag.trim(); - if (!Tag.isValidTagName(trimmedTag)) { - throw new ParseException(Tag.MESSAGE_CONSTRAINTS); - } return new Tag(trimmedTag); } @@ -117,6 +131,9 @@ public static Set parseTags(Collection tags) throws ParseException requireNonNull(tags); final Set tagSet = new HashSet<>(); for (String tagName : tags) { + if (tagName.isBlank()) { + continue; + } tagSet.add(parseTag(tagName)); } return tagSet; diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/workbook/logic/parser/Prefix.java similarity index 95% rename from src/main/java/seedu/address/logic/parser/Prefix.java rename to src/main/java/seedu/workbook/logic/parser/Prefix.java index c859d5fa5db..f80215b89f4 100644 --- a/src/main/java/seedu/address/logic/parser/Prefix.java +++ b/src/main/java/seedu/workbook/logic/parser/Prefix.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package seedu.workbook.logic.parser; /** * A prefix that marks the beginning of an argument in an arguments string. diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/workbook/logic/parser/WorkBookParser.java similarity index 64% rename from src/main/java/seedu/address/logic/parser/AddressBookParser.java rename to src/main/java/seedu/workbook/logic/parser/WorkBookParser.java index 1e466792b46..4dc73b2f42a 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/workbook/logic/parser/WorkBookParser.java @@ -1,26 +1,28 @@ -package seedu.address.logic.parser; +package seedu.workbook.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 seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.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 seedu.workbook.logic.commands.AddCommand; +import seedu.workbook.logic.commands.ClearCommand; +import seedu.workbook.logic.commands.Command; +import seedu.workbook.logic.commands.DeleteCommand; +import seedu.workbook.logic.commands.EditCommand; +import seedu.workbook.logic.commands.ExitCommand; +import seedu.workbook.logic.commands.FindCommand; +import seedu.workbook.logic.commands.HelpCommand; +import seedu.workbook.logic.commands.ListCommand; +import seedu.workbook.logic.commands.RedoCommand; +import seedu.workbook.logic.commands.UndoCommand; +import seedu.workbook.logic.parser.exceptions.ParseException; /** * Parses user input. */ -public class AddressBookParser { +public class WorkBookParser { /** * Used for initial separation of command word and args. @@ -62,6 +64,12 @@ public Command parseCommand(String userInput) throws ParseException { case ListCommand.COMMAND_WORD: return new ListCommand(); + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + + case RedoCommand.COMMAND_WORD: + return new RedoCommand(); + case ExitCommand.COMMAND_WORD: return new ExitCommand(); diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/seedu/workbook/logic/parser/exceptions/ParseException.java similarity index 72% rename from src/main/java/seedu/address/logic/parser/exceptions/ParseException.java rename to src/main/java/seedu/workbook/logic/parser/exceptions/ParseException.java index 158a1a54c1c..9c9fd28d9b6 100644 --- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java +++ b/src/main/java/seedu/workbook/logic/parser/exceptions/ParseException.java @@ -1,6 +1,6 @@ -package seedu.address.logic.parser.exceptions; +package seedu.workbook.logic.parser.exceptions; -import seedu.address.commons.exceptions.IllegalValueException; +import seedu.workbook.commons.exceptions.IllegalValueException; /** * Represents a parse error encountered by a parser. diff --git a/src/main/java/seedu/workbook/logic/parser/util/CheckedFunction.java b/src/main/java/seedu/workbook/logic/parser/util/CheckedFunction.java new file mode 100644 index 00000000000..664fdacbc80 --- /dev/null +++ b/src/main/java/seedu/workbook/logic/parser/util/CheckedFunction.java @@ -0,0 +1,16 @@ +package seedu.workbook.logic.parser.util; + +import seedu.workbook.logic.parser.exceptions.ParseException; + +// Reused from CS2103T-T10-4 +// https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110 +/** + * This is a functional interface which represents a function that can throw {@code ParseException}. + * + * @param the type of the exception thrown by the function + * @param the type of the result of the function + */ +@FunctionalInterface +public interface CheckedFunction { + R apply(T t) throws ParseException; +} diff --git a/src/main/java/seedu/workbook/model/Model.java b/src/main/java/seedu/workbook/model/Model.java new file mode 100644 index 00000000000..46393f0e1a5 --- /dev/null +++ b/src/main/java/seedu/workbook/model/Model.java @@ -0,0 +1,105 @@ +package seedu.workbook.model; + +import java.nio.file.Path; +import java.util.function.Predicate; + +import javafx.collections.ObservableList; +import seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.model.internship.Internship; + + +/** + * The API of the Model component. + */ +public interface Model { + /** {@code Predicate} that always evaluate to true */ + Predicate PREDICATE_SHOW_ALL_INTERNSHIPS = 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' work book file path. */ + Path getWorkBookFilePath(); + + /** Sets the user prefs' work book file path. */ + void setWorkBookFilePath(Path workBookFilePath); + + /** Replaces work book data with the data in {@code workBook}. */ + void setWorkBook(ReadOnlyWorkBook workBook); + + /** Returns the WorkBook. */ + ReadOnlyWorkBook getWorkBook(); + + /** + * Returns true if an Internship with the same identity as {@code internship} + * exists in WorkBook. + */ + boolean hasInternship(Internship internship); + + /** + * Deletes the given Internship. + * The internship must exist in WorkBook. + */ + void deleteInternship(Internship target); + + /** + * Adds the given Internship. + * {@code internship} must not already exist in the WorkBook. + */ + void addInternship(Internship internship); + + /** + * Replaces the given internship {@code target} with {@code editedInternship}. + * {@code target} must exist in WorkBook. + * The Internship identity of {@code editedInternship} must not be the same as + * another existing internship in WorkBook. + */ + void setInternship(Internship target, Internship editedInternship); + + /** Returns an unmodifiable view of the filtered internship list */ + ObservableList getFilteredInternshipList(); + + /** + * Returns true if the model has undone WorkBook states to restore. + */ + boolean canUndoWorkBook(); + + /** + * Returns true if the model has undone WorkBook states to restore. + */ + boolean canRedoWorkBook(); + + /** + * Restores the model's WorkBook back to its previous state. + */ + void undoWorkBook(); + + /** + * Restores the model's WorkBook to its previously undone state. + */ + void redoWorkBook(); + + /** + * Saves the current WorkBook state for undo. + */ + void commitWorkBook(); + + /** + * Updates the filter of the filtered internship list to filter by the given + * {@code predicate}. + * + * @throws NullPointerException if {@code predicate} is null. + */ + void updateFilteredInternshipList(Predicate predicate); + + +} diff --git a/src/main/java/seedu/workbook/model/ModelManager.java b/src/main/java/seedu/workbook/model/ModelManager.java new file mode 100644 index 00000000000..94245fc539c --- /dev/null +++ b/src/main/java/seedu/workbook/model/ModelManager.java @@ -0,0 +1,177 @@ +package seedu.workbook.model; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.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.workbook.commons.core.GuiSettings; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.model.internship.Internship; + +/** + * Represents the in-memory model of the WorkBook data. + */ +public class ModelManager implements Model { + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private final VersionedWorkBook versionedWorkBook; + private final UserPrefs userPrefs; + private final FilteredList filteredInternships; + + /** + * Initializes a ModelManager with the given WorkBook and userPrefs. + */ + public ModelManager(ReadOnlyWorkBook workBook, ReadOnlyUserPrefs userPrefs) { + requireAllNonNull(workBook, userPrefs); + + logger.fine("Initializing with work book: " + workBook + " and user prefs " + userPrefs); + + versionedWorkBook = new VersionedWorkBook(workBook); + this.userPrefs = new UserPrefs(userPrefs); + filteredInternships = new FilteredList<>(this.versionedWorkBook.getInternshipList()); + } + + public ModelManager() { + this(new WorkBook(), 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 getWorkBookFilePath() { + return userPrefs.getWorkBookFilePath(); + } + + @Override + public void setWorkBookFilePath(Path workBookFilePath) { + requireNonNull(workBookFilePath); + userPrefs.setWorkBookFilePath(workBookFilePath); + } + + //=========== WorkBook ================================================================================ + + @Override + public void setWorkBook(ReadOnlyWorkBook workBook) { + this.versionedWorkBook.resetData(workBook); + } + + @Override + public ReadOnlyWorkBook getWorkBook() { + return versionedWorkBook; + } + + @Override + public boolean hasInternship(Internship internship) { + requireNonNull(internship); + return versionedWorkBook.hasInternship(internship); + } + + @Override + public void deleteInternship(Internship target) { + versionedWorkBook.removeInternship(target); + } + + @Override + public void addInternship(Internship internship) { + versionedWorkBook.addInternship(internship); + // resets ui view to show all internships whenever add command is executed + // ideal behaviour TBD + updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS); + } + + @Override + public void setInternship(Internship target, Internship editedInternship) { + requireAllNonNull(target, editedInternship); + + versionedWorkBook.setInternship(target, editedInternship); + } + + //=========== Filtered Internship List Accessors ============================================================= + + /** + * Returns an unmodifiable view of the list of {@code Internship} backed by the internal list of + * {@code versionedWorkBook} + */ + @Override + public ObservableList getFilteredInternshipList() { + return filteredInternships; + } + + @Override + public boolean canUndoWorkBook() { + return versionedWorkBook.canUndo(); + } + + @Override + public boolean canRedoWorkBook() { + return versionedWorkBook.canRedo(); + } + + @Override + public void undoWorkBook() { + versionedWorkBook.undo(); + } + + @Override + public void redoWorkBook() { + versionedWorkBook.redo(); + } + + @Override + public void commitWorkBook() { + versionedWorkBook.commit(); + } + + @Override + public void updateFilteredInternshipList(Predicate predicate) { + requireNonNull(predicate); + filteredInternships.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 versionedWorkBook.equals(other.versionedWorkBook) + && userPrefs.equals(other.userPrefs) + && filteredInternships.equals(other.filteredInternships); + } + +} diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/workbook/model/ReadOnlyUserPrefs.java similarity index 57% rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java rename to src/main/java/seedu/workbook/model/ReadOnlyUserPrefs.java index befd58a4c73..14b337f16c7 100644 --- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java +++ b/src/main/java/seedu/workbook/model/ReadOnlyUserPrefs.java @@ -1,8 +1,8 @@ -package seedu.address.model; +package seedu.workbook.model; import java.nio.file.Path; -import seedu.address.commons.core.GuiSettings; +import seedu.workbook.commons.core.GuiSettings; /** * Unmodifiable view of user prefs. @@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs { GuiSettings getGuiSettings(); - Path getAddressBookFilePath(); + Path getWorkBookFilePath(); } diff --git a/src/main/java/seedu/workbook/model/ReadOnlyWorkBook.java b/src/main/java/seedu/workbook/model/ReadOnlyWorkBook.java new file mode 100644 index 00000000000..fb5fbb53c18 --- /dev/null +++ b/src/main/java/seedu/workbook/model/ReadOnlyWorkBook.java @@ -0,0 +1,17 @@ +package seedu.workbook.model; + +import javafx.collections.ObservableList; +import seedu.workbook.model.internship.Internship; + +/** + * Unmodifiable view of a WorkBook + */ +public interface ReadOnlyWorkBook { + + /** + * Returns an unmodifiable view of the internships list. + * This list will not contain any duplicate internships. + */ + ObservableList getInternshipList(); + +} diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/workbook/model/UserPrefs.java similarity index 70% rename from src/main/java/seedu/address/model/UserPrefs.java rename to src/main/java/seedu/workbook/model/UserPrefs.java index 25a5fd6eab9..095d85d64a4 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/seedu/workbook/model/UserPrefs.java @@ -1,4 +1,4 @@ -package seedu.address.model; +package seedu.workbook.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 seedu.workbook.commons.core.GuiSettings; /** * Represents User's preferences. @@ -14,7 +14,7 @@ public class UserPrefs implements ReadOnlyUserPrefs { private GuiSettings guiSettings = new GuiSettings(); - private Path addressBookFilePath = Paths.get("data" , "addressbook.json"); + private Path workBookFilePath = Paths.get("data" , "workbook.json"); /** * Creates a {@code UserPrefs} with default values. @@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) { public void resetData(ReadOnlyUserPrefs newUserPrefs) { requireNonNull(newUserPrefs); setGuiSettings(newUserPrefs.getGuiSettings()); - setAddressBookFilePath(newUserPrefs.getAddressBookFilePath()); + setWorkBookFilePath(newUserPrefs.getWorkBookFilePath()); } public GuiSettings getGuiSettings() { @@ -47,13 +47,14 @@ public void setGuiSettings(GuiSettings guiSettings) { this.guiSettings = guiSettings; } - public Path getAddressBookFilePath() { - return addressBookFilePath; + @Override + public Path getWorkBookFilePath() { + return workBookFilePath; } - public void setAddressBookFilePath(Path addressBookFilePath) { - requireNonNull(addressBookFilePath); - this.addressBookFilePath = addressBookFilePath; + public void setWorkBookFilePath(Path workBookFilePath) { + requireNonNull(workBookFilePath); + this.workBookFilePath = workBookFilePath; } @Override @@ -68,19 +69,19 @@ public boolean equals(Object other) { UserPrefs o = (UserPrefs) other; return guiSettings.equals(o.guiSettings) - && addressBookFilePath.equals(o.addressBookFilePath); + && workBookFilePath.equals(o.workBookFilePath); } @Override public int hashCode() { - return Objects.hash(guiSettings, addressBookFilePath); + return Objects.hash(guiSettings, workBookFilePath); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Gui Settings : " + guiSettings); - sb.append("\nLocal data file location : " + addressBookFilePath); + sb.append("\nLocal data file location : " + workBookFilePath); return sb.toString(); } diff --git a/src/main/java/seedu/workbook/model/VersionedWorkBook.java b/src/main/java/seedu/workbook/model/VersionedWorkBook.java new file mode 100644 index 00000000000..426bd4bb860 --- /dev/null +++ b/src/main/java/seedu/workbook/model/VersionedWorkBook.java @@ -0,0 +1,114 @@ +//Solution below adapted from +// https://github.com/se-edu/addressbook-level4/blob/master/src/main/java/seedu/address/model/VersionedAddressBook.java +package seedu.workbook.model; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@code WorkBook} that keeps track of its own history. + */ +public class VersionedWorkBook extends WorkBook { + + private final List workBookStateList; + private int currentStatePointer; + + /** + * Creates a VersionedWorkBook using the Internships in the {@code initialState} + */ + public VersionedWorkBook(ReadOnlyWorkBook initialState) { + super(initialState); + + workBookStateList = new ArrayList<>(); + workBookStateList.add(new WorkBook(initialState)); + currentStatePointer = 0; + } + + /** + * Saves a copy of the current {@code WorkBook} state at the end of the state list. + * Undone states are removed from the state list. + */ + public void commit() { + removeStatesAfterCurrentPointer(); + workBookStateList.add(new WorkBook(this)); + currentStatePointer++; + } + + private void removeStatesAfterCurrentPointer() { + workBookStateList.subList(currentStatePointer + 1, workBookStateList.size()).clear(); + } + + /** + * Restores the WorkBook to its previous state. + */ + public void undo() { + if (!canUndo()) { + throw new NoUndoableStateException(); + } + currentStatePointer--; + resetData(workBookStateList.get(currentStatePointer)); + } + + /** + * Restores the WorkBook to its previously undone state. + */ + public void redo() { + if (!canRedo()) { + throw new NoRedoableStateException(); + } + currentStatePointer++; + resetData(workBookStateList.get(currentStatePointer)); + } + + /** + * Returns true if {@code undo()} has WorkBook states to undo. + */ + public boolean canUndo() { + return currentStatePointer > 0; + } + + /** + * Returns true if {@code redo()} has WorkBook states to redo. + */ + public boolean canRedo() { + return currentStatePointer < workBookStateList.size() - 1; + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof VersionedWorkBook)) { + return false; + } + + VersionedWorkBook otherVersionedAddressBook = (VersionedWorkBook) other; + + // state check + return super.equals(otherVersionedAddressBook) + && workBookStateList.equals(otherVersionedAddressBook.workBookStateList) + && currentStatePointer == otherVersionedAddressBook.currentStatePointer; + } + + /** + * Thrown when trying to {@code undo()} but can't. + */ + public static class NoUndoableStateException extends RuntimeException { + private NoUndoableStateException() { + super("Current state pointer at the start of workBookState list, unable to undo changes."); + } + } + + /** + * Thrown when trying to {@code redo()} but can't. + */ + public static class NoRedoableStateException extends RuntimeException { + private NoRedoableStateException() { + super("Current state pointer at end of addressBookState list, unable to redo."); + } + } +} diff --git a/src/main/java/seedu/workbook/model/WorkBook.java b/src/main/java/seedu/workbook/model/WorkBook.java new file mode 100644 index 00000000000..18cdb89e61a --- /dev/null +++ b/src/main/java/seedu/workbook/model/WorkBook.java @@ -0,0 +1,125 @@ +package seedu.workbook.model; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import javafx.collections.ObservableList; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.UniqueInternshipList; + +/** + * Wraps all data at the WorkBook level + * Duplicates are not allowed (by .isSameInternship comparison) + */ +public class WorkBook implements ReadOnlyWorkBook { + + private final UniqueInternshipList internships; + + /* + * The 'unusual' code block below is a non-static initialization block, + * sometimes used to avoid duplication between constructors. + * See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html + * + * Note that non-static init blocks are not recommended to use. + * There are other ways to avoid duplication among constructors. + */ + { + internships = new UniqueInternshipList(); + } + + public WorkBook() { + } + + /** + * Creates an WorkBook using the Internships in the {@code toBeCopied} + */ + public WorkBook(ReadOnlyWorkBook toBeCopied) { + this(); + resetData(toBeCopied); + } + + //// list overwrite operations + + /** + * Replaces the contents of the internship list with {@code internships}. + * {@code internships} must not contain duplicate internships. + */ + public void setInternships(List internships) { + this.internships.setInternships(internships); + } + + /** + * Resets the existing data of this {@code WorkBook} with {@code newData}. + */ + public void resetData(ReadOnlyWorkBook newData) { + requireNonNull(newData); + + setInternships(newData.getInternshipList()); + } + + //// internship-level operations + + /** + * Returns true if an internship with the same identity as {@code internship} + * exists in the work book. + */ + public boolean hasInternship(Internship internship) { + requireNonNull(internship); + return internships.contains(internship); + } + + /** + * Adds an internship to the work book. + * The internship must not already exist in the work book. + */ + public void addInternship(Internship i) { + internships.add(i); + } + + /** + * Replaces the given internship {@code target} in the list with + * {@code editedInternship}. + * {@code target} must exist in the work book. + * The internship identity of {@code editedInternship} must not be the same as + * another existing internship in the work book. + */ + public void setInternship(Internship target, Internship editedInternship) { + requireNonNull(editedInternship); + + internships.setInternship(target, editedInternship); + } + + /** + * Removes {@code key} from this {@code WorkBook}. + * {@code key} must exist in the work book. + */ + public void removeInternship(Internship key) { + internships.remove(key); + } + + //// util methods + + @Override + public String toString() { + return internships.asUnmodifiableObservableList().size() + " internship applications"; + // TODO: refine later + } + + @Override + public ObservableList getInternshipList() { + return internships.asUnmodifiableObservableList(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof WorkBook // instanceof handles nulls + && internships.equals(((WorkBook) other).internships)); + } + + @Override + public int hashCode() { + return internships.hashCode(); + } +} diff --git a/src/main/java/seedu/workbook/model/internship/Company.java b/src/main/java/seedu/workbook/model/internship/Company.java new file mode 100644 index 00000000000..b91b9e1c645 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/Company.java @@ -0,0 +1,64 @@ +package seedu.workbook.model.internship; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.util.AppUtil.checkArgument; + +import seedu.workbook.commons.util.StringUtil; + +/** + * Represents an Internship's company in WorkBook. + * Guarantees: immutable; is valid as declared in + * {@link #isValidCompany(String)} + */ +public class Company { + + // CHECKSTYLE.OFF: LineLength + public static final String MESSAGE_CONSTRAINTS = "Company names should only contain alphanumeric characters and spaces, and it should not be blank"; + // CHECKSTYLE.ON: LineLength + + /* + * The first character of the Company must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String name; + + /** + * Constructs a {@code Company}. + * + * @param name A valid Company name. + */ + public Company(String name) { + requireNonNull(name); + checkArgument(isValidCompany(name), MESSAGE_CONSTRAINTS); + String modifiedName = StringUtil.toPascalCase(name); + this.name = modifiedName; + } + + /** + * Returns true if a given string is a valid Company Name. + */ + public static boolean isValidCompany(String test) { + return test.matches(VALIDATION_REGEX); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Company // instanceof handles nulls + && name.equals(((Company) other).name)); // state check + } + + + @Override + public int hashCode() { + return name.hashCode(); + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicate.java b/src/main/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicate.java new file mode 100644 index 00000000000..3e745be390e --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicate.java @@ -0,0 +1,31 @@ +package seedu.workbook.model.internship; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.workbook.commons.util.StringUtil; + +/** + * Tests that a {@code Internship}'s {@code Company} matches any of the keywords given. + */ +public class CompanyContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public CompanyContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Internship internship) { + return keywords.stream() + .allMatch(keyword -> StringUtil.containsWordIgnoreCase(internship.getCompany().name, keyword)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof CompanyContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((CompanyContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/DateTime.java b/src/main/java/seedu/workbook/model/internship/DateTime.java new file mode 100644 index 00000000000..76a2e8c1c1e --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/DateTime.java @@ -0,0 +1,97 @@ +package seedu.workbook.model.internship; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.util.AppUtil.checkArgument; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.format.ResolverStyle; + +/** + * Represents a DateTime in WorkBook. + * Guarantees: immutable; name is valid as declared in {@link #isValidDateTime(String)} + */ +public class DateTime { + public static final DateTime EMPTY_DATETIME = new DateTime(""); + public static final String MESSAGE_CONSTRAINTS = "Date should be formatted as dd-mmm-yyyy hh:mm," + + " and should actually exist."; + + private static final String datePattern = "d-MMM-uuuu HH:mm"; + private static final DateTimeFormatterBuilder formatterBuilder = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendPattern(datePattern); + private static final DateTimeFormatter dateFormatter = formatterBuilder.toFormatter() + .withResolverStyle(ResolverStyle.STRICT); + + + public final String value; + + /** + * Constructs a {@code DateTime}. + * + * @param dateTime A valid dateTime. + */ + public DateTime(String dateTime) { + requireNonNull(dateTime); + if (!dateTime.isEmpty()) { + checkArgument(isValidDateTime(dateTime), MESSAGE_CONSTRAINTS); + String str = String.join(" ", dateTime.split("\\s+", 2)); + this.value = LocalDateTime.parse(str, dateFormatter).format(dateFormatter); + } else { + this.value = ""; + } + } + + /** + * Returns true if a given string is a valid {@code DateTime}. + */ + public static boolean isValidDateTime(String test) { + try { + if (test.isEmpty()) { + return true; + } + String str = String.join(" ", test.split("\\s+", 2)); + LocalDateTime.parse(str, dateFormatter); + } catch (DateTimeParseException e) { + return false; + } + return true; + } + + /** + * Note that DateTimeParseException will be thrown if this is called on DateTime.EMPTY + */ + public boolean isAfter(DateTime other) { + LocalDateTime thisDate = LocalDateTime.parse(this.value, dateFormatter); + LocalDateTime otherDate = LocalDateTime.parse(other.value, dateFormatter); + return thisDate.isAfter(otherDate); + } + + /** + * Note that DateTimeParseException will be thrown if this is called on DateTime.EMPTY + */ + public boolean isPast() { + LocalDateTime thisDate = LocalDateTime.parse(this.value, dateFormatter); + return LocalDateTime.now().isAfter(thisDate); + } + + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DateTime // instanceof handles nulls + && value.equals(((DateTime) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/workbook/model/internship/Email.java similarity index 90% rename from src/main/java/seedu/address/model/person/Email.java rename to src/main/java/seedu/workbook/model/internship/Email.java index f866e7133de..40edc99ad5f 100644 --- a/src/main/java/seedu/address/model/person/Email.java +++ b/src/main/java/seedu/workbook/model/internship/Email.java @@ -1,14 +1,15 @@ -package seedu.address.model.person; +package seedu.workbook.model.internship; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static seedu.workbook.commons.util.AppUtil.checkArgument; /** - * Represents a Person's email in the address book. + * Represents a Person's email in the WorkBook. * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)} */ public class Email { + public static final Email EMPTY_EMAIL = new Email(""); private static final String SPECIAL_CHARACTERS = "+_.-"; public static final String MESSAGE_CONSTRAINTS = "Emails should be of the format local-part@domain " + "and adhere to the following constraints:\n" @@ -48,6 +49,9 @@ public Email(String email) { * Returns if a given string is a valid email. */ public static boolean isValidEmail(String test) { + if (test.isEmpty()) { + return true; + } return test.matches(VALIDATION_REGEX); } diff --git a/src/main/java/seedu/workbook/model/internship/Internship.java b/src/main/java/seedu/workbook/model/internship/Internship.java new file mode 100644 index 00000000000..83d0026ffbe --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/Internship.java @@ -0,0 +1,162 @@ +package seedu.workbook.model.internship; + +import static seedu.workbook.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import seedu.workbook.model.tag.Tag; + +/** + * Represents an Internship Application in WorkBook. + * Guarantees: details are present and not null, field values are validated, immutable. + */ +public class Internship { + + // Identity fields + private final Company company; + private final Role role; + private final Email email; + private final Stage stage; + private final DateTime dateTime; + + // Data fields + + private final Set languageTags = new HashSet<>(); + private final Set tags = new HashSet<>(); + + /** + * Every field must be present and not null. + */ + public Internship( + Company company, Role role, Email email, Stage stage, DateTime dateTime, + Set languageTags, Set tags) { + requireAllNonNull(company, role, email, stage, dateTime, tags); + this.company = company; + this.role = role; + this.email = email; + this.stage = stage; + this.dateTime = dateTime; + this.languageTags.addAll(languageTags); + this.tags.addAll(tags); + } + + public Company getCompany() { + return company; + } + + public Role getRole() { + return role; + } + + + public Email getEmail() { + return email; + } + public Stage getStage() { + return stage; + } + public DateTime getDateTime() { + return dateTime; + } + + /** + * Returns an immutable language tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + */ + public Set getLanguageTags() { + return Collections.unmodifiableSet(languageTags); + } + + /** + * Returns an immutable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + */ + public Set getTags() { + return Collections.unmodifiableSet(tags); + } + + /** + * Returns true if both internships have the same company AND role. + * This defines a weaker notion of equality between two internships. + */ + public boolean isSameInternship(Internship otherInternship) { + if (otherInternship == this) { + return true; + } + + return otherInternship != null + && otherInternship.getCompany().equals(getCompany()) + && otherInternship.getRole().equals(getRole()); + } + + public boolean stageHasNoTips() { + return this.getStage().hasNoTips(); + } + + /** + * Returns true if both internships have the same identity and data fields. + * This defines a stronger notion of equality between two internships. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof Internship)) { + return false; + } + + Internship otherInternship = (Internship) other; + return otherInternship.getCompany().equals(getCompany()) + && otherInternship.getRole().equals(getRole()) + && otherInternship.getEmail().equals(getEmail()) + && otherInternship.getStage().equals(getStage()) + && otherInternship.getDateTime().equals(getDateTime()) + && otherInternship.getLanguageTags().equals(getLanguageTags()) + && otherInternship.getTags().equals(getTags()); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(company, role, email, stage, dateTime, languageTags, tags); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(getCompany()) + .append("; Role: ") + .append(getRole()) + .append("; Stage: ") + .append(getStage()); + + if (!getDateTime().value.isEmpty()) { + builder.append("; Date: ") + .append(getDateTime()); + } + + if (!getEmail().value.isEmpty()) { + builder.append("; Email: ") + .append(getEmail()); + } + + Set languageTags = getLanguageTags(); + if (!languageTags.isEmpty()) { + builder.append("; Language Tags: "); + languageTags.forEach(builder::append); + } + + Set tags = getTags(); + if (!tags.isEmpty()) { + builder.append("; Tags: "); + tags.forEach(builder::append); + } + return builder.toString(); + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/InternshipComparator.java b/src/main/java/seedu/workbook/model/internship/InternshipComparator.java new file mode 100644 index 00000000000..76d7f234022 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/InternshipComparator.java @@ -0,0 +1,34 @@ +package seedu.workbook.model.internship; + +import java.util.Comparator; + +/** + * Comparator used for sorting the Internship list by Date. + */ +public class InternshipComparator implements Comparator { + + @Override + public int compare(Internship o1, Internship o2) { + DateTime o1DateTime = o1.getDateTime(); + DateTime o2DateTime = o2.getDateTime(); + + if (o1DateTime.equals(DateTime.EMPTY_DATETIME)) { + return o2DateTime.equals(DateTime.EMPTY_DATETIME) + ? o1.getCompany().name.compareTo(o2.getCompany().name) + : o2DateTime.isPast() + ? -1 + : 1; + } + + if (o1DateTime.isPast()) { + return o2DateTime.equals(DateTime.EMPTY_DATETIME) || o2DateTime.isAfter(o1DateTime) + ? 1 + : -1; + } + + return (o2DateTime.equals(DateTime.EMPTY_DATETIME) || o2DateTime.isPast()) + || o2DateTime.isAfter(o1DateTime) + ? -1 + : 1; + } +} diff --git a/src/main/java/seedu/workbook/model/internship/Role.java b/src/main/java/seedu/workbook/model/internship/Role.java new file mode 100644 index 00000000000..f0ffe55fe38 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/Role.java @@ -0,0 +1,63 @@ +package seedu.workbook.model.internship; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.util.AppUtil.checkArgument; + +import seedu.workbook.commons.util.StringUtil; + +/** + * Represents an Internship's role in WorkBook. + * Guarantees: immutable; is valid as declared in {@link #isValidRole(String)} + */ +public class Role { + + // CHECKSTYLE.OFF: LineLength + public static final String MESSAGE_CONSTRAINTS = "Role titles should only contain alphanumeric characters and spaces, and it should not be blank"; + // CHECKSTYLE.ON: LineLength + + /* + * The first character of the Role must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String value; + + /** + * Constructs a {@code Role}. + * + * @param role A valid Role title. + */ + public Role(String role) { + requireNonNull(role); + checkArgument(isValidRole(role), MESSAGE_CONSTRAINTS); + String modifiedRole = StringUtil.toPascalCase(role); + value = modifiedRole; + } + + /** + * Returns true if a given string is a valid Role. + */ + public static boolean isValidRole(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 Role // instanceof handles nulls + && value.equals(((Role) other).value)); // state check + } + + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/RoleContainsKeywordsPredicate.java b/src/main/java/seedu/workbook/model/internship/RoleContainsKeywordsPredicate.java new file mode 100644 index 00000000000..d68887df7ea --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/RoleContainsKeywordsPredicate.java @@ -0,0 +1,31 @@ +package seedu.workbook.model.internship; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.workbook.commons.util.StringUtil; + +/** + * Tests that a {@code Internship}'s {@code Role} matches any of the keywords given. + */ +public class RoleContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public RoleContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Internship internship) { + return keywords.stream() + .allMatch(keyword -> StringUtil.containsWordIgnoreCase(internship.getRole().value, keyword)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof RoleContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((RoleContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/Stage.java b/src/main/java/seedu/workbook/model/internship/Stage.java new file mode 100644 index 00000000000..f00213e71cc --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/Stage.java @@ -0,0 +1,71 @@ +package seedu.workbook.model.internship; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.util.AppUtil.checkArgument; + +import seedu.workbook.commons.util.StringUtil; +import seedu.workbook.model.internship.util.StageUtil; + +/** + * Represents an Internship's application stage in WorkBook. + * Guarantees: immutable; is valid as declared in {@link #isValidStage(String)} + */ +public class Stage { + + // CHECKSTYLE.OFF: LineLength + public static final String MESSAGE_CONSTRAINTS = "Stage should only contain alphanumeric characters and spaces, and it should not be blank"; + // CHECKSTYLE.ON: LineLength + + /* + * The first character of the Stage must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String value; + + /** + * Constructs a {@code Stage}. + * + * @param stage A valid Stage name. + */ + public Stage(String stage) { + requireNonNull(stage); + checkArgument(isValidStage(stage), MESSAGE_CONSTRAINTS); + String modifiedStage = StringUtil.toPascalCase(stage); + value = modifiedStage; + } + + /** + * Returns true if a given string is a valid stage. + */ + public static boolean isValidStage(String test) { + return test.matches(VALIDATION_REGEX); + } + + /** + * Returns true if a given stage does not have curated tips. + */ + public boolean hasNoTips() { + return !StageUtil.stageHasTips(this); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Stage // instanceof handles nulls + && value.equals(((Stage) other).value)); // state check + } + + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/StageContainsKeywordsPredicate.java b/src/main/java/seedu/workbook/model/internship/StageContainsKeywordsPredicate.java new file mode 100644 index 00000000000..04408d65245 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/StageContainsKeywordsPredicate.java @@ -0,0 +1,31 @@ +package seedu.workbook.model.internship; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.workbook.commons.util.StringUtil; + +/** + * Tests that a {@code Internship}'s {@code Stage} matches any of the keywords given. + */ +public class StageContainsKeywordsPredicate implements Predicate { + private final List keywords; + + public StageContainsKeywordsPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Internship internship) { + return keywords.stream() + .allMatch(keyword -> StringUtil.containsWordIgnoreCase(internship.getStage().value, keyword)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof StageContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((StageContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/workbook/model/internship/UniqueInternshipList.java b/src/main/java/seedu/workbook/model/internship/UniqueInternshipList.java new file mode 100644 index 00000000000..4c5525e20c4 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/UniqueInternshipList.java @@ -0,0 +1,160 @@ +package seedu.workbook.model.internship; + +import static java.util.Objects.requireNonNull; +import static seedu.workbook.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Iterator; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.collections.transformation.SortedList; +import seedu.workbook.model.internship.exceptions.DuplicateInternshipException; +import seedu.workbook.model.internship.exceptions.InternshipNotFoundException; + +/** + * A list of internships that enforces uniqueness between its elements and does + * not allow nulls. + * A internship is considered unique by comparing using + * {@code Internship#isSameInternship(Internship)}. + * + * As such, adding and updating of internships uses + * Internship#isSameInternship(Internship) for equality so as to ensure that the + * internship being added or updated is unique in terms of identity in the + * UniqueInternshipList. + * + * However, the removal of an internship uses Internship#equals(Object) so as to + * ensure that the internship with exactly the same fields will be removed. + * + * Supports a minimal set of list operations. + * + * @see Internship#isSameInternship(Internship) + */ +public class UniqueInternshipList implements Iterable { + + // All updates should be performed only on internalList + private final ObservableList internalList = FXCollections.observableArrayList(); + + // wrapper on internalList, is automatically updated whenever + // internalList is updated, and is always in sorted order w.r.t + // InternshipComparator + private final SortedList sortedInternalList = new SortedList<>(internalList, + new InternshipComparator()); + + // is observed by UI components/external objects + private final ObservableList unmodifiableSortedInternalList = FXCollections + .unmodifiableObservableList(sortedInternalList); + + /** + * Returns true if the list contains an equivalent internship as the given + * argument. + */ + public boolean contains(Internship toCheck) { + requireNonNull(toCheck); + return internalList.stream().anyMatch(toCheck::isSameInternship); + } + + /** + * Adds an Internship to the list. + * The Internship must not already exist in the list. + */ + public void add(Internship toAdd) { + requireNonNull(toAdd); + if (contains(toAdd)) { + throw new DuplicateInternshipException(); + } + internalList.add(toAdd); + } + + /** + * Replaces the Internship {@code target} in the list with + * {@code editedInternship}. + * {@code target} must exist in the list. + * The Internship identity of {@code editedInternship} must not be the same as + * another existing Internship in the list. + */ + public void setInternship(Internship target, Internship editedInternship) { + requireAllNonNull(target, editedInternship); + + int index = internalList.indexOf(target); + if (index == -1) { + throw new InternshipNotFoundException(); + } + + if (!target.isSameInternship(editedInternship) && contains(editedInternship)) { + throw new DuplicateInternshipException(); + } + + internalList.set(index, editedInternship); + } + + /** + * Removes the equivalent Internship from the list. + * The Internship must exist in the list. + */ + public void remove(Internship toRemove) { + requireNonNull(toRemove); + if (!internalList.remove(toRemove)) { + throw new InternshipNotFoundException(); + } + } + + public void setInternships(UniqueInternshipList replacement) { + requireNonNull(replacement); + internalList.setAll(replacement.internalList); + } + + /** + * Replaces the contents of this list with {@code Internships}. + * {@code Internships} must not contain duplicate Internships. + */ + public void setInternships(List internships) { + requireAllNonNull(internships); + if (!internshipsAreUnique(internships)) { + throw new DuplicateInternshipException(); + } + + internalList.setAll(internships); + } + + /** + * Returns the sorted list as an unmodifiable {@code ObservableList}. + * + * @see seedu.workbook.ui.MainWindow#fillInnerParts() + * @see seedu.workbook.storage.JsonSerializableWorkBook#JsonSerializableWorkBook(ReadOnlyWorkBook) + */ + public ObservableList asUnmodifiableObservableList() { + return unmodifiableSortedInternalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueInternshipList // instanceof handles nulls + && sortedInternalList.equals(((UniqueInternshipList) other).sortedInternalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + + /** + * Returns true if {@code internships} contains only unique internships. + */ + private boolean internshipsAreUnique(List internships) { + for (int i = 0; i < internships.size() - 1; i++) { + for (int j = i + 1; j < internships.size(); j++) { + if (internships.get(i).isSameInternship(internships.get(j))) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/seedu/workbook/model/internship/exceptions/DuplicateInternshipException.java b/src/main/java/seedu/workbook/model/internship/exceptions/DuplicateInternshipException.java new file mode 100644 index 00000000000..2bbe7114a02 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/exceptions/DuplicateInternshipException.java @@ -0,0 +1,11 @@ +package seedu.workbook.model.internship.exceptions; + +/** + * Signals that the operation will result in duplicate Internships (Internships + * are considered duplicates if they have the same identity). + */ +public class DuplicateInternshipException extends RuntimeException { + public DuplicateInternshipException() { + super("Operation would result in duplicate internship applications"); + } +} diff --git a/src/main/java/seedu/workbook/model/internship/exceptions/InternshipNotFoundException.java b/src/main/java/seedu/workbook/model/internship/exceptions/InternshipNotFoundException.java new file mode 100644 index 00000000000..4b03291e342 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/exceptions/InternshipNotFoundException.java @@ -0,0 +1,6 @@ +package seedu.workbook.model.internship.exceptions; + +/** + * Signals that the operation is unable to find the specified internship. + */ +public class InternshipNotFoundException extends RuntimeException {} diff --git a/src/main/java/seedu/workbook/model/internship/util/StageUtil.java b/src/main/java/seedu/workbook/model/internship/util/StageUtil.java new file mode 100644 index 00000000000..74779135386 --- /dev/null +++ b/src/main/java/seedu/workbook/model/internship/util/StageUtil.java @@ -0,0 +1,136 @@ +package seedu.workbook.model.internship.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import seedu.workbook.model.internship.Stage; + +/** + * Contains utility methods used in implementing methods regarding {@code Stage} for GUI. + */ +public class StageUtil { + + private static final List stagesWithTips = Arrays.asList( + new Stage("Application Sent"), + new Stage("Online Assessment"), + new Stage("Technical Interview"), + new Stage("Behavioral Interview"), + new Stage("Phone Interview"), + new Stage("Rejected") + ); + + // CHECKSTYLE.OFF: LineLength + private static final List applicationSentTips = Arrays.asList( + "Contact the hiring manager/recruitment by submitting a short follow-up email to show interest in the company and stand out!", + "Keep a copy of your resume by the phone so that you can refer to them and answer questions if the company were to call you for a short interview!", + "Conduct a detailed research on the organisation you applied for, especially their mission statement, policies, initiatives and programmes to prepare for a potential interview!", + "Prepare for interviews and assessment by brushing up on your interview and coding skills! Refer to our tips included in “Online Assessment”, “Technical Interview” and “Behavioural Interview” for more advice!" + ); + + // 'Algorithm cheat sheets': https://www.techinterviewhandbook.org/algorithms/study-cheatsheet/ + // 'LeetCode': https://leetcode.com/ + private static final List onlineAssessmentTips = Arrays.asList( + "Decide on a programming language! We highly recommend Python as it has a huge library of useful functions and data structures!", + "Remember to make a note of all the important keywords in the question!", + "Algorithms cheat sheets - This includes the must-remembers that you should internalize for every data structure.", + "Keep Practicing. Not sure which questions to try? Have a look at LeetCode!" + ); + + // 'STAR': https://www.themuse.com/advice/star-interview-method + // 'online mock interviews': https://interviewing.io/?urc=DMCa + private static final List technicalInterviewTips = Arrays.asList( + "Do not jump into coding right away. Coding questions tend to be vague and underspecified on purpose to gauge your attention to detail and carefulness. Ask at least 2-3 clarifying questions!", + "Before starting, go through the different ways you could solve this question, discussing the time and space complexity tradeoffs!", + "Explain what you are trying to achieve as you are coding to your interviewer, so he knows exactly what you are doing at each step!", + "Once finished, remember to ALWAYS check that your code compiles and works for edge cases as well!" + ); + + private static final List behavioralInterviewTips = Arrays.asList( + "Mainly looking at your soft-skills and your ability to adapt and navigate about scenarios presented in the workplace.", + "Prepare relevant-to-the-role experiences beforehand, especially if it’s from school projects because you’re still a student! ;)", + "Try out the STAR framework to keep your answers concise and relevant to the question.", + "Be yourself! Be natural and confident. If it helps, practice with a friend and let them evaluate you. You can also try scheduling online mock interviews to put your skills to the test." + ); + + private static final List phoneInterviewTips = Arrays.asList( + "A recruiter is looking for the following indicators during the Phone Interview: Passion for tech/coding, Enthusiasm, Communication skills, Culture fit, Alignment with company mission/values", + "As such, focus on displaying your soft skills (Show not tell!)", + "Radiate excitement about the company or project, and that positivity will make a good first impression on your interviewer.", + "Be honest: What interests you the most about this job? What kinds of projects were you hoping to work on?", + "Do your research and tailor your answers to the exact position and company you’re interviewing for.", + "Look for opportunities to show your value alignment. Show that you support the mission of the organization." + ); + + private static final List rejectedTips = Arrays.asList( + "Acknowledge your emotions and feelings about the rejection. Don’t worry, it is perfectly normal to feel this way but don’t give up!", + "Remind yourself that you are competent. Getting rejected does not mean you are not qualified, it could just mean that there was an applicant more suitable for the particular job! Capitalise on the skills and expertise that are unique to yourself!", + "Express gratitude by thanking the company for the opportunity and taking the time to know you better! If you are interested in applying to the company in the future, do also maintain a good impression and let them know about it! :)", + "Ask for feedback from the company so that you can do better the next time! It’ll be good to find out what went well, what could be improved on and how to go about improving them!", + "Most importantly, keep trying and move on to the next opportunity, they are plenty awaiting you! Sharpen, refine your skills before applying for internships again, you’ll be one step closer to landing the internship of your dream!" + ); + // CHECKSTYLE.ON: LineLength + + private static final List> listOfTips = Arrays.asList( + applicationSentTips, + onlineAssessmentTips, + technicalInterviewTips, + behavioralInterviewTips, + phoneInterviewTips, + rejectedTips + ); + + + private static final Map> tipsForStage = new HashMap<>(); + + /* + * Static initialization block to populate the map. + * Each stage is mapped to a list of tips. + */ + static { + for (int i = 0; i < stagesWithTips.size(); i++) { + tipsForStage.put(stagesWithTips.get(i), listOfTips.get(i)); + } + } + + /** + * Returns the list of stages with curated tips. + */ + public static List getStagesWithTips() { + return stagesWithTips; + } + + /** + * Returns a list of tips if stage is present in {@code stagesWithTips}, + * otherwise return an empty list. + * @param stage the given stage + * @return a list of stage-specific tips + */ + public static List getStageSpecificTips(Stage stage) { + return (!stagesWithTips.contains(stage)) + ? Collections.emptyList() + : tipsForStage.get(stage); + } + + + /** + * Checks if a stage is in the pre-defined list of stages which has tips. + * @param stage the given stage + * @return true if the stage has tips + */ + public static boolean stageHasTips(Stage stage) { + return stagesWithTips.contains(stage); + } + + /** + * Returns the list of stages with curated tips as a string + * for {@code CommandResult} message to hint users on + * the stages we have tips for. + */ + public static String stagesWithTipsToString() { + return stagesWithTips.toString(); + } + +} diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/workbook/model/tag/Tag.java similarity index 65% rename from src/main/java/seedu/address/model/tag/Tag.java rename to src/main/java/seedu/workbook/model/tag/Tag.java index b0ea7e7dad7..62f9c441e90 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/seedu/workbook/model/tag/Tag.java @@ -1,16 +1,14 @@ -package seedu.address.model.tag; +package seedu.workbook.model.tag; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; /** - * Represents a Tag in the address book. - * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)} + * Represents a Tag in WorkBook. + * Guarantees: immutable; any String is taken as a valid Tag/Language Tag */ 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 = "Tag names should not be blank"; public final String tagName; @@ -21,7 +19,6 @@ public class Tag { */ public Tag(String tagName) { requireNonNull(tagName); - checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS); this.tagName = tagName; } @@ -29,7 +26,7 @@ public Tag(String tagName) { * Returns true if a given string is a valid tag name. */ public static boolean isValidTagName(String test) { - return test.matches(VALIDATION_REGEX); + return !test.isBlank(); } @Override diff --git a/src/main/java/seedu/workbook/model/util/SampleDataUtil.java b/src/main/java/seedu/workbook/model/util/SampleDataUtil.java new file mode 100644 index 00000000000..069eaa1021c --- /dev/null +++ b/src/main/java/seedu/workbook/model/util/SampleDataUtil.java @@ -0,0 +1,91 @@ +package seedu.workbook.model.util; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.tag.Tag; + +/** + * Contains utility methods for populating {@code WorkBook} with sample data. + */ +public class SampleDataUtil { + public static Internship[] getSampleInternships() { + return new Internship[] { + new Internship( + new Company("Jane Street"), + new Role("Software Engineer"), + new Email("hr@janestreet.com"), + new Stage("HR Interview"), + new DateTime("11-Dec-2022 15:30"), + getTagSet("OCaml"), + getTagSet("remote")), + new Internship( + new Company("Hudson River Trading"), + new Role("Algorithm Engineer"), + new Email("teamlead@hrt.com"), + new Stage("Interview with Team Lead"), + new DateTime("11-Dec-2022 18:30"), + getTagSet("Python"), + getTagSet("quant")), + new Internship( + new Company("Shopee"), + new Role("Android Engineer"), + Email.EMPTY_EMAIL, + new Stage("Online Assessment"), + new DateTime("12-Dec-2022 18:30"), + getTagSet("Kotlin"), + getTagSet("backup")), + new Internship( + new Company("Visa"), + new Role("Backend Engineer"), + Email.EMPTY_EMAIL, + new Stage("Technical Interview"), + new DateTime("15-Oct-2022 16:00"), + getTagSet("Java"), + getTagSet("payments")), + new Internship( + new Company("Binance"), + new Role("Blockchain Engineer"), + new Email("hr@binance.com"), + new Stage("Application Sent"), + DateTime.EMPTY_DATETIME, + getTagSet("Solidity"), + getTagSet("crypto")), + new Internship( + new Company("Optiver"), + new Role("Software Engineer"), + Email.EMPTY_EMAIL, + new Stage("Rejected"), + new DateTime("20-Oct-2022 10:20"), + getTagSet("Rust"), + getTagSet("trading")) + }; + } + + public static ReadOnlyWorkBook getSampleWorkBook() { + WorkBook sampleWb = new WorkBook(); + for (Internship sampleInternship : getSampleInternships()) { + sampleWb.addInternship(sampleInternship); + } + return sampleWb; + } + + /** + * 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/workbook/storage/JsonAdaptedDateTime.java b/src/main/java/seedu/workbook/storage/JsonAdaptedDateTime.java new file mode 100644 index 00000000000..051aec4dc9f --- /dev/null +++ b/src/main/java/seedu/workbook/storage/JsonAdaptedDateTime.java @@ -0,0 +1,50 @@ +/* +package seedu.workbook.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import seedu.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.model.internship.DateTime; + +public class JsonAdaptedDateTime { + + private final String date; + */ +/** + * Constructs a {@code JsonAdaptedDateTime} with the given {@code daye}. + *//* + + @JsonCreator + public JsonAdaptedDateTime(String date) { + this.date = date; + } + + */ +/** + * Converts a given {@code DateTime} into this class for Jackson use. + *//* + + public JsonAdaptedDateTime(DateTime source) { + date = source.value; + } + + @JsonValue + public String getDateTime() { + return date; + } + + */ +/** + * Converts this Jackson-friendly adapted date object into the model's {@code DateTime} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted date. + *//* + + public DateTime toModelType() throws IllegalValueException { + if (!DateTime.isValidDate(date)) { + throw new IllegalValueException(DateTime.MESSAGE_CONSTRAINTS); + } + return new DateTime(date); + } +} +*/ diff --git a/src/main/java/seedu/workbook/storage/JsonAdaptedInternship.java b/src/main/java/seedu/workbook/storage/JsonAdaptedInternship.java new file mode 100644 index 00000000000..293cb2350b0 --- /dev/null +++ b/src/main/java/seedu/workbook/storage/JsonAdaptedInternship.java @@ -0,0 +1,143 @@ +package seedu.workbook.storage; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import seedu.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.tag.Tag; + +/** + * Jackson-friendly version of {@link Internship}. + */ +class JsonAdaptedInternship { + + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Internship's %s field is missing!"; + + private final String company; + private final String role; + private final String email; + private final String stage; + private final String dateTime; + private final List languages = new ArrayList<>(); + private final List tagged = new ArrayList<>(); + + /** + * Constructs a {@code JsonAdaptedInternship} with the given Internship details. + */ + @JsonCreator + public JsonAdaptedInternship(@JsonProperty("company") String company, @JsonProperty("role") String role, + @JsonProperty("email") String email, + @JsonProperty("stage") String stage, + @JsonProperty("dateTime") String dateTime, + @JsonProperty("languages") List languages, + @JsonProperty("tagged") List tagged) { + this.company = company; + this.role = role; + this.email = email; + this.stage = stage; + this.dateTime = dateTime; + if (languages != null) { + this.languages.addAll(languages); + } + if (tagged != null) { + this.tagged.addAll(tagged); + } + } + + /** + * Converts a given {@code Internship} into this class for Jackson use. + */ + public JsonAdaptedInternship(Internship source) { + company = source.getCompany().name; + role = source.getRole().value; + email = source.getEmail().value; + stage = source.getStage().value; + dateTime = source.getDateTime().value; + languages.addAll(source.getLanguageTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList())); + tagged.addAll(source.getTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList())); + } + + /** + * Converts this Jackson-friendly adapted Internship object into the model's + * {@code Internship} object. + * + * @throws IllegalValueException if there were any data constraints violated in + * the adapted Internship. + */ + public Internship toModelType() throws IllegalValueException { + final List languageTags = new ArrayList<>(); + for (JsonAdaptedTag language : languages) { + languageTags.add(language.toModelType()); + } + + final List tags = new ArrayList<>(); + for (JsonAdaptedTag tag : tagged) { + tags.add(tag.toModelType()); + } + + if (company == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Company.class.getSimpleName())); + } + if (!Company.isValidCompany(company)) { + throw new IllegalValueException(Company.MESSAGE_CONSTRAINTS); + } + final Company modelCompany = new Company(company); + + if (role == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Role.class.getSimpleName())); + } + if (!Role.isValidRole(role)) { + throw new IllegalValueException(Role.MESSAGE_CONSTRAINTS); + } + final Role modelRole = new Role(role); + + if (email == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName())); + } + if (!Email.isValidEmail(email)) { + throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS); + } + final Email modelEmail = new Email(email); + + if (stage == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Stage.class.getSimpleName())); + } + if (!Stage.isValidStage(stage)) { + throw new IllegalValueException(Stage.MESSAGE_CONSTRAINTS); + } + final Stage modelStage = new Stage(stage); + + if (dateTime == null) { + throw new IllegalValueException( + String.format(MISSING_FIELD_MESSAGE_FORMAT, DateTime.class.getSimpleName())); + } + if (!DateTime.isValidDateTime(dateTime)) { + throw new IllegalValueException(DateTime.MESSAGE_CONSTRAINTS); + } + final DateTime modelDateTime = new DateTime(dateTime); + + final Set modelLanguageTags = new HashSet<>(languageTags); + + final Set modelTags = new HashSet<>(tags); + + return new Internship(modelCompany, modelRole, modelEmail, modelStage, modelDateTime, modelLanguageTags, + modelTags); + } + +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/workbook/storage/JsonAdaptedTag.java similarity index 89% rename from src/main/java/seedu/address/storage/JsonAdaptedTag.java rename to src/main/java/seedu/workbook/storage/JsonAdaptedTag.java index 0df22bdb754..09d736f9c2b 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java +++ b/src/main/java/seedu/workbook/storage/JsonAdaptedTag.java @@ -1,10 +1,10 @@ -package seedu.address.storage; +package seedu.workbook.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 seedu.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.model.tag.Tag; /** * Jackson-friendly version of {@link Tag}. diff --git a/src/main/java/seedu/workbook/storage/JsonSerializableWorkBook.java b/src/main/java/seedu/workbook/storage/JsonSerializableWorkBook.java new file mode 100644 index 00000000000..d93435e5901 --- /dev/null +++ b/src/main/java/seedu/workbook/storage/JsonSerializableWorkBook.java @@ -0,0 +1,62 @@ +package seedu.workbook.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.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.internship.Internship; + +/** + * An Immutable WorkBook that is serializable to JSON format. + */ +@JsonRootName(value = "workbook") +class JsonSerializableWorkBook { + + public static final String MESSAGE_DUPLICATE_INTERNSHIP = "Internship list contains duplicate internship(s)."; + + private final List internships = new ArrayList<>(); + + /** + * Constructs a {@code JsonSerializableWorkBook} with the given internships. + */ + @JsonCreator + public JsonSerializableWorkBook(@JsonProperty("internships") List internships) { + this.internships.addAll(internships); + } + + /** + * Converts a given {@code ReadOnlyWorkBook} into this class for Jackson use. + * + * @param source future changes to this will not affect the created + * {@code JsonSerializableWorkBook}. + */ + public JsonSerializableWorkBook(ReadOnlyWorkBook source) { + internships.addAll( + source.getInternshipList().stream().map(JsonAdaptedInternship::new).collect(Collectors.toList())); + } + + /** + * Converts this work book into the model's {@code WorkBook} object. + * + * @throws IllegalValueException if there were any data constraints violated. + */ + public WorkBook toModelType() throws IllegalValueException { + WorkBook workBook = new WorkBook(); + for (JsonAdaptedInternship jsonAdaptedInternship : internships) { + Internship internship = jsonAdaptedInternship.toModelType(); + if (workBook.hasInternship(internship)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_INTERNSHIP); + } + workBook.addInternship(internship); + } + return workBook; + } + +} diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/workbook/storage/JsonUserPrefsStorage.java similarity index 82% rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java rename to src/main/java/seedu/workbook/storage/JsonUserPrefsStorage.java index bc2bbad84aa..7a6d9f937f7 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/seedu/workbook/storage/JsonUserPrefsStorage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; +package seedu.workbook.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 seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.commons.util.JsonUtil; +import seedu.workbook.model.ReadOnlyUserPrefs; +import seedu.workbook.model.UserPrefs; /** * A class to access UserPrefs stored in the hard disk as a json file diff --git a/src/main/java/seedu/workbook/storage/JsonWorkBookStorage.java b/src/main/java/seedu/workbook/storage/JsonWorkBookStorage.java new file mode 100644 index 00000000000..bdfe2fecdc4 --- /dev/null +++ b/src/main/java/seedu/workbook/storage/JsonWorkBookStorage.java @@ -0,0 +1,80 @@ +package seedu.workbook.storage; + +import static java.util.Objects.requireNonNull; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.logging.Logger; + +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.commons.util.FileUtil; +import seedu.workbook.commons.util.JsonUtil; +import seedu.workbook.model.ReadOnlyWorkBook; + +/** + * A class to access WorkBook data stored as a json file on the hard disk. + */ +public class JsonWorkBookStorage implements WorkBookStorage { + + private static final Logger logger = LogsCenter.getLogger(JsonWorkBookStorage.class); + + private Path filePath; + + public JsonWorkBookStorage(Path filePath) { + this.filePath = filePath; + } + + public Path getWorkBookFilePath() { + return filePath; + } + + @Override + public Optional readWorkBook() throws DataConversionException { + return readWorkBook(filePath); + } + + /** + * Similar to {@link #readWorkBook()}. + * + * @param filePath location of the data. Cannot be null. + * @throws DataConversionException if the file is not in the correct format. + */ + public Optional readWorkBook(Path filePath) throws DataConversionException { + requireNonNull(filePath); + + Optional jsonWorkBook = JsonUtil.readJsonFile( + filePath, JsonSerializableWorkBook.class); + if (!jsonWorkBook.isPresent()) { + return Optional.empty(); + } + + try { + return Optional.of(jsonWorkBook.get().toModelType()); + } catch (IllegalValueException ive) { + logger.info("Illegal values found in " + filePath + ": " + ive.getMessage()); + throw new DataConversionException(ive); + } + } + + @Override + public void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException { + saveWorkBook(workBook, filePath); + } + + /** + * Similar to {@link #saveWorkBook(ReadOnlyWorkBook)}. + * + * @param filePath location of the data. Cannot be null. + */ + public void saveWorkBook(ReadOnlyWorkBook workBook, Path filePath) throws IOException { + requireNonNull(workBook); + requireNonNull(filePath); + + FileUtil.createIfMissing(filePath); + JsonUtil.saveJsonFile(new JsonSerializableWorkBook(workBook), filePath); + } + +} diff --git a/src/main/java/seedu/workbook/storage/Storage.java b/src/main/java/seedu/workbook/storage/Storage.java new file mode 100644 index 00000000000..f13b2704184 --- /dev/null +++ b/src/main/java/seedu/workbook/storage/Storage.java @@ -0,0 +1,32 @@ +package seedu.workbook.storage; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.model.ReadOnlyUserPrefs; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.UserPrefs; + +/** + * API of the Storage component + */ +public interface Storage extends WorkBookStorage, UserPrefsStorage { + + @Override + Optional readUserPrefs() throws DataConversionException, IOException; + + @Override + void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException; + + @Override + Path getWorkBookFilePath(); + + @Override + Optional readWorkBook() throws DataConversionException, IOException; + + @Override + void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException; + +} diff --git a/src/main/java/seedu/workbook/storage/StorageManager.java b/src/main/java/seedu/workbook/storage/StorageManager.java new file mode 100644 index 00000000000..90a20eea00c --- /dev/null +++ b/src/main/java/seedu/workbook/storage/StorageManager.java @@ -0,0 +1,78 @@ +package seedu.workbook.storage; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.logging.Logger; + +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.model.ReadOnlyUserPrefs; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.UserPrefs; + +/** + * Manages storage of WorkBook data in local storage. + */ +public class StorageManager implements Storage { + + private static final Logger logger = LogsCenter.getLogger(StorageManager.class); + private WorkBookStorage workBookStorage; + private UserPrefsStorage userPrefsStorage; + + /** + * Creates a {@code StorageManager} with the given {@code WorkBookStorage} and {@code UserPrefStorage}. + */ + public StorageManager(WorkBookStorage workBookStorage, UserPrefsStorage userPrefsStorage) { + this.workBookStorage = workBookStorage; + this.userPrefsStorage = userPrefsStorage; + } + + // ================ UserPrefs methods ============================== + + @Override + public Path getUserPrefsFilePath() { + return userPrefsStorage.getUserPrefsFilePath(); + } + + @Override + public Optional readUserPrefs() throws DataConversionException, IOException { + return userPrefsStorage.readUserPrefs(); + } + + @Override + public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException { + userPrefsStorage.saveUserPrefs(userPrefs); + } + + + // ================ WorkBook methods ============================== + + @Override + public Path getWorkBookFilePath() { + return workBookStorage.getWorkBookFilePath(); + } + + @Override + public Optional readWorkBook() throws DataConversionException, IOException { + return readWorkBook(workBookStorage.getWorkBookFilePath()); + } + + @Override + public Optional readWorkBook(Path filePath) throws DataConversionException, IOException { + logger.fine("Attempting to read data from file: " + filePath); + return workBookStorage.readWorkBook(filePath); + } + + @Override + public void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException { + saveWorkBook(workBook, workBookStorage.getWorkBookFilePath()); + } + + @Override + public void saveWorkBook(ReadOnlyWorkBook workBook, Path filePath) throws IOException { + logger.fine("Attempting to write to data file: " + filePath); + workBookStorage.saveWorkBook(workBook, filePath); + } + +} diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/workbook/storage/UserPrefsStorage.java similarity index 71% rename from src/main/java/seedu/address/storage/UserPrefsStorage.java rename to src/main/java/seedu/workbook/storage/UserPrefsStorage.java index 29eef178dbc..f70b18c4b8a 100644 --- a/src/main/java/seedu/address/storage/UserPrefsStorage.java +++ b/src/main/java/seedu/workbook/storage/UserPrefsStorage.java @@ -1,15 +1,15 @@ -package seedu.address.storage; +package seedu.workbook.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 seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.model.ReadOnlyUserPrefs; +import seedu.workbook.model.UserPrefs; /** - * Represents a storage for {@link seedu.address.model.UserPrefs}. + * Represents a storage for {@link seedu.workbook.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 seedu.workbook.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/workbook/storage/WorkBookStorage.java b/src/main/java/seedu/workbook/storage/WorkBookStorage.java new file mode 100644 index 00000000000..8f890686d84 --- /dev/null +++ b/src/main/java/seedu/workbook/storage/WorkBookStorage.java @@ -0,0 +1,45 @@ +package seedu.workbook.storage; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.model.ReadOnlyWorkBook; + +/** + * Represents a storage for {@link seedu.workbook.model.WorkBook}. + */ +public interface WorkBookStorage { + + /** + * Returns the file path of the data file. + */ + Path getWorkBookFilePath(); + + /** + * Returns WorkBook data as a {@link ReadOnlyWorkBook}. + * 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 readWorkBook() throws DataConversionException, IOException; + + /** + * @see #getWorkBookFilePath() + */ + Optional readWorkBook(Path filePath) throws DataConversionException, IOException; + + /** + * Saves the given {@link ReadOnlyWorkBook} to the storage. + * @param workBook cannot be null. + * @throws IOException if there was any problem writing to the file. + */ + void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException; + + /** + * @see #saveWorkBook(ReadOnlyWorkBook) + */ + void saveWorkBook(ReadOnlyWorkBook workBook, Path filePath) throws IOException; + +} diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/workbook/ui/CommandBox.java similarity index 89% rename from src/main/java/seedu/address/ui/CommandBox.java rename to src/main/java/seedu/workbook/ui/CommandBox.java index 9e75478664b..cdc8b2767d6 100644 --- a/src/main/java/seedu/address/ui/CommandBox.java +++ b/src/main/java/seedu/workbook/ui/CommandBox.java @@ -1,12 +1,12 @@ -package seedu.address.ui; +package seedu.workbook.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 seedu.workbook.logic.commands.CommandResult; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.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 seedu.workbook.logic.Logic#execute(String) */ CommandResult execute(String commandText) throws CommandException, ParseException; } diff --git a/src/main/java/seedu/workbook/ui/HelpCard.java b/src/main/java/seedu/workbook/ui/HelpCard.java new file mode 100644 index 00000000000..69fc389fcc3 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/HelpCard.java @@ -0,0 +1,47 @@ +package seedu.workbook.ui; + + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.Region; +import seedu.workbook.ui.util.HelpUtil; +import seedu.workbook.ui.util.HelpUtil.Command; + +/** + * An UI component that displays information of a {@code Internship}. + */ +public class HelpCard extends UiPart { + + private static final String FXML = "HelpCard.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 Command command; + + @FXML + private Label commandLabel; + @FXML + private Label exampleLabel; + + + + + /** + * Creates a {@code HelpCard} with the given {@code Command} and example to display. + */ + public HelpCard(Command command) { + super(FXML); + this.command = command; + + commandLabel.setText(HelpUtil.getCommandHeader(command)); + exampleLabel.setText(HelpUtil.getCommandExample(command)); + } + +} diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/workbook/ui/HelpWindow.java similarity index 77% rename from src/main/java/seedu/address/ui/HelpWindow.java rename to src/main/java/seedu/workbook/ui/HelpWindow.java index 3f16b2fcf26..2c2f5017304 100644 --- a/src/main/java/seedu/address/ui/HelpWindow.java +++ b/src/main/java/seedu/workbook/ui/HelpWindow.java @@ -1,31 +1,27 @@ -package seedu.address.ui; +package seedu.workbook.ui; import java.util.logging.Logger; import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.Label; import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; +import javafx.scene.layout.GridPane; import javafx.stage.Stage; -import seedu.address.commons.core.LogsCenter; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.ui.util.HelpUtil; +import seedu.workbook.ui.util.HelpUtil.Command; /** * 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 HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL; private static final Logger logger = LogsCenter.getLogger(HelpWindow.class); private static final String FXML = "HelpWindow.fxml"; @FXML - private Button copyButton; - - @FXML - private Label helpMessage; + private GridPane gridPane; /** * Creates a new HelpWindow. @@ -34,7 +30,16 @@ public class HelpWindow extends UiPart { */ public HelpWindow(Stage root) { super(FXML, root); - helpMessage.setText(HELP_MESSAGE); + + for (int i = 0; i < Command.values().length; i++) { + Command command = Command.values()[i]; + HelpCard helpCard = new HelpCard(command); + gridPane.add(helpCard.getRoot(), 0, i + 1); + } + + UrlCard urlCard = new UrlCard(); + gridPane.add(urlCard.getRoot(), 0, Command.values().length + 1); + } /** @@ -96,7 +101,7 @@ public void focus() { private void copyUrl() { final Clipboard clipboard = Clipboard.getSystemClipboard(); final ClipboardContent url = new ClipboardContent(); - url.putString(USERGUIDE_URL); + url.putString(HelpUtil.getUserGuideUrl()); clipboard.setContent(url); } } diff --git a/src/main/java/seedu/workbook/ui/InternshipCard.java b/src/main/java/seedu/workbook/ui/InternshipCard.java new file mode 100644 index 00000000000..23e0577fd06 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/InternshipCard.java @@ -0,0 +1,130 @@ +package seedu.workbook.ui; + + +import java.util.Comparator; +import java.util.List; + +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.internship.util.StageUtil; + +/** + * An UI component that displays information of a {@code Internship}. + */ +public class InternshipCard extends UiPart { + + private static final String FXML = "InternshipListCard.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 Internship internship; + + //Independent tips window residing in each internship list card controller + private TipsWindow tipsWindow; + + private final Stage internshipStage; + + @FXML + private HBox cardPane; + @FXML + private Label company; + @FXML + private Label role; + @FXML + private Label id; + @FXML + private Label email; + @FXML + private Label stage; + @FXML + private Label dateTime; + @FXML + private FlowPane tags; + @FXML + private Button tipsButton; + + + /** + * Creates a {@code InternshipCode} with the given {@code Internship} and index to display. + */ + public InternshipCard(Internship internship, int displayedIndex) { + super(FXML); + this.internship = internship; + this.internshipStage = internship.getStage(); + boolean hasNoTips = internshipStage.hasNoTips(); + + if (hasNoTips) { + tipsButton.setVisible(false); + } + + id.setText(displayedIndex + ". "); + company.setText(internship.getCompany().name); + role.setText(internship.getRole().value); + email.setText(internship.getEmail().value); + stage.setText(internshipStage.value); + dateTime.setText(internship.getDateTime().value); + internship.getLanguageTags().stream() + .sorted(Comparator.comparing(languageTag -> languageTag.tagName)) + .forEach(languageTag -> tags.getChildren().add(new LanguageTagLabel(languageTag.tagName))); + internship.getTags().stream() + .sorted(Comparator.comparing(tag -> tag.tagName)) + .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); + + tipsWindow = new TipsWindow(); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof InternshipCard)) { + return false; + } + + // state check + InternshipCard card = (InternshipCard) other; + return id.getText().equals(card.id.getText()) + && internship.equals(card.internship); + } + + /** + * Opens the tip window depending on the internship stage. + */ + @FXML + private void showTips() { + //Check if tips window is showing. + if (!tipsWindow.isShowing()) { + //Do not populate tips window for stages that have no stage-specific tips. + if (this.internshipStage.hasNoTips()) { + return; + } + + //Set header of tips to be name of stage. + tipsWindow.setTipsHeader(this.internshipStage.value); + + List tips = StageUtil.getStageSpecificTips(this.internshipStage); + + tipsWindow.populateTips(tips); + tipsWindow.show(); + } else { + tipsWindow.focus(); + } + } +} diff --git a/src/main/java/seedu/workbook/ui/InternshipListPanel.java b/src/main/java/seedu/workbook/ui/InternshipListPanel.java new file mode 100644 index 00000000000..da0795765f8 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/InternshipListPanel.java @@ -0,0 +1,52 @@ +package seedu.workbook.ui; + +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.layout.Region; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.model.internship.Internship; + +/** + * Panel containing the list of internships. + */ +public class InternshipListPanel extends UiPart { + private static final String FXML = "InternshipListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(InternshipListPanel.class); + + @FXML + private ListView internshipListView; + + /** + * Creates a {@code InternshipListPanel} with the given {@code ObservableList}. + */ + public InternshipListPanel(ObservableList internshipList) { + super(FXML); + internshipListView.setItems(internshipList); + internshipListView.setCellFactory(listView -> new InternshipListViewCell()); + + // put first card into focus + internshipListView.getSelectionModel().selectFirst(); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Internship} using a {@code InternshipCard}. + */ + class InternshipListViewCell extends ListCell { + @Override + protected void updateItem(Internship internship, boolean empty) { + super.updateItem(internship, empty); + + if (empty || internship == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new InternshipCard(internship, getIndex() + 1).getRoot()); + } + } + } + +} diff --git a/src/main/java/seedu/workbook/ui/LanguageTagLabel.java b/src/main/java/seedu/workbook/ui/LanguageTagLabel.java new file mode 100644 index 00000000000..9f621fc287a --- /dev/null +++ b/src/main/java/seedu/workbook/ui/LanguageTagLabel.java @@ -0,0 +1,17 @@ +package seedu.workbook.ui; + +import javafx.scene.control.Label; + +/** + * Custom wrapper on a JavaFX Label to allow custom css styling. + */ +public class LanguageTagLabel extends Label { + /** + * Creates a {@code LanguageTabLabel} with the input text. + */ + public LanguageTagLabel(String text) { + super(text); + getStyleClass().setAll("languageTagLabel"); + } + +} diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/workbook/ui/MainWindow.java similarity index 74% rename from src/main/java/seedu/address/ui/MainWindow.java rename to src/main/java/seedu/workbook/ui/MainWindow.java index 9106c3aa6e5..8e9f762c59c 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/workbook/ui/MainWindow.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.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 seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.logic.Logic; +import seedu.workbook.logic.commands.CommandResult; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.logic.parser.exceptions.ParseException; /** * The Main Window. Provides the basic application layout containing @@ -24,6 +24,7 @@ public class MainWindow extends UiPart { private static final String FXML = "MainWindow.fxml"; + private static final int WIDTH_BREAKPOINT = 1000; private final Logger logger = LogsCenter.getLogger(getClass()); @@ -31,7 +32,8 @@ public class MainWindow extends UiPart { private Logic logic; // Independent Ui parts residing in this Ui container - private PersonListPanel personListPanel; + private InternshipListPanel internshipListPanel; + private WideInternshipListPanel wideInternshipListPanel; private ResultDisplay resultDisplay; private HelpWindow helpWindow; @@ -42,7 +44,7 @@ public class MainWindow extends UiPart { private MenuItem helpMenuItem; @FXML - private StackPane personListPanelPlaceholder; + private StackPane internshipListPanelPlaceholder; @FXML private StackPane resultDisplayPlaceholder; @@ -65,6 +67,8 @@ public MainWindow(Stage primaryStage, Logic logic) { setAccelerators(); + setWidthEventHandlers(); + helpWindow = new HelpWindow(); } @@ -110,13 +114,18 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) { * Fills up all the placeholders of this window. */ void fillInnerParts() { - personListPanel = new PersonListPanel(logic.getFilteredPersonList()); - personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + internshipListPanel = new InternshipListPanel(logic.getFilteredInternshipList()); + wideInternshipListPanel = new WideInternshipListPanel(logic.getFilteredInternshipList()); + if (logic.getGuiSettings().getWindowWidth() >= WIDTH_BREAKPOINT) { + internshipListPanelPlaceholder.getChildren().add(wideInternshipListPanel.getRoot()); + } else { + internshipListPanelPlaceholder.getChildren().add(internshipListPanel.getRoot()); + } resultDisplay = new ResultDisplay(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); - StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath()); + StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getWorkBookFilePath()); statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot()); CommandBox commandBox = new CommandBox(this::executeCommand); @@ -135,6 +144,19 @@ private void setWindowDefaultSize(GuiSettings guiSettings) { } } + private void setWidthEventHandlers() { + this.primaryStage.widthProperty().addListener((observable, oldVal, newVal) -> { + if (newVal.doubleValue() >= WIDTH_BREAKPOINT) { + // toggle to different layout + internshipListPanelPlaceholder.getChildren().clear(); + internshipListPanelPlaceholder.getChildren().add(wideInternshipListPanel.getRoot()); + } else { + internshipListPanelPlaceholder.getChildren().clear(); + internshipListPanelPlaceholder.getChildren().add(internshipListPanel.getRoot()); + } + }); + } + /** * Opens the help window or focuses on it if it's already opened. */ @@ -163,14 +185,14 @@ private void handleExit() { primaryStage.hide(); } - public PersonListPanel getPersonListPanel() { - return personListPanel; + public InternshipListPanel getInternshipListPanel() { + return internshipListPanel; } /** * Executes the command and returns the result. * - * @see seedu.address.logic.Logic#execute(String) + * @see seedu.workbook.logic.Logic#execute(String) */ private CommandResult executeCommand(String commandText) throws CommandException, ParseException { try { diff --git a/src/main/java/seedu/workbook/ui/NarrowInternshipCard.java b/src/main/java/seedu/workbook/ui/NarrowInternshipCard.java new file mode 100644 index 00000000000..6595c8638e5 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/NarrowInternshipCard.java @@ -0,0 +1,94 @@ +package seedu.workbook.ui; + + +import java.util.Comparator; + +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import seedu.workbook.model.internship.Internship; + +/** + * An UI component that displays information of a {@code Internship}. + */ +public class NarrowInternshipCard extends UiPart { + + private static final String FXML = "NarrowInternshipListCard.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 Internship internship; + + + @FXML + private HBox cardPane; + @FXML + private Label company; + @FXML + private Label role; + @FXML + private Label id; + @FXML + private Label email; + @FXML + private Label stage; + @FXML + private Label dateTime; + @FXML + private FlowPane tags; + @FXML + private Button tipsButton; + + + /** + * Creates a {@code InternshipCode} with the given {@code Internship} and index to display. + */ + public NarrowInternshipCard(Internship internship, int displayedIndex) { + super(FXML); + this.internship = internship; + + + id.setText(displayedIndex + ". "); + company.setText(internship.getCompany().name); + role.setText(internship.getRole().value); + email.setText(internship.getEmail().value); + stage.setText(internship.getStage().value); + dateTime.setText(internship.getDateTime().value); + internship.getLanguageTags().stream() + .sorted(Comparator.comparing(languageTag -> languageTag.tagName)) + .forEach(languageTag -> tags.getChildren().add(new LanguageTagLabel(languageTag.tagName))); + internship.getTags().stream() + .sorted(Comparator.comparing(tag -> tag.tagName)) + .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); + + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof NarrowInternshipCard)) { + return false; + } + + // state check + NarrowInternshipCard card = (NarrowInternshipCard) other; + return id.getText().equals(card.id.getText()) + && internship.equals(card.internship); + } + +} diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/seedu/workbook/ui/ResultDisplay.java similarity index 95% rename from src/main/java/seedu/address/ui/ResultDisplay.java rename to src/main/java/seedu/workbook/ui/ResultDisplay.java index 7d98e84eedf..eb1bb89307f 100644 --- a/src/main/java/seedu/address/ui/ResultDisplay.java +++ b/src/main/java/seedu/workbook/ui/ResultDisplay.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.ui; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/seedu/workbook/ui/StatusBarFooter.java similarity index 96% rename from src/main/java/seedu/address/ui/StatusBarFooter.java rename to src/main/java/seedu/workbook/ui/StatusBarFooter.java index b577f829423..4364b876d1d 100644 --- a/src/main/java/seedu/address/ui/StatusBarFooter.java +++ b/src/main/java/seedu/workbook/ui/StatusBarFooter.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.ui; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/src/main/java/seedu/workbook/ui/TipCard.java b/src/main/java/seedu/workbook/ui/TipCard.java new file mode 100644 index 00000000000..1a1a4f3ccb3 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/TipCard.java @@ -0,0 +1,47 @@ +package seedu.workbook.ui; + + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.Region; + +/** + * An UI component that displays information of a {@code Internship}. + */ +public class TipCard extends UiPart { + + private static final String FXML = "TipCard.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 int index; + public final String tip; + + @FXML + private Label indexLabel; + @FXML + private Label tipLabel; + + + + + /** + * Creates a {@code TipCard} with the given {@code Tip} and index to display. + */ + public TipCard(int index, String tip) { + super(FXML); + this.tip = tip; + this.index = index; + + this.indexLabel.setText(String.valueOf(this.index) + ". "); + this.tipLabel.setText(this.tip); + } + +} diff --git a/src/main/java/seedu/workbook/ui/TipsPanel.java b/src/main/java/seedu/workbook/ui/TipsPanel.java new file mode 100644 index 00000000000..535bbde692b --- /dev/null +++ b/src/main/java/seedu/workbook/ui/TipsPanel.java @@ -0,0 +1,54 @@ +package seedu.workbook.ui; + +import java.util.List; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Region; + +/** + * Controller for a tips panel + */ +public class TipsPanel extends UiPart { + + private static final String FXML = "TipsPanel.fxml"; + + @FXML + private Label tipsHeader; + + @FXML + private GridPane gridPane; + + + /** + * Creates a new TipsWindow. + */ + public TipsPanel() { + super(FXML); + } + + /* + * Set the tips window header to be the stage name. + */ + public void setTipsHeader(String stageName) { + tipsHeader.setText("Tips for " + stageName); + } + + /** + * Populates the tips window with tips. + * @param tips List of tips to populate the tip window. + */ + public void populateTips(List tips) { + //Clear no tips label + gridPane.getChildren().clear(); + + for (int i = 0; i < tips.size(); i++) { + int index = i + 1; + String tip = tips.get(i); + TipCard tipCard = new TipCard(index, tip); + gridPane.add(tipCard.getRoot(), 0, i, 1, 1); + } + } + +} diff --git a/src/main/java/seedu/workbook/ui/TipsWindow.java b/src/main/java/seedu/workbook/ui/TipsWindow.java new file mode 100644 index 00000000000..4d49a4e120b --- /dev/null +++ b/src/main/java/seedu/workbook/ui/TipsWindow.java @@ -0,0 +1,108 @@ +package seedu.workbook.ui; + +import java.util.List; +import java.util.logging.Logger; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; +import javafx.stage.Stage; +import seedu.workbook.commons.core.LogsCenter; + +/** + * Controller for a tips page + */ +public class TipsWindow extends UiPart { + + private static final Logger logger = LogsCenter.getLogger(TipsWindow.class); + private static final String FXML = "TipsWindow.fxml"; + + @FXML + private Label tipsHeader; + + @FXML + private GridPane gridPane; + + /** + * Creates a new TipsWindow. + * + * @param root Stage to use as the root of the TipsWindow. + */ + public TipsWindow(Stage root) { + super(FXML, root); + } + + /** + * Creates a new TipsWindow. + */ + public TipsWindow() { + this(new Stage()); + } + + /** + * Shows the help window. + * @throws IllegalStateException + *
    + *
  • + * if this method is called on a thread other than the JavaFX Application Thread. + *
  • + *
  • + * if this method is called during animation or layout processing. + *
  • + *
  • + * if this method is called on the primary stage. + *
  • + *
  • + * if {@code dialogStage} is already showing. + *
  • + *
+ */ + public void show() { + logger.fine("Showing tips page about the internship stage."); + getRoot().show(); + getRoot().centerOnScreen(); + } + + /** + * Returns true if the tips window is currently being shown. + */ + public boolean isShowing() { + return getRoot().isShowing(); + } + + /** + * Hides the tips window. + */ + public void hide() { + getRoot().hide(); + } + + /** + * Focuses on the tips window. + */ + public void focus() { + getRoot().requestFocus(); + } + + /* + * Set the tips window header to be the stage name. + */ + public void setTipsHeader(String stageName) { + tipsHeader.setText("Tips for " + stageName); + } + + /** + * Populates the tips window with tips. + * @param tips List of tips to populate the tip window. + */ + public void populateTips(List tips) { + for (int i = 0; i < tips.size(); i++) { + + int index = i + 1; + String tip = tips.get(i); + TipCard tipCard = new TipCard(index, tip); + gridPane.add(tipCard.getRoot(), 0, i, 1, 1); + } + } + +} diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/seedu/workbook/ui/Ui.java similarity index 85% rename from src/main/java/seedu/address/ui/Ui.java rename to src/main/java/seedu/workbook/ui/Ui.java index 17aa0b494fe..a254067b93c 100644 --- a/src/main/java/seedu/address/ui/Ui.java +++ b/src/main/java/seedu/workbook/ui/Ui.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.ui; import javafx.stage.Stage; diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/workbook/ui/UiManager.java similarity index 93% rename from src/main/java/seedu/address/ui/UiManager.java rename to src/main/java/seedu/workbook/ui/UiManager.java index fdf024138bc..64f16062457 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/seedu/workbook/ui/UiManager.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.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 seedu.workbook.MainApp; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.commons.util.StringUtil; +import seedu.workbook.logic.Logic; /** * The manager of the UI component. diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/seedu/workbook/ui/UiPart.java similarity index 97% rename from src/main/java/seedu/address/ui/UiPart.java rename to src/main/java/seedu/workbook/ui/UiPart.java index fc820e01a9c..6d7e3603357 100644 --- a/src/main/java/seedu/address/ui/UiPart.java +++ b/src/main/java/seedu/workbook/ui/UiPart.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.ui; import static java.util.Objects.requireNonNull; @@ -6,7 +6,7 @@ import java.net.URL; import javafx.fxml.FXMLLoader; -import seedu.address.MainApp; +import seedu.workbook.MainApp; /** * Represents a distinct part of the UI. e.g. Windows, dialogs, panels, status bars, etc. diff --git a/src/main/java/seedu/workbook/ui/UrlCard.java b/src/main/java/seedu/workbook/ui/UrlCard.java new file mode 100644 index 00000000000..95989a3889d --- /dev/null +++ b/src/main/java/seedu/workbook/ui/UrlCard.java @@ -0,0 +1,55 @@ +package seedu.workbook.ui; + + +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.layout.Region; +import seedu.workbook.ui.util.HelpUtil; + +/** + * An UI component that displays the {@code URL} of the {@code User Guide}. + */ +public class UrlCard extends UiPart { + + private static final String FXML = "UrlCard.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 + */ + + @FXML + private Label urlMessage; + + @FXML + private Button copyButton; + + + /** + * Creates a {@code URLCard} with the given {@code URL} and message to display. + */ + public UrlCard() { + super(FXML); + + urlMessage.setText(HelpUtil.getUrlMessage()); + } + + /** + * Copies the URL to the user guide to the clipboard. + */ + @FXML + private void copyUrl() { + final Clipboard clipboard = Clipboard.getSystemClipboard(); + final ClipboardContent url = new ClipboardContent(); + url.putString(HelpUtil.getUserGuideUrl()); + clipboard.setContent(url); + } + +} diff --git a/src/main/java/seedu/workbook/ui/WideInternshipListPanel.java b/src/main/java/seedu/workbook/ui/WideInternshipListPanel.java new file mode 100644 index 00000000000..648134c94c0 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/WideInternshipListPanel.java @@ -0,0 +1,102 @@ +package seedu.workbook.ui; + +import java.util.List; +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.HBox; +import javafx.scene.layout.Region; +import seedu.workbook.commons.core.LogsCenter; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.internship.util.StageUtil; + +/** + * Panel containing the list of internships for wide window format. + */ +public class WideInternshipListPanel extends UiPart { + private static final String FXML = "WideInternshipListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(WideInternshipListPanel.class); + + @FXML + private HBox tipsPanelContainer; + + @FXML + private ListView wideInternshipListView; + + /** + * Creates a {@code WideInternshipListPanel} with the given {@code ObservableList}. + */ + public WideInternshipListPanel(ObservableList internshipList) { + super(FXML); + wideInternshipListView.setItems(internshipList); + wideInternshipListView.setCellFactory(listView -> new WideInternshipListViewCell()); + setInternshipSelectedEventHandlers(); + + // put first card into focus + wideInternshipListView.getSelectionModel().selectFirst(); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Internship} using a {@code InternshipCard}. + */ + class WideInternshipListViewCell extends ListCell { + @Override + protected void updateItem(Internship internship, boolean empty) { + super.updateItem(internship, empty); + + if (empty || internship == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new NarrowInternshipCard(internship, getIndex() + 1).getRoot()); + } + } + } + + /** + * Add listener to when an internship card is selected. + */ + private void setInternshipSelectedEventHandlers() { + this.wideInternshipListView + .getSelectionModel() + .selectedItemProperty() + .addListener((observable, oldVal, newVal) -> { + tipsPanelContainer.getChildren().clear(); + // should not show tips when no card is selected + if (newVal == null) { + return; + } + TipsPanel tipsPanel = tipPanelBuilder(newVal.getStage()); + tipsPanelContainer.getChildren().add(tipsPanel.getRoot()); + }); + } + + /** + * Builds a {@code TipsPanel} from the given internship {@code internshipStage}. + * @param internshipStage + * @return + */ + private TipsPanel tipPanelBuilder(Stage internshipStage) { + + TipsPanel tipsPanel = new TipsPanel(); + + //Set header of tips to be name of stage. + tipsPanel.setTipsHeader(internshipStage.value); + + if (internshipStage.hasNoTips()) { + //Default tips panel has no tips label + return tipsPanel; + } + + List tips = StageUtil.getStageSpecificTips(internshipStage); + + tipsPanel.populateTips(tips); + + return tipsPanel; + } + +} diff --git a/src/main/java/seedu/workbook/ui/util/HelpUtil.java b/src/main/java/seedu/workbook/ui/util/HelpUtil.java new file mode 100644 index 00000000000..2bc35d083e8 --- /dev/null +++ b/src/main/java/seedu/workbook/ui/util/HelpUtil.java @@ -0,0 +1,107 @@ +package seedu.workbook.ui.util; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Contains utility methods used in implementing methods regarding {@code HelpWindow} for GUI. + */ +public class HelpUtil { + + public static final String ADD_HEADER = "Add an Internship: "; + public static final String ADD_EXAMPLE = "add c/COMPANY r/ROLE s/STAGE [d/DATETIME] [e/EMAIL] " + + "[l/PROGRAMMING LANGUAGE]… [t/TAG]…"; + public static final String EDIT_HEADER = "Edit an Internship: "; + public static final String EDIT_EXAMPLE = "edit INDEX [c/COMPANY] [r/ROLE] [s/STAGE] [d/DATETIME] [e/EMAIL] " + + "[l/PROGRAMMING LANGUAGE]… [t/TAG]…"; + public static final String DELETE_HEADER = "Delete an Internship: "; + public static final String DELETE_EXAMPLE = "delete INDEX"; + public static final String CLEAR_HEADER = "Clear all Internships: "; + public static final String CLEAR_EXAMPLE = "clear"; + public static final String LIST_HEADER = "List all Internships: "; + public static final String LIST_EXAMPLE = "list"; + public static final String FIND_HEADER = "Filter Internships: "; + public static final String FIND_EXAMPLE = "find c/COMPANY | r/ROLE | s/STAGE"; + public static final String UNDO_HEADER = "Undo a command: "; + public static final String UNDO_EXAMPLE = "undo"; + public static final String REDO_HEADER = "Redo a command: "; + public static final String REDO_EXAMPLE = "redo"; + public static final String EXIT_HEADER = "Exit application: "; + public static final String EXIT_EXAMPLE = "exit"; + public static final String USERGUIDE_URL = "https://ay2223s1-cs2103t-t10-3.github.io/tp/UserGuide.html"; + public static final String URL_MESSAGE = "Refer to the user guide for more information: " + USERGUIDE_URL; + + public static final List LIST_OF_HEADERS = Arrays.asList( + ADD_HEADER, + LIST_HEADER, + FIND_HEADER, + EDIT_HEADER, + DELETE_HEADER, + CLEAR_HEADER, + UNDO_HEADER, + REDO_HEADER, + EXIT_HEADER + ); + + public static final List LIST_OF_EXAMPLES = Arrays.asList( + ADD_EXAMPLE, + LIST_EXAMPLE, + FIND_EXAMPLE, + EDIT_EXAMPLE, + DELETE_EXAMPLE, + CLEAR_EXAMPLE, + UNDO_EXAMPLE, + REDO_EXAMPLE, + EXIT_EXAMPLE + ); + + public static final Map HEADERS_FOR_COMMAND = new HashMap<>(); + public static final Map EXAMPLES_FOR_COMMAND = new HashMap<>(); + + /** + * Contains all commands supported by WB. + */ + public enum Command { + ADD, LIST, FIND, EDIT, DELETE, CLEAR, UNDO, REDO, EXIT, + } + + /* + * Static initialization block to populate the maps. + * Each command is mapped to a header and example. + */ + static { + for (int i = 0; i < Command.values().length; i++) { + HEADERS_FOR_COMMAND.put(Command.values()[i], LIST_OF_HEADERS.get(i)); + EXAMPLES_FOR_COMMAND.put(Command.values()[i], LIST_OF_EXAMPLES.get(i)); + } + } + + /** + * Returns command header for a given command. + * @param command Command to return header for. + * @return Command header as String. + */ + public static String getCommandHeader(Command command) { + return HEADERS_FOR_COMMAND.get(command); + } + + /** + * Returns command example for a given command. + * @param command Command to return example for. + * @return Command example as String. + */ + public static String getCommandExample(Command command) { + return EXAMPLES_FOR_COMMAND.get(command); + } + + public static String getUserGuideUrl() { + return USERGUIDE_URL; + } + + public static String getUrlMessage() { + return URL_MESSAGE; + } + +} diff --git a/src/main/resources/images/lightbulb.png b/src/main/resources/images/lightbulb.png new file mode 100644 index 00000000000..5ade40bb0f5 Binary files /dev/null and b/src/main/resources/images/lightbulb.png differ diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 36e6b001cd8..ee13144d236 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -350,3 +350,12 @@ -fx-background-radius: 2; -fx-font-size: 11; } + +#tags .languageTagLabel { + -fx-text-fill: white; + -fx-background-color: rgb(135, 135, 215); + -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/HelpCard.fxml b/src/main/resources/view/HelpCard.fxml new file mode 100644 index 00000000000..85390a3f658 --- /dev/null +++ b/src/main/resources/view/HelpCard.fxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css index 17e8a8722cd..a3b604fb5ce 100644 --- a/src/main/resources/view/HelpWindow.css +++ b/src/main/resources/view/HelpWindow.css @@ -1,7 +1,21 @@ -#copyButton, #helpMessage { +#copyButton, #urlMessage { -fx-text-fill: white; } +#topHeader { + -fx-text-fill: orange; + -fx-font-weight: bold; + -fx-font-size: 20px; +} + +.commandText { + -fx-text-fill: white; +} + +.commandHeader { + -fx-text-fill: orange; +} + #copyButton { -fx-background-color: dimgray; } @@ -14,6 +28,10 @@ -fx-background-color: darkgray; } -#helpMessageContainer { +.commandContainer { + -fx-background-color: derive(#1d1d1d, 20%); +} + +#urlMessageContainer, #topHeaderContainer { -fx-background-color: derive(#1d1d1d, 20%); } diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml index 5dea0adef70..73204360e72 100644 --- a/src/main/resources/view/HelpWindow.fxml +++ b/src/main/resources/view/HelpWindow.fxml @@ -3,13 +3,15 @@ - + + + - + @@ -18,27 +20,24 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/InternshipListCard.fxml b/src/main/resources/view/InternshipListCard.fxml new file mode 100644 index 00000000000..15a605815f4 --- /dev/null +++ b/src/main/resources/view/InternshipListCard.fxml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/InternshipListPanel.fxml similarity index 76% rename from src/main/resources/view/PersonListPanel.fxml rename to src/main/resources/view/InternshipListPanel.fxml index 8836d323cc5..ec14fcc91f7 100644 --- a/src/main/resources/view/PersonListPanel.fxml +++ b/src/main/resources/view/InternshipListPanel.fxml @@ -4,5 +4,5 @@ - + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index a431648f6c0..5e745b4e0d5 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -6,13 +6,12 @@ - + - + @@ -21,6 +20,7 @@ + @@ -32,25 +32,23 @@ - - + - + - + - + - + - + - + diff --git a/src/main/resources/view/NarrowInternshipListCard.fxml b/src/main/resources/view/NarrowInternshipListCard.fxml new file mode 100644 index 00000000000..2881ae99fcb --- /dev/null +++ b/src/main/resources/view/NarrowInternshipListCard.fxml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml deleted file mode 100644 index f08ea32ad55..00000000000 --- a/src/main/resources/view/PersonListCard.fxml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/view/TipCard.fxml b/src/main/resources/view/TipCard.fxml new file mode 100644 index 00000000000..eb431ee7102 --- /dev/null +++ b/src/main/resources/view/TipCard.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/Tips.css b/src/main/resources/view/Tips.css new file mode 100644 index 00000000000..beba190241f --- /dev/null +++ b/src/main/resources/view/Tips.css @@ -0,0 +1,28 @@ +#tipsHeader { + -fx-text-fill: orange; + -fx-font-weight: bold; + -fx-font-size: 20px; +} + +.headerContainer { + -fx-background-color: derive(#1d1d1d, 20%); +} + +#gridPane { + -fx-background-color: derive(#1d1d1d, 20%); +} + +.tipContainer { + -fx-background-color: derive(#1d1d1d, 20%); +} + +.indexText { + -fx-text-fill: white; + -fx-font-weight: bold; + -fx-font-size: 14px; +} + +.tipText { + -fx-text-fill: white; + -fx-font-size: 14px; +} diff --git a/src/main/resources/view/TipsPanel.fxml b/src/main/resources/view/TipsPanel.fxml new file mode 100644 index 00000000000..06934a1e985 --- /dev/null +++ b/src/main/resources/view/TipsPanel.fxml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/TipsWindow.fxml b/src/main/resources/view/TipsWindow.fxml new file mode 100644 index 00000000000..7a8cf4bf148 --- /dev/null +++ b/src/main/resources/view/TipsWindow.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/UrlCard.fxml b/src/main/resources/view/UrlCard.fxml new file mode 100644 index 00000000000..a6e85388ebb --- /dev/null +++ b/src/main/resources/view/UrlCard.fxml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/WideInternshipListPanel.fxml b/src/main/resources/view/WideInternshipListPanel.fxml new file mode 100644 index 00000000000..0ee797b8ca6 --- /dev/null +++ b/src/main/resources/view/WideInternshipListPanel.fxml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json deleted file mode 100644 index 6a4d2b7181c..00000000000 --- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "persons": [ { - "name": "Valid Person", - "phone": "9482424", - "email": "hans@example.com", - "address": "4th street" - }, { - "name": "Person With Invalid Phone Field", - "phone": "948asdf2424", - "email": "hans@example.com", - "address": "4th street" - } ] -} diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json deleted file mode 100644 index ccd21f7d1a9..00000000000 --- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "persons": [ { - "name": "Person with invalid name field: Ha!ns Mu@ster", - "phone": "9482424", - "email": "hans@example.com", - "address": "4th street" - } ] -} diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json deleted file mode 100644 index 48831cc7674..00000000000 --- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "persons": [ { - "name": "Alice Pauline", - "phone": "94351253", - "email": "alice@example.com", - "address": "123, Jurong West Ave 6, #08-111", - "tagged": [ "friends" ] - }, { - "name": "Alice Pauline", - "phone": "94351253", - "email": "pauline@example.com", - "address": "4th street" - } ] -} diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json deleted file mode 100644 index ad3f135ae42..00000000000 --- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "persons": [ { - "name": "Hans Muster", - "phone": "9482424", - "email": "invalid@email!3e", - "address": "4th street" - } ] -} diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json deleted file mode 100644 index f10eddee12e..00000000000 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()", - "persons" : [ { - "name" : "Alice Pauline", - "phone" : "94351253", - "email" : "alice@example.com", - "address" : "123, Jurong West Ave 6, #08-111", - "tagged" : [ "friends" ] - }, { - "name" : "Benson Meier", - "phone" : "98765432", - "email" : "johnd@example.com", - "address" : "311, Clementi Ave 2, #02-25", - "tagged" : [ "owesMoney", "friends" ] - }, { - "name" : "Carl Kurz", - "phone" : "95352563", - "email" : "heinz@example.com", - "address" : "wall street", - "tagged" : [ ] - }, { - "name" : "Daniel Meier", - "phone" : "87652533", - "email" : "cornelia@example.com", - "address" : "10th street", - "tagged" : [ "friends" ] - }, { - "name" : "Elle Meyer", - "phone" : "9482224", - "email" : "werner@example.com", - "address" : "michegan ave", - "tagged" : [ ] - }, { - "name" : "Fiona Kunz", - "phone" : "9482427", - "email" : "lydia@example.com", - "address" : "little tokyo", - "tagged" : [ ] - }, { - "name" : "George Best", - "phone" : "9482442", - "email" : "anna@example.com", - "address" : "4th street", - "tagged" : [ ] - } ] -} diff --git a/src/test/data/JsonSerializableWorkBookTest/duplicateInternshipWorkBook.json b/src/test/data/JsonSerializableWorkBookTest/duplicateInternshipWorkBook.json new file mode 100644 index 00000000000..5654ecb0db3 --- /dev/null +++ b/src/test/data/JsonSerializableWorkBookTest/duplicateInternshipWorkBook.json @@ -0,0 +1,16 @@ +{ + "internships": [ { + "company": "Alice Pauline", + "role": "Software Engineer", + "email": "alice@example.com", + "stage": "HR interview", + "dateTime": "12-Oct-2022 12:00", + "tagged": [ "friends" ] + }, { + "company": "Alice Pauline", + "role": "Software Engineer", + "email": "pauline@example.com", + "stage": "Rejected", + "dateTime": "12-Oct-2022 12:00" + } ] +} diff --git a/src/test/data/JsonSerializableWorkBookTest/invalidInternshipWorkBook.json b/src/test/data/JsonSerializableWorkBookTest/invalidInternshipWorkBook.json new file mode 100644 index 00000000000..ec4a7209f31 --- /dev/null +++ b/src/test/data/JsonSerializableWorkBookTest/invalidInternshipWorkBook.json @@ -0,0 +1,9 @@ +{ + "internships": [ { + "company": "Hans Muster", + "role": "Software Engineer", + "email": "invalid@email!3e", + "stage": "HR interview", + "dateTime": "" + } ] +} diff --git a/src/test/data/JsonSerializableWorkBookTest/typicalInternshipsWorkBook.json b/src/test/data/JsonSerializableWorkBookTest/typicalInternshipsWorkBook.json new file mode 100644 index 00000000000..4450035c293 --- /dev/null +++ b/src/test/data/JsonSerializableWorkBookTest/typicalInternshipsWorkBook.json @@ -0,0 +1,54 @@ +{ + "_comment": "WorkBook save file which contains the same Internship values as in TypicalInternships#getTypicalWorkBook()", + "internships" : [ { + "company" : "Alice Pauline", + "role" : "Software Engineer", + "email" : "alice@example.com", + "stage" : "Technical Interview", + "dateTime": "12-Oct-2022 12:00", + "tagged" : [ "friends" ] + }, { + "company" : "Benson Meier", + "role" : "Software Engineer", + "email" : "johnd@example.com", + "stage" : "HR Interview", + "dateTime": "12-Dec-2022 14:00", + "languages": [ "Java", "Python" ], + "tagged" : [ "owesMoney", "friends" ] + }, { + "company" : "Carl Kurz", + "role" : "Software Engineer", + "email" : "heinz@example.com", + "stage" : "Rejected", + "dateTime" : "", + "tagged" : [ ] + }, { + "company" : "Daniel Meier", + "role" : "Software Engineer", + "email" : "cornelia@example.com", + "stage" : "Technical Interview", + "dateTime": "", + "tagged" : [ "friends" ] + }, { + "company" : "Elle Meyer", + "role" : "Software Engineer", + "email" : "werner@example.com", + "stage" : "Application Sent", + "dateTime": "", + "tagged" : [ ] + }, { + "company" : "Fiona Kunz", + "role" : "Software Engineer", + "email" : "lydia@example.com", + "stage" : "Online Assessment", + "dateTime": "", + "tagged" : [ ] + }, { + "company" : "George Best", + "role" : "Software Engineer", + "email" : "anna@example.com", + "stage" : "Team Lead Interview", + "dateTime": "", + "tagged" : [ ] + } ] +} diff --git a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json index 1037548a9cd..80765f2ac30 100644 --- a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json +++ b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json @@ -9,5 +9,5 @@ "z" : 99 } }, - "addressBookFilePath" : "addressbook.json" + "workBookFilePath" : "workbook.json" } diff --git a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json index b819bed900a..b120effd378 100644 --- a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json +++ b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json @@ -7,5 +7,5 @@ "y" : 100 } }, - "addressBookFilePath" : "addressbook.json" + "workBookFilePath" : "workbook.json" } diff --git a/src/test/data/JsonWorkBookStorageTest/invalidAndValidInternshipWorkBook.json b/src/test/data/JsonWorkBookStorageTest/invalidAndValidInternshipWorkBook.json new file mode 100644 index 00000000000..3ce2f0258de --- /dev/null +++ b/src/test/data/JsonWorkBookStorageTest/invalidAndValidInternshipWorkBook.json @@ -0,0 +1,13 @@ +{ + "internships": [ { + "company": "Valid Internship", + "role": "Software Engineer", + "email": "hans@example.com", + "stage": "Technical Interview", + "date": "16-Oct-2022 14:00" + }, { + "company": "Internship With Missing Role", + "email": "hans@example.com", + "stage": "Technical Interview" + } ] +} diff --git a/src/test/data/JsonWorkBookStorageTest/invalidInternshipWorkBook.json b/src/test/data/JsonWorkBookStorageTest/invalidInternshipWorkBook.json new file mode 100644 index 00000000000..1fd3e0f4553 --- /dev/null +++ b/src/test/data/JsonWorkBookStorageTest/invalidInternshipWorkBook.json @@ -0,0 +1,8 @@ +{ + "internships": [ { + "company": "Internship with invalid company field: Ha!ns Mu@ster", + "role": "Software Engineer", + "email": "hans@example.com", + "stage": "Technical Interview" + } ] +} diff --git a/src/test/data/JsonAddressBookStorageTest/notJsonFormatAddressBook.json b/src/test/data/JsonWorkBookStorageTest/notJsonFormatWorkBook.json similarity index 100% rename from src/test/data/JsonAddressBookStorageTest/notJsonFormatAddressBook.json rename to src/test/data/JsonWorkBookStorageTest/notJsonFormatWorkBook.json diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java deleted file mode 100644 index cb8714bb055..00000000000 --- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package seedu.address.logic.commands; - -import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.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 seedu.address.model.person.Person; -import seedu.address.testutil.PersonBuilder; - -/** - * Contains integration tests (interaction with the Model) for {@code AddCommand}. - */ -public class AddCommandIntegrationTest { - - private Model model; - - @BeforeEach - public void setUp() { - model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - } - - @Test - public void execute_newPerson_success() { - Person validPerson = new PersonBuilder().build(); - - Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); - expectedModel.addPerson(validPerson); - - assertCommandSuccess(new AddCommand(validPerson), model, - String.format(AddCommand.MESSAGE_SUCCESS, validPerson), expectedModel); - } - - @Test - public void execute_duplicatePerson_throwsCommandException() { - Person personInList = model.getAddressBook().getPersonList().get(0); - assertCommandFailure(new AddCommand(personInList), model, AddCommand.MESSAGE_DUPLICATE_PERSON); - } - -} diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java deleted file mode 100644 index 5865713d5dd..00000000000 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; -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 java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.function.Predicate; - -import org.junit.jupiter.api.Test; - -import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.person.Person; -import seedu.address.testutil.PersonBuilder; - -public class AddCommandTest { - - @Test - public void constructor_nullPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new AddCommand(null)); - } - - @Test - public void execute_personAcceptedByModel_addSuccessful() throws Exception { - ModelStubAcceptingPersonAdded modelStub = new ModelStubAcceptingPersonAdded(); - Person validPerson = new PersonBuilder().build(); - - CommandResult commandResult = new AddCommand(validPerson).execute(modelStub); - - assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, validPerson), commandResult.getFeedbackToUser()); - assertEquals(Arrays.asList(validPerson), modelStub.personsAdded); - } - - @Test - public void execute_duplicatePerson_throwsCommandException() { - Person validPerson = new PersonBuilder().build(); - AddCommand addCommand = new AddCommand(validPerson); - ModelStub modelStub = new ModelStubWithPerson(validPerson); - - assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PERSON, () -> addCommand.execute(modelStub)); - } - - @Test - public void equals() { - Person alice = new PersonBuilder().withName("Alice").build(); - Person bob = new PersonBuilder().withName("Bob").build(); - AddCommand addAliceCommand = new AddCommand(alice); - AddCommand addBobCommand = new AddCommand(bob); - - // same object -> returns true - assertTrue(addAliceCommand.equals(addAliceCommand)); - - // same values -> returns true - AddCommand addAliceCommandCopy = new AddCommand(alice); - assertTrue(addAliceCommand.equals(addAliceCommandCopy)); - - // different types -> returns false - assertFalse(addAliceCommand.equals(1)); - - // null -> returns false - assertFalse(addAliceCommand.equals(null)); - - // different person -> returns false - assertFalse(addAliceCommand.equals(addBobCommand)); - } - - /** - * A default model stub that have all of the methods failing. - */ - private class ModelStub implements Model { - @Override - public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { - throw new AssertionError("This method should not be called."); - } - - @Override - public ReadOnlyUserPrefs getUserPrefs() { - throw new AssertionError("This method should not be called."); - } - - @Override - public GuiSettings getGuiSettings() { - throw new AssertionError("This method should not be called."); - } - - @Override - public void setGuiSettings(GuiSettings guiSettings) { - throw new AssertionError("This method should not be called."); - } - - @Override - public Path getAddressBookFilePath() { - throw new AssertionError("This method should not be called."); - } - - @Override - public void setAddressBookFilePath(Path addressBookFilePath) { - throw new AssertionError("This method should not be called."); - } - - @Override - public void addPerson(Person person) { - throw new AssertionError("This method should not be called."); - } - - @Override - public void setAddressBook(ReadOnlyAddressBook newData) { - throw new AssertionError("This method should not be called."); - } - - @Override - public ReadOnlyAddressBook getAddressBook() { - throw new AssertionError("This method should not be called."); - } - - @Override - 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."); - } - - @Override - public void setPerson(Person target, Person editedPerson) { - throw new AssertionError("This method should not be called."); - } - - @Override - public ObservableList getFilteredPersonList() { - throw new AssertionError("This method should not be called."); - } - - @Override - public void updateFilteredPersonList(Predicate predicate) { - throw new AssertionError("This method should not be called."); - } - } - - /** - * A Model stub that contains a single person. - */ - private class ModelStubWithPerson extends ModelStub { - private final Person person; - - ModelStubWithPerson(Person person) { - requireNonNull(person); - this.person = person; - } - - @Override - public boolean hasPerson(Person person) { - requireNonNull(person); - return this.person.isSamePerson(person); - } - } - - /** - * A Model stub that always accept the person being added. - */ - private class ModelStubAcceptingPersonAdded extends ModelStub { - final ArrayList personsAdded = new ArrayList<>(); - - @Override - public boolean hasPerson(Person person) { - requireNonNull(person); - return personsAdded.stream().anyMatch(person::isSamePerson); - } - - @Override - public void addPerson(Person person) { - requireNonNull(person); - personsAdded.add(person); - } - - @Override - public ReadOnlyAddressBook getAddressBook() { - return new AddressBook(); - } - } - -} diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java deleted file mode 100644 index 80d9110c03a..00000000000 --- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package seedu.address.logic.commands; - -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.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; - -public class ClearCommandTest { - - @Test - public void execute_emptyAddressBook_success() { - Model model = new ModelManager(); - Model expectedModel = new ModelManager(); - - assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel); - } - - @Test - public void execute_nonEmptyAddressBook_success() { - Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - expectedModel.setAddressBook(new AddressBook()); - - assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel); - } - -} diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java deleted file mode 100644 index 643a1d08069..00000000000 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ /dev/null @@ -1,128 +0,0 @@ -package seedu.address.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 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; - -/** - * Contains helper methods for testing commands. - */ -public class CommandTestUtil { - - public static final String VALID_NAME_AMY = "Amy Bee"; - public static final String VALID_NAME_BOB = "Bob Choo"; - public static final String VALID_PHONE_AMY = "11111111"; - public static final String VALID_PHONE_BOB = "22222222"; - public static final String VALID_EMAIL_AMY = "amy@example.com"; - public static final String VALID_EMAIL_BOB = "bob@example.com"; - public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1"; - public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3"; - public static final String VALID_TAG_HUSBAND = "husband"; - public static final String VALID_TAG_FRIEND = "friend"; - - public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY; - public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB; - public static final String PHONE_DESC_AMY = " " + PREFIX_PHONE + VALID_PHONE_AMY; - public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB; - public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY; - public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB; - public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY; - public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB; - public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND; - public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND; - - public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names - public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones - public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol - public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses - public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags - - public static final String PREAMBLE_WHITESPACE = "\t \r \n"; - public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble"; - - public static final EditCommand.EditPersonDescriptor DESC_AMY; - public static final EditCommand.EditPersonDescriptor DESC_BOB; - - static { - DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY) - .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY) - .withTags(VALID_TAG_FRIEND).build(); - DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB) - .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB) - .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); - } - - /** - * Executes the given {@code command}, confirms that
- * - the returned {@link CommandResult} matches {@code expectedCommandResult}
- * - the {@code actualModel} matches {@code expectedModel} - */ - public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult, - Model expectedModel) { - try { - CommandResult result = command.execute(actualModel); - assertEquals(expectedCommandResult, result); - assertEquals(expectedModel, actualModel); - } catch (CommandException ce) { - throw new AssertionError("Execution of command should not fail.", ce); - } - } - - /** - * Convenience wrapper to {@link #assertCommandSuccess(Command, Model, CommandResult, Model)} - * that takes a string {@code expectedMessage}. - */ - public static void assertCommandSuccess(Command command, Model actualModel, String expectedMessage, - Model expectedModel) { - CommandResult expectedCommandResult = new CommandResult(expectedMessage); - assertCommandSuccess(command, actualModel, expectedCommandResult, expectedModel); - } - - /** - * 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 - */ - 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()); - - assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel)); - assertEquals(expectedAddressBook, actualModel.getAddressBook()); - assertEquals(expectedFilteredList, actualModel.getFilteredPersonList()); - } - /** - * Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the - * {@code model}'s address book. - */ - public static void showPersonAtIndex(Model model, Index targetIndex) { - assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size()); - - Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased()); - final String[] splitName = person.getName().fullName.split("\\s+"); - model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0]))); - - assertEquals(1, model.getFilteredPersonList().size()); - } - -} diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java deleted file mode 100644 index 45a8c910ba1..00000000000 --- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package seedu.address.logic.commands; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.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 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; - -/** - * Contains integration tests (interaction with the Model) and unit tests for - * {@code DeleteCommand}. - */ -public class DeleteCommandTest { - - private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - - @Test - public void execute_validIndexUnfilteredList_success() { - Person personToDelete = model.getFilteredPersonList().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()); - expectedModel.deletePerson(personToDelete); - - assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); - } - - @Test - public void execute_invalidIndexUnfilteredList_throwsCommandException() { - Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); - DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex); - - assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - @Test - public void execute_validIndexFilteredList_success() { - showPersonAtIndex(model, INDEX_FIRST_PERSON); - - Person personToDelete = model.getFilteredPersonList().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()); - expectedModel.deletePerson(personToDelete); - showNoPerson(expectedModel); - - assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); - } - - @Test - 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()); - - DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex); - - assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - @Test - public void equals() { - DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON); - DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON); - - // same object -> returns true - assertTrue(deleteFirstCommand.equals(deleteFirstCommand)); - - // same values -> returns true - DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON); - assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy)); - - // different types -> returns false - assertFalse(deleteFirstCommand.equals(1)); - - // null -> returns false - assertFalse(deleteFirstCommand.equals(null)); - - // different person -> returns false - assertFalse(deleteFirstCommand.equals(deleteSecondCommand)); - } - - /** - * Updates {@code model}'s filtered list to show no one. - */ - private void showNoPerson(Model model) { - model.updateFilteredPersonList(p -> false); - - assertTrue(model.getFilteredPersonList().isEmpty()); - } -} diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java deleted file mode 100644 index 214c6c2507b..00000000000 --- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java +++ /dev/null @@ -1,173 +0,0 @@ -package seedu.address.logic.commands; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.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 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; - -/** - * Contains integration tests (interaction with the Model) and unit tests for EditCommand. - */ -public class EditCommandTest { - - private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - - @Test - public void execute_allFieldsSpecifiedUnfilteredList_success() { - Person editedPerson = new PersonBuilder().build(); - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build(); - EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); - - 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); - - 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()); - - PersonBuilder personInList = new PersonBuilder(lastPerson); - Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB) - .withTags(VALID_TAG_HUSBAND).build(); - - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB) - .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build(); - EditCommand editCommand = new EditCommand(indexLastPerson, descriptor); - - String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson); - - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); - expectedModel.setPerson(lastPerson, editedPerson); - - assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); - } - - @Test - public void execute_noFieldSpecifiedUnfilteredList_success() { - EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor()); - Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); - - String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson); - - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); - - assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); - } - - @Test - public void execute_filteredList_success() { - showPersonAtIndex(model, INDEX_FIRST_PERSON); - - Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); - Person editedPerson = new PersonBuilder(personInFilteredList).withName(VALID_NAME_BOB).build(); - EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, - new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build()); - - String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson); - - Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); - expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson); - - assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); - } - - @Test - public void execute_duplicatePersonUnfilteredList_failure() { - Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build(); - EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor); - - assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); - } - - @Test - 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()); - EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, - new EditPersonDescriptorBuilder(personInList).build()); - - assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); - } - - @Test - public void execute_invalidPersonIndexUnfilteredList_failure() { - Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build(); - EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor); - - assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - /** - * Edit filtered list where index is larger than size of filtered list, - * but smaller than size of address book - */ - @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()); - - EditCommand editCommand = new EditCommand(outOfBoundIndex, - new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build()); - - assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - @Test - public void equals() { - final EditCommand standardCommand = new EditCommand(INDEX_FIRST_PERSON, DESC_AMY); - - // same values -> returns true - EditPersonDescriptor copyDescriptor = new EditPersonDescriptor(DESC_AMY); - EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_PERSON, copyDescriptor); - assertTrue(standardCommand.equals(commandWithSameValues)); - - // same object -> returns true - assertTrue(standardCommand.equals(standardCommand)); - - // null -> returns false - assertFalse(standardCommand.equals(null)); - - // different types -> returns false - assertFalse(standardCommand.equals(new ClearCommand())); - - // different index -> returns false - assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_PERSON, DESC_AMY))); - - // different descriptor -> returns false - assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_PERSON, DESC_BOB))); - } - -} diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java deleted file mode 100644 index e0288792e72..00000000000 --- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package seedu.address.logic.commands; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.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 org.junit.jupiter.api.Test; - -import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.testutil.EditPersonDescriptorBuilder; - -public class EditPersonDescriptorTest { - - @Test - public void equals() { - // same values -> returns true - EditPersonDescriptor descriptorWithSameValues = new EditPersonDescriptor(DESC_AMY); - assertTrue(DESC_AMY.equals(descriptorWithSameValues)); - - // same object -> returns true - assertTrue(DESC_AMY.equals(DESC_AMY)); - - // null -> returns false - assertFalse(DESC_AMY.equals(null)); - - // different types -> returns false - assertFalse(DESC_AMY.equals(5)); - - // different values -> returns false - assertFalse(DESC_AMY.equals(DESC_BOB)); - - // different name -> returns false - EditPersonDescriptor editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withName(VALID_NAME_BOB).build(); - assertFalse(DESC_AMY.equals(editedAmy)); - - // different phone -> returns false - editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withPhone(VALID_PHONE_BOB).build(); - assertFalse(DESC_AMY.equals(editedAmy)); - - // different email -> returns false - editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build(); - assertFalse(DESC_AMY.equals(editedAmy)); - - // different address -> returns false - editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build(); - assertFalse(DESC_AMY.equals(editedAmy)); - - // different tags -> returns false - editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build(); - assertFalse(DESC_AMY.equals(editedAmy)); - } -} diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java deleted file mode 100644 index 9b15db28bbb..00000000000 --- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package seedu.address.logic.commands; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.commons.core.Messages.MESSAGE_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 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; - -/** - * Contains integration tests (interaction with the Model) for {@code FindCommand}. - */ -public class FindCommandTest { - private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - - @Test - public void equals() { - NameContainsKeywordsPredicate firstPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("first")); - NameContainsKeywordsPredicate secondPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("second")); - - FindCommand findFirstCommand = new FindCommand(firstPredicate); - FindCommand findSecondCommand = new FindCommand(secondPredicate); - - // same object -> returns true - assertTrue(findFirstCommand.equals(findFirstCommand)); - - // same values -> returns true - FindCommand findFirstCommandCopy = new FindCommand(firstPredicate); - assertTrue(findFirstCommand.equals(findFirstCommandCopy)); - - // different types -> returns false - assertFalse(findFirstCommand.equals(1)); - - // null -> returns false - assertFalse(findFirstCommand.equals(null)); - - // different person -> returns false - assertFalse(findFirstCommand.equals(findSecondCommand)); - } - - @Test - public void execute_zeroKeywords_noPersonFound() { - String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); - NameContainsKeywordsPredicate predicate = preparePredicate(" "); - FindCommand command = new FindCommand(predicate); - expectedModel.updateFilteredPersonList(predicate); - assertCommandSuccess(command, model, expectedMessage, expectedModel); - assertEquals(Collections.emptyList(), model.getFilteredPersonList()); - } - - @Test - public void execute_multipleKeywords_multiplePersonsFound() { - String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); - NameContainsKeywordsPredicate 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()); - } - - /** - * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}. - */ - private NameContainsKeywordsPredicate preparePredicate(String userInput) { - return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); - } -} diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java deleted file mode 100644 index 435ff1f7275..00000000000 --- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package seedu.address.logic.commands; - -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex; -import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; -import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; - -import 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; - -/** - * Contains integration tests (interaction with the Model) and unit tests for ListCommand. - */ -public class ListCommandTest { - - private Model model; - private Model expectedModel; - - @BeforeEach - public void setUp() { - model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); - expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); - } - - @Test - public void execute_listIsNotFiltered_showsSameList() { - assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel); - } - - @Test - public void execute_listIsFiltered_showsEverything() { - showPersonAtIndex(model, INDEX_FIRST_PERSON); - assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel); - } -} diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java deleted file mode 100644 index 5cf487d7ebb..00000000000 --- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java +++ /dev/null @@ -1,141 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY; -import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB; -import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; -import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; -import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC; -import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; -import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC; -import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC; -import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC; -import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY; -import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB; -import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY; -import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB; -import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY; -import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; -import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND; -import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND; -import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; -import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; -import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; -import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; -import static seedu.address.testutil.TypicalPersons.AMY; -import static seedu.address.testutil.TypicalPersons.BOB; - -import org.junit.jupiter.api.Test; - -import seedu.address.logic.commands.AddCommand; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; -import seedu.address.model.tag.Tag; -import seedu.address.testutil.PersonBuilder; - -public class AddCommandParserTest { - private AddCommandParser parser = new AddCommandParser(); - - @Test - public void parse_allFieldsPresent_success() { - Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND).build(); - - // whitespace only preamble - assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB - + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson)); - - // multiple names - last name accepted - assertParseSuccess(parser, NAME_DESC_AMY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB - + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson)); - - // multiple phones - last phone accepted - assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_AMY + PHONE_DESC_BOB + EMAIL_DESC_BOB - + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson)); - - // multiple emails - last email accepted - assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_AMY + EMAIL_DESC_BOB - + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson)); - - // multiple addresses - last address accepted - assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_AMY - + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson)); - - // multiple tags - all accepted - Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND) - .build(); - assertParseSuccess(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB - + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, new AddCommand(expectedPersonMultipleTags)); - } - - @Test - public void parse_optionalFieldsMissing_success() { - // zero tags - Person expectedPerson = new PersonBuilder(AMY).withTags().build(); - assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY, - new AddCommand(expectedPerson)); - } - - @Test - public void parse_compulsoryFieldMissing_failure() { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); - - // missing name prefix - assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB, - expectedMessage); - - // missing phone prefix - assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB, - expectedMessage); - - // missing email prefix - assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + ADDRESS_DESC_BOB, - expectedMessage); - - // missing address prefix - assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_ADDRESS_BOB, - expectedMessage); - - // all prefixes missing - assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_ADDRESS_BOB, - expectedMessage); - } - - @Test - public void parse_invalidValue_failure() { - // invalid name - assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB - + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS); - - // invalid phone - assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + ADDRESS_DESC_BOB - + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS); - - // invalid email - assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB - + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS); - - // invalid address - assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC - + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS); - - // invalid tag - assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB - + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS); - - // two invalid values, only first invalid value reported - assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC, - Name.MESSAGE_CONSTRAINTS); - - // non-empty preamble - assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB - + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, - String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); - } -} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java deleted file mode 100644 index d9659205b57..00000000000 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package seedu.address.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 java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -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(); - - @Test - public void parseCommand_add() throws Exception { - Person person = new PersonBuilder().build(); - AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person)); - assertEquals(new AddCommand(person), command); - } - - @Test - public void parseCommand_clear() throws Exception { - assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand); - assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand); - } - - @Test - public void parseCommand_delete() throws Exception { - DeleteCommand command = (DeleteCommand) parser.parseCommand( - DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased()); - assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command); - } - - @Test - public void parseCommand_edit() throws Exception { - Person person = new PersonBuilder().build(); - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build(); - EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " " - + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor)); - assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command); - } - - @Test - public void parseCommand_exit() throws Exception { - assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand); - assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand); - } - - @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); - } - - @Test - public void parseCommand_help() throws Exception { - assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand); - assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand); - } - - @Test - public void parseCommand_list() throws Exception { - assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand); - assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand); - } - - @Test - public void parseCommand_unrecognisedInput_throwsParseException() { - assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), () - -> parser.parseCommand("")); - } - - @Test - public void parseCommand_unknownCommand_throwsParseException() { - assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand")); - } -} diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java deleted file mode 100644 index 2ff31522486..00000000000 --- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java +++ /dev/null @@ -1,211 +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.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; - -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; - -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); - - private EditCommandParser parser = new EditCommandParser(); - - @Test - public void parse_missingParts_failure() { - // no index specified - assertParseFailure(parser, VALID_NAME_AMY, MESSAGE_INVALID_FORMAT); - - // no field specified - assertParseFailure(parser, "1", EditCommand.MESSAGE_NOT_EDITED); - - // no index and no field specified - assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT); - } - - @Test - public void parse_invalidPreamble_failure() { - // negative index - assertParseFailure(parser, "-5" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); - - // zero index - assertParseFailure(parser, "0" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); - - // invalid arguments being parsed as preamble - assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT); - - // invalid prefix being parsed as preamble - assertParseFailure(parser, "1 i/ string", MESSAGE_INVALID_FORMAT); - } - - @Test - public void parse_invalidValue_failure() { - assertParseFailure(parser, "1" + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name - assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone - assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email - assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address - assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag - - // invalid phone followed by valid email - assertParseFailure(parser, "1" + INVALID_PHONE_DESC + EMAIL_DESC_AMY, Phone.MESSAGE_CONSTRAINTS); - - // valid phone followed by invalid phone. The test case for invalid phone followed by valid phone - // is tested at {@code parse_invalidValueFollowedByValidValue_success()} - assertParseFailure(parser, "1" + PHONE_DESC_BOB + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); - - // while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited, - // parsing it together with a valid tag results in error - assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS); - assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS); - assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS); - - // multiple invalid values, but only the first invalid value is captured - assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY, - Name.MESSAGE_CONSTRAINTS); - } - - @Test - public void parse_allFieldsSpecified_success() { - Index targetIndex = INDEX_SECOND_PERSON; - String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + TAG_DESC_HUSBAND - + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY + TAG_DESC_FRIEND; - - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY) - .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY) - .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); - - assertParseSuccess(parser, userInput, expectedCommand); - } - - @Test - public void parse_someFieldsSpecified_success() { - Index targetIndex = INDEX_FIRST_PERSON; - String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + EMAIL_DESC_AMY; - - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB) - .withEmail(VALID_EMAIL_AMY).build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); - - assertParseSuccess(parser, userInput, expectedCommand); - } - - @Test - public void parse_oneFieldSpecified_success() { - // name - Index targetIndex = INDEX_THIRD_PERSON; - String userInput = targetIndex.getOneBased() + NAME_DESC_AMY; - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY).build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - - // phone - userInput = targetIndex.getOneBased() + PHONE_DESC_AMY; - descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_AMY).build(); - expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - - // email - userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY; - descriptor = new EditPersonDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build(); - expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - - // address - userInput = targetIndex.getOneBased() + ADDRESS_DESC_AMY; - descriptor = new EditPersonDescriptorBuilder().withAddress(VALID_ADDRESS_AMY).build(); - expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - - // tags - userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND; - descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build(); - expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - } - - @Test - public void parse_multipleRepeatedFields_acceptsLast() { - Index targetIndex = INDEX_FIRST_PERSON; - String userInput = targetIndex.getOneBased() + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY - + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND - + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + TAG_DESC_HUSBAND; - - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB) - .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND) - .build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); - - assertParseSuccess(parser, userInput, expectedCommand); - } - - @Test - public void parse_invalidValueFollowedByValidValue_success() { - // no other valid values specified - Index targetIndex = INDEX_FIRST_PERSON; - String userInput = targetIndex.getOneBased() + INVALID_PHONE_DESC + PHONE_DESC_BOB; - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB).build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - - // other valid values specified - userInput = targetIndex.getOneBased() + EMAIL_DESC_BOB + INVALID_PHONE_DESC + ADDRESS_DESC_BOB - + PHONE_DESC_BOB; - descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB) - .withAddress(VALID_ADDRESS_BOB).build(); - expectedCommand = new EditCommand(targetIndex, descriptor); - assertParseSuccess(parser, userInput, expectedCommand); - } - - @Test - public void parse_resetTags_success() { - Index targetIndex = INDEX_THIRD_PERSON; - String userInput = targetIndex.getOneBased() + TAG_EMPTY; - - EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); - - assertParseSuccess(parser, userInput, expectedCommand); - } -} diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java deleted file mode 100644 index 70f4f0e79c4..00000000000 --- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; -import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; - -import java.util.Arrays; - -import org.junit.jupiter.api.Test; - -import seedu.address.logic.commands.FindCommand; -import seedu.address.model.person.NameContainsKeywordsPredicate; - -public class FindCommandParserTest { - - private FindCommandParser parser = new FindCommandParser(); - - @Test - public void parse_emptyArg_throwsParseException() { - assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); - } - - @Test - public void parse_validArgs_returnsFindCommand() { - // no leading and trailing whitespaces - FindCommand expectedFindCommand = - new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); - assertParseSuccess(parser, "Alice Bob", expectedFindCommand); - - // multiple whitespaces between keywords - assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand); - } - -} diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java deleted file mode 100644 index 4256788b1a7..00000000000 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ /dev/null @@ -1,196 +0,0 @@ -package seedu.address.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 java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -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; - -public class ParserUtilTest { - private static final String INVALID_NAME = "R@chel"; - private static final String INVALID_PHONE = "+651234"; - private static final String INVALID_ADDRESS = " "; - private static final String INVALID_EMAIL = "example.com"; - private static final String INVALID_TAG = "#friend"; - - private static final String VALID_NAME = "Rachel Walker"; - private static final String VALID_PHONE = "123456"; - private static final String VALID_ADDRESS = "123 Main Street #0505"; - private static final String VALID_EMAIL = "rachel@example.com"; - private static final String VALID_TAG_1 = "friend"; - private static final String VALID_TAG_2 = "neighbour"; - - private static final String WHITESPACE = " \t\r\n"; - - @Test - public void parseIndex_invalidInput_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parseIndex("10 a")); - } - - @Test - public void parseIndex_outOfRangeInput_throwsParseException() { - assertThrows(ParseException.class, MESSAGE_INVALID_INDEX, () - -> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1))); - } - - @Test - public void parseIndex_validInput_success() throws Exception { - // No whitespaces - assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex("1")); - - // Leading and trailing whitespaces - assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex(" 1 ")); - } - - @Test - public void parseName_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> ParserUtil.parseName((String) null)); - } - - @Test - public void parseName_invalidValue_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parseName(INVALID_NAME)); - } - - @Test - public void parseName_validValueWithoutWhitespace_returnsName() throws Exception { - Name expectedName = new Name(VALID_NAME); - assertEquals(expectedName, ParserUtil.parseName(VALID_NAME)); - } - - @Test - public void parseName_validValueWithWhitespace_returnsTrimmedName() throws Exception { - String nameWithWhitespace = WHITESPACE + VALID_NAME + WHITESPACE; - Name expectedName = new Name(VALID_NAME); - assertEquals(expectedName, ParserUtil.parseName(nameWithWhitespace)); - } - - @Test - public void parsePhone_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> ParserUtil.parsePhone((String) null)); - } - - @Test - public void parsePhone_invalidValue_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parsePhone(INVALID_PHONE)); - } - - @Test - public void parsePhone_validValueWithoutWhitespace_returnsPhone() throws Exception { - Phone expectedPhone = new Phone(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); - assertEquals(expectedPhone, ParserUtil.parsePhone(phoneWithWhitespace)); - } - - @Test - 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); - assertEquals(expectedAddress, ParserUtil.parseAddress(VALID_ADDRESS)); - } - - @Test - public void parseAddress_validValueWithWhitespace_returnsTrimmedAddress() throws Exception { - String addressWithWhitespace = WHITESPACE + VALID_ADDRESS + WHITESPACE; - Address expectedAddress = new Address(VALID_ADDRESS); - assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace)); - } - - @Test - public void parseEmail_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> ParserUtil.parseEmail((String) null)); - } - - @Test - public void parseEmail_invalidValue_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parseEmail(INVALID_EMAIL)); - } - - @Test - public void parseEmail_validValueWithoutWhitespace_returnsEmail() throws Exception { - Email expectedEmail = new Email(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); - assertEquals(expectedEmail, ParserUtil.parseEmail(emailWithWhitespace)); - } - - @Test - public void parseTag_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> ParserUtil.parseTag(null)); - } - - @Test - public void parseTag_invalidValue_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parseTag(INVALID_TAG)); - } - - @Test - public void parseTag_validValueWithoutWhitespace_returnsTag() throws Exception { - Tag expectedTag = new Tag(VALID_TAG_1); - assertEquals(expectedTag, ParserUtil.parseTag(VALID_TAG_1)); - } - - @Test - public void parseTag_validValueWithWhitespace_returnsTrimmedTag() throws Exception { - String tagWithWhitespace = WHITESPACE + VALID_TAG_1 + WHITESPACE; - Tag expectedTag = new Tag(VALID_TAG_1); - assertEquals(expectedTag, ParserUtil.parseTag(tagWithWhitespace)); - } - - @Test - public void parseTags_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> ParserUtil.parseTags(null)); - } - - @Test - public void parseTags_collectionWithInvalidTags_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, INVALID_TAG))); - } - - @Test - public void parseTags_emptyCollection_returnsEmptySet() throws Exception { - assertTrue(ParserUtil.parseTags(Collections.emptyList()).isEmpty()); - } - - @Test - public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception { - Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, VALID_TAG_2)); - Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2))); - - assertEquals(expectedTagSet, actualTagSet); - } -} diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java deleted file mode 100644 index 87782528ecd..00000000000 --- a/src/test/java/seedu/address/model/AddressBookTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package seedu.address.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 java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.junit.jupiter.api.Test; - -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; - -public class AddressBookTest { - - private final AddressBook addressBook = new AddressBook(); - - @Test - public void constructor() { - assertEquals(Collections.emptyList(), addressBook.getPersonList()); - } - - @Test - public void resetData_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> addressBook.resetData(null)); - } - - @Test - public void resetData_withValidReadOnlyAddressBook_replacesData() { - AddressBook newData = getTypicalAddressBook(); - addressBook.resetData(newData); - assertEquals(newData, addressBook); - } - - @Test - public void resetData_withDuplicatePersons_throwsDuplicatePersonException() { - // Two persons with the same identity fields - Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND) - .build(); - List newPersons = Arrays.asList(ALICE, editedAlice); - AddressBookStub newData = new AddressBookStub(newPersons); - - assertThrows(DuplicatePersonException.class, () -> addressBook.resetData(newData)); - } - - @Test - public void hasPerson_nullPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> addressBook.hasPerson(null)); - } - - @Test - public void hasPerson_personNotInAddressBook_returnsFalse() { - assertFalse(addressBook.hasPerson(ALICE)); - } - - @Test - public void hasPerson_personInAddressBook_returnsTrue() { - addressBook.addPerson(ALICE); - assertTrue(addressBook.hasPerson(ALICE)); - } - - @Test - public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() { - addressBook.addPerson(ALICE); - Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND) - .build(); - assertTrue(addressBook.hasPerson(editedAlice)); - } - - @Test - public void getPersonList_modifyList_throwsUnsupportedOperationException() { - assertThrows(UnsupportedOperationException.class, () -> addressBook.getPersonList().remove(0)); - } - - /** - * A stub ReadOnlyAddressBook whose persons list can violate interface constraints. - */ - private static class AddressBookStub implements ReadOnlyAddressBook { - private final ObservableList persons = FXCollections.observableArrayList(); - - AddressBookStub(Collection persons) { - this.persons.setAll(persons); - } - - @Override - public ObservableList getPersonList() { - return persons; - } - } - -} diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/person/AddressTest.java deleted file mode 100644 index dcd3be87b3a..00000000000 --- a/src/test/java/seedu/address/model/person/AddressTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package seedu.address.model.person; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.testutil.Assert.assertThrows; - -import org.junit.jupiter.api.Test; - -public class AddressTest { - - @Test - public void constructor_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new Address(null)); - } - - @Test - public void constructor_invalidAddress_throwsIllegalArgumentException() { - String invalidAddress = ""; - assertThrows(IllegalArgumentException.class, () -> new Address(invalidAddress)); - } - - @Test - public void isValidAddress() { - // null address - assertThrows(NullPointerException.class, () -> Address.isValidAddress(null)); - - // invalid addresses - assertFalse(Address.isValidAddress("")); // empty string - assertFalse(Address.isValidAddress(" ")); // spaces only - - // valid addresses - assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355")); - assertTrue(Address.isValidAddress("-")); // one character - assertTrue(Address.isValidAddress("Leng Inc; 1234 Market St; San Francisco CA 2349879; USA")); // long address - } -} diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java deleted file mode 100644 index f136664e017..00000000000 --- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package seedu.address.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 seedu.address.testutil.PersonBuilder; - -public class NameContainsKeywordsPredicateTest { - - @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); - - // same object -> returns true - assertTrue(firstPredicate.equals(firstPredicate)); - - // same values -> returns true - NameContainsKeywordsPredicate firstPredicateCopy = new NameContainsKeywordsPredicate(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_nameContainsKeywords_returnsTrue() { - // One keyword - NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Alice")); - assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build())); - - // Multiple keywords - predicate = new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")); - assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build())); - - // Only one matching keyword - predicate = new NameContainsKeywordsPredicate(Arrays.asList("Bob", "Carol")); - assertTrue(predicate.test(new PersonBuilder().withName("Alice Carol").build())); - - // Mixed-case keywords - predicate = new NameContainsKeywordsPredicate(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()); - assertFalse(predicate.test(new PersonBuilder().withName("Alice").build())); - - // Non-matching keyword - predicate = new NameContainsKeywordsPredicate(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")); - 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/NameTest.java b/src/test/java/seedu/address/model/person/NameTest.java deleted file mode 100644 index c9801392874..00000000000 --- a/src/test/java/seedu/address/model/person/NameTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package seedu.address.model.person; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.testutil.Assert.assertThrows; - -import org.junit.jupiter.api.Test; - -public class NameTest { - - @Test - public void constructor_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new Name(null)); - } - - @Test - public void constructor_invalidName_throwsIllegalArgumentException() { - String invalidName = ""; - assertThrows(IllegalArgumentException.class, () -> new Name(invalidName)); - } - - @Test - public void isValidName() { - // null name - assertThrows(NullPointerException.class, () -> Name.isValidName(null)); - - // invalid name - assertFalse(Name.isValidName("")); // empty string - assertFalse(Name.isValidName(" ")); // spaces only - assertFalse(Name.isValidName("^")); // only non-alphanumeric characters - assertFalse(Name.isValidName("peter*")); // contains non-alphanumeric characters - - // valid name - assertTrue(Name.isValidName("peter jack")); // alphabets only - assertTrue(Name.isValidName("12345")); // numbers only - assertTrue(Name.isValidName("peter the 2nd")); // alphanumeric characters - assertTrue(Name.isValidName("Capital Tan")); // with capital letters - assertTrue(Name.isValidName("David Roger Jackson Ray Jr 2nd")); // long names - } -} diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java deleted file mode 100644 index b29c097cfd4..00000000000 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package seedu.address.model.person; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; -import static seedu.address.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalPersons.ALICE; -import static seedu.address.testutil.TypicalPersons.BOB; - -import org.junit.jupiter.api.Test; - -import seedu.address.testutil.PersonBuilder; - -public class PersonTest { - - @Test - public void asObservableList_modifyList_throwsUnsupportedOperationException() { - Person person = new PersonBuilder().build(); - assertThrows(UnsupportedOperationException.class, () -> person.getTags().remove(0)); - } - - @Test - public void isSamePerson() { - // same object -> returns true - assertTrue(ALICE.isSamePerson(ALICE)); - - // null -> returns false - assertFalse(ALICE.isSamePerson(null)); - - // same name, all other attributes different -> returns true - Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB) - .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND).build(); - assertTrue(ALICE.isSamePerson(editedAlice)); - - // different name, all other attributes same -> returns false - editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build(); - assertFalse(ALICE.isSamePerson(editedAlice)); - - // name differs in case, all other attributes same -> returns false - Person editedBob = new PersonBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build(); - assertFalse(BOB.isSamePerson(editedBob)); - - // name has trailing spaces, all other attributes same -> returns false - String nameWithTrailingSpaces = VALID_NAME_BOB + " "; - editedBob = new PersonBuilder(BOB).withName(nameWithTrailingSpaces).build(); - assertFalse(BOB.isSamePerson(editedBob)); - } - - @Test - public void equals() { - // same values -> returns true - Person aliceCopy = new PersonBuilder(ALICE).build(); - assertTrue(ALICE.equals(aliceCopy)); - - // same object -> returns true - assertTrue(ALICE.equals(ALICE)); - - // null -> returns false - assertFalse(ALICE.equals(null)); - - // different type -> returns false - assertFalse(ALICE.equals(5)); - - // different person -> returns false - assertFalse(ALICE.equals(BOB)); - - // different name -> returns false - Person editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build(); - assertFalse(ALICE.equals(editedAlice)); - - // different phone -> returns false - editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).build(); - assertFalse(ALICE.equals(editedAlice)); - - // different email -> returns false - editedAlice = new PersonBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build(); - assertFalse(ALICE.equals(editedAlice)); - - // different address -> returns false - editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).build(); - assertFalse(ALICE.equals(editedAlice)); - - // different tags -> returns false - editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build(); - assertFalse(ALICE.equals(editedAlice)); - } -} diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/seedu/address/model/person/PhoneTest.java deleted file mode 100644 index 8dd52766a5f..00000000000 --- a/src/test/java/seedu/address/model/person/PhoneTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package seedu.address.model.person; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.testutil.Assert.assertThrows; - -import org.junit.jupiter.api.Test; - -public class PhoneTest { - - @Test - public void constructor_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new Phone(null)); - } - - @Test - public void constructor_invalidPhone_throwsIllegalArgumentException() { - String invalidPhone = ""; - assertThrows(IllegalArgumentException.class, () -> new Phone(invalidPhone)); - } - - @Test - public void isValidPhone() { - // null phone number - assertThrows(NullPointerException.class, () -> Phone.isValidPhone(null)); - - // invalid phone numbers - assertFalse(Phone.isValidPhone("")); // empty string - assertFalse(Phone.isValidPhone(" ")); // spaces only - assertFalse(Phone.isValidPhone("91")); // less than 3 numbers - assertFalse(Phone.isValidPhone("phone")); // non-numeric - assertFalse(Phone.isValidPhone("9011p041")); // alphabets within digits - assertFalse(Phone.isValidPhone("9312 1534")); // spaces within digits - - // valid phone numbers - assertTrue(Phone.isValidPhone("911")); // exactly 3 numbers - assertTrue(Phone.isValidPhone("93121534")); - assertTrue(Phone.isValidPhone("124293842033123")); // long phone numbers - } -} diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/seedu/address/model/person/UniquePersonListTest.java deleted file mode 100644 index 1cc5fe9e0fe..00000000000 --- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java +++ /dev/null @@ -1,170 +0,0 @@ -package seedu.address.model.person; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; -import static seedu.address.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalPersons.ALICE; -import static seedu.address.testutil.TypicalPersons.BOB; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import seedu.address.model.person.exceptions.DuplicatePersonException; -import seedu.address.model.person.exceptions.PersonNotFoundException; -import seedu.address.testutil.PersonBuilder; - -public class UniquePersonListTest { - - private final UniquePersonList uniquePersonList = new UniquePersonList(); - - @Test - public void contains_nullPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.contains(null)); - } - - @Test - public void contains_personNotInList_returnsFalse() { - assertFalse(uniquePersonList.contains(ALICE)); - } - - @Test - public void contains_personInList_returnsTrue() { - uniquePersonList.add(ALICE); - assertTrue(uniquePersonList.contains(ALICE)); - } - - @Test - public void contains_personWithSameIdentityFieldsInList_returnsTrue() { - uniquePersonList.add(ALICE); - Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND) - .build(); - assertTrue(uniquePersonList.contains(editedAlice)); - } - - @Test - public void add_nullPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.add(null)); - } - - @Test - public void add_duplicatePerson_throwsDuplicatePersonException() { - uniquePersonList.add(ALICE); - assertThrows(DuplicatePersonException.class, () -> uniquePersonList.add(ALICE)); - } - - @Test - public void setPerson_nullTargetPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.setPerson(null, ALICE)); - } - - @Test - public void setPerson_nullEditedPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.setPerson(ALICE, null)); - } - - @Test - public void setPerson_targetPersonNotInList_throwsPersonNotFoundException() { - assertThrows(PersonNotFoundException.class, () -> uniquePersonList.setPerson(ALICE, ALICE)); - } - - @Test - public void setPerson_editedPersonIsSamePerson_success() { - uniquePersonList.add(ALICE); - uniquePersonList.setPerson(ALICE, ALICE); - UniquePersonList expectedUniquePersonList = new UniquePersonList(); - expectedUniquePersonList.add(ALICE); - assertEquals(expectedUniquePersonList, uniquePersonList); - } - - @Test - public void setPerson_editedPersonHasSameIdentity_success() { - uniquePersonList.add(ALICE); - Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND) - .build(); - uniquePersonList.setPerson(ALICE, editedAlice); - UniquePersonList expectedUniquePersonList = new UniquePersonList(); - expectedUniquePersonList.add(editedAlice); - assertEquals(expectedUniquePersonList, uniquePersonList); - } - - @Test - public void setPerson_editedPersonHasDifferentIdentity_success() { - uniquePersonList.add(ALICE); - uniquePersonList.setPerson(ALICE, BOB); - UniquePersonList expectedUniquePersonList = new UniquePersonList(); - expectedUniquePersonList.add(BOB); - assertEquals(expectedUniquePersonList, uniquePersonList); - } - - @Test - public void setPerson_editedPersonHasNonUniqueIdentity_throwsDuplicatePersonException() { - uniquePersonList.add(ALICE); - uniquePersonList.add(BOB); - assertThrows(DuplicatePersonException.class, () -> uniquePersonList.setPerson(ALICE, BOB)); - } - - @Test - public void remove_nullPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.remove(null)); - } - - @Test - public void remove_personDoesNotExist_throwsPersonNotFoundException() { - assertThrows(PersonNotFoundException.class, () -> uniquePersonList.remove(ALICE)); - } - - @Test - public void remove_existingPerson_removesPerson() { - uniquePersonList.add(ALICE); - uniquePersonList.remove(ALICE); - UniquePersonList expectedUniquePersonList = new UniquePersonList(); - assertEquals(expectedUniquePersonList, uniquePersonList); - } - - @Test - public void setPersons_nullUniquePersonList_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.setPersons((UniquePersonList) null)); - } - - @Test - public void setPersons_uniquePersonList_replacesOwnListWithProvidedUniquePersonList() { - uniquePersonList.add(ALICE); - UniquePersonList expectedUniquePersonList = new UniquePersonList(); - expectedUniquePersonList.add(BOB); - uniquePersonList.setPersons(expectedUniquePersonList); - assertEquals(expectedUniquePersonList, uniquePersonList); - } - - @Test - public void setPersons_nullList_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> uniquePersonList.setPersons((List) null)); - } - - @Test - public void setPersons_list_replacesOwnListWithProvidedList() { - uniquePersonList.add(ALICE); - List personList = Collections.singletonList(BOB); - uniquePersonList.setPersons(personList); - UniquePersonList expectedUniquePersonList = new UniquePersonList(); - expectedUniquePersonList.add(BOB); - assertEquals(expectedUniquePersonList, uniquePersonList); - } - - @Test - public void setPersons_listWithDuplicatePersons_throwsDuplicatePersonException() { - List listWithDuplicatePersons = Arrays.asList(ALICE, ALICE); - assertThrows(DuplicatePersonException.class, () -> uniquePersonList.setPersons(listWithDuplicatePersons)); - } - - @Test - public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() { - assertThrows(UnsupportedOperationException.class, () - -> uniquePersonList.asUnmodifiableObservableList().remove(0)); - } -} diff --git a/src/test/java/seedu/address/model/tag/TagTest.java b/src/test/java/seedu/address/model/tag/TagTest.java deleted file mode 100644 index 64d07d79ee2..00000000000 --- a/src/test/java/seedu/address/model/tag/TagTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package seedu.address.model.tag; - -import static seedu.address.testutil.Assert.assertThrows; - -import org.junit.jupiter.api.Test; - -public class TagTest { - - @Test - public void constructor_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new Tag(null)); - } - - @Test - public void constructor_invalidTagName_throwsIllegalArgumentException() { - String invalidTagName = ""; - assertThrows(IllegalArgumentException.class, () -> new Tag(invalidTagName)); - } - - @Test - public void isValidTagName() { - // null tag name - assertThrows(NullPointerException.class, () -> Tag.isValidTagName(null)); - } - -} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java deleted file mode 100644 index 83b11331cdb..00000000000 --- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package seedu.address.storage; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static seedu.address.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT; -import static seedu.address.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalPersons.BENSON; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Phone; - -public class JsonAdaptedPersonTest { - private static final String INVALID_NAME = "R@chel"; - private static final String INVALID_PHONE = "+651234"; - private static final String INVALID_ADDRESS = " "; - private static final String INVALID_EMAIL = "example.com"; - private static final String INVALID_TAG = "#friend"; - - private static final String VALID_NAME = BENSON.getName().toString(); - private static final String VALID_PHONE = BENSON.getPhone().toString(); - private static final String VALID_EMAIL = BENSON.getEmail().toString(); - private static final String VALID_ADDRESS = BENSON.getAddress().toString(); - private static final List VALID_TAGS = BENSON.getTags().stream() - .map(JsonAdaptedTag::new) - .collect(Collectors.toList()); - - @Test - public void toModelType_validPersonDetails_returnsPerson() throws Exception { - JsonAdaptedPerson person = new JsonAdaptedPerson(BENSON); - assertEquals(BENSON, person.toModelType()); - } - - @Test - public void toModelType_invalidName_throwsIllegalValueException() { - JsonAdaptedPerson person = - new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); - String expectedMessage = Name.MESSAGE_CONSTRAINTS; - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_nullName_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); - String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()); - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_invalidPhone_throwsIllegalValueException() { - JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); - String expectedMessage = Phone.MESSAGE_CONSTRAINTS; - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_nullPhone_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); - String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()); - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_invalidEmail_throwsIllegalValueException() { - JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS); - String expectedMessage = Email.MESSAGE_CONSTRAINTS; - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_nullEmail_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS); - String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()); - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_invalidAddress_throwsIllegalValueException() { - JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS); - String expectedMessage = Address.MESSAGE_CONSTRAINTS; - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_nullAddress_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS); - String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()); - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_invalidTags_throwsIllegalValueException() { - List invalidTags = new ArrayList<>(VALID_TAGS); - invalidTags.add(new JsonAdaptedTag(INVALID_TAG)); - JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags); - assertThrows(IllegalValueException.class, person::toModelType); - } - -} diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java deleted file mode 100644 index ac3c3af9566..00000000000 --- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package seedu.address.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 java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; - -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; - -public class JsonAddressBookStorageTest { - private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonAddressBookStorageTest"); - - @TempDir - public Path testFolder; - - @Test - 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 Path addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) { - return prefsFileInTestDataFolder != null - ? TEST_DATA_FOLDER.resolve(prefsFileInTestDataFolder) - : null; - } - - @Test - public void read_missingFile_emptyResult() throws Exception { - assertFalse(readAddressBook("NonExistentFile.json").isPresent()); - } - - @Test - public void read_notJsonFormat_exceptionThrown() { - assertThrows(DataConversionException.class, () -> readAddressBook("notJsonFormatAddressBook.json")); - } - - @Test - public void readAddressBook_invalidPersonAddressBook_throwDataConversionException() { - assertThrows(DataConversionException.class, () -> readAddressBook("invalidPersonAddressBook.json")); - } - - @Test - public void readAddressBook_invalidAndValidPersonAddressBook_throwDataConversionException() { - assertThrows(DataConversionException.class, () -> readAddressBook("invalidAndValidPersonAddressBook.json")); - } - - @Test - public void readAndSaveAddressBook_allInOrder_success() throws Exception { - Path filePath = testFolder.resolve("TempAddressBook.json"); - AddressBook original = getTypicalAddressBook(); - JsonAddressBookStorage jsonAddressBookStorage = new JsonAddressBookStorage(filePath); - - // Save in new file and read back - jsonAddressBookStorage.saveAddressBook(original, filePath); - ReadOnlyAddressBook readBack = jsonAddressBookStorage.readAddressBook(filePath).get(); - assertEquals(original, new AddressBook(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)); - - // 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)); - - } - - @Test - public void saveAddressBook_nullAddressBook_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> saveAddressBook(null, "SomeFile.json")); - } - - /** - * Saves {@code addressBook} at the specified {@code filePath}. - */ - private void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) { - try { - new JsonAddressBookStorage(Paths.get(filePath)) - .saveAddressBook(addressBook, addToTestDataPathIfNotNull(filePath)); - } catch (IOException ioe) { - throw new AssertionError("There should not be an error writing to the file.", ioe); - } - } - - @Test - public void saveAddressBook_nullFilePath_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> saveAddressBook(new AddressBook(), null)); - } -} 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/AddressBookBuilder.java b/src/test/java/seedu/address/testutil/AddressBookBuilder.java deleted file mode 100644 index d53799fd110..00000000000 --- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java +++ /dev/null @@ -1,34 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.model.AddressBook; -import seedu.address.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 { - - private AddressBook addressBook; - - public AddressBookBuilder() { - addressBook = new AddressBook(); - } - - public AddressBookBuilder(AddressBook addressBook) { - this.addressBook = addressBook; - } - - /** - * Adds a new {@code Person} to the {@code AddressBook} that we are building. - */ - public AddressBookBuilder withPerson(Person person) { - addressBook.addPerson(person); - return this; - } - - public AddressBook build() { - return addressBook; - } -} diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java deleted file mode 100644 index 4584bd5044e..00000000000 --- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java +++ /dev/null @@ -1,87 +0,0 @@ -package seedu.address.testutil; - -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; -import seedu.address.model.tag.Tag; - -/** - * A utility class to help with building EditPersonDescriptor objects. - */ -public class EditPersonDescriptorBuilder { - - private EditPersonDescriptor descriptor; - - public EditPersonDescriptorBuilder() { - descriptor = new EditPersonDescriptor(); - } - - public EditPersonDescriptorBuilder(EditPersonDescriptor descriptor) { - this.descriptor = new EditPersonDescriptor(descriptor); - } - - /** - * Returns an {@code EditPersonDescriptor} with fields containing {@code person}'s details - */ - public EditPersonDescriptorBuilder(Person person) { - descriptor = new EditPersonDescriptor(); - descriptor.setName(person.getName()); - descriptor.setPhone(person.getPhone()); - descriptor.setEmail(person.getEmail()); - descriptor.setAddress(person.getAddress()); - descriptor.setTags(person.getTags()); - } - - /** - * Sets the {@code Name} of the {@code EditPersonDescriptor} that we are building. - */ - public EditPersonDescriptorBuilder withName(String name) { - descriptor.setName(new Name(name)); - return this; - } - - /** - * Sets the {@code Phone} of the {@code EditPersonDescriptor} that we are building. - */ - public EditPersonDescriptorBuilder withPhone(String phone) { - descriptor.setPhone(new Phone(phone)); - return this; - } - - /** - * Sets the {@code Email} of the {@code EditPersonDescriptor} that we are building. - */ - public EditPersonDescriptorBuilder withEmail(String email) { - descriptor.setEmail(new Email(email)); - return this; - } - - /** - * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building. - */ - public EditPersonDescriptorBuilder withAddress(String address) { - descriptor.setAddress(new Address(address)); - return this; - } - - /** - * Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor} - * that we are building. - */ - public EditPersonDescriptorBuilder withTags(String... tags) { - Set tagSet = Stream.of(tags).map(Tag::new).collect(Collectors.toSet()); - descriptor.setTags(tagSet); - return this; - } - - public EditPersonDescriptor build() { - return descriptor; - } -} diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java deleted file mode 100644 index 6be381d39ba..00000000000 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ /dev/null @@ -1,96 +0,0 @@ -package seedu.address.testutil; - -import java.util.HashSet; -import java.util.Set; - -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; -import seedu.address.model.tag.Tag; -import seedu.address.model.util.SampleDataUtil; - -/** - * A utility class to help with building Person objects. - */ -public class PersonBuilder { - - public static final String DEFAULT_NAME = "Amy Bee"; - public static final String DEFAULT_PHONE = "85355255"; - public static final String DEFAULT_EMAIL = "amy@gmail.com"; - public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111"; - - private Name name; - private Phone phone; - private Email email; - private Address address; - private Set tags; - - /** - * Creates a {@code PersonBuilder} with the default details. - */ - public PersonBuilder() { - name = new Name(DEFAULT_NAME); - phone = new Phone(DEFAULT_PHONE); - email = new Email(DEFAULT_EMAIL); - address = new Address(DEFAULT_ADDRESS); - tags = new HashSet<>(); - } - - /** - * Initializes the PersonBuilder with the data of {@code personToCopy}. - */ - public PersonBuilder(Person personToCopy) { - name = personToCopy.getName(); - phone = personToCopy.getPhone(); - email = personToCopy.getEmail(); - address = personToCopy.getAddress(); - tags = new HashSet<>(personToCopy.getTags()); - } - - /** - * Sets the {@code Name} of the {@code Person} that we are building. - */ - public PersonBuilder withName(String name) { - this.name = new Name(name); - return this; - } - - /** - * Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building. - */ - public PersonBuilder withTags(String ... tags) { - this.tags = SampleDataUtil.getTagSet(tags); - return this; - } - - /** - * Sets the {@code Address} of the {@code Person} that we are building. - */ - public PersonBuilder withAddress(String address) { - this.address = new Address(address); - return this; - } - - /** - * Sets the {@code Phone} of the {@code Person} that we are building. - */ - public PersonBuilder withPhone(String phone) { - this.phone = new Phone(phone); - return this; - } - - /** - * Sets the {@code Email} of the {@code Person} that we are building. - */ - public PersonBuilder withEmail(String email) { - this.email = new Email(email); - return this; - } - - public Person build() { - return new Person(name, phone, email, address, tags); - } - -} diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java deleted file mode 100644 index 90849945183..00000000000 --- a/src/test/java/seedu/address/testutil/PersonUtil.java +++ /dev/null @@ -1,62 +0,0 @@ -package seedu.address.testutil; - -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; - -import java.util.Set; - -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.model.person.Person; -import seedu.address.model.tag.Tag; - -/** - * A utility class for Person. - */ -public class PersonUtil { - - /** - * Returns an add command string for adding the {@code person}. - */ - public static String getAddCommand(Person person) { - return AddCommand.COMMAND_WORD + " " + getPersonDetails(person); - } - - /** - * Returns the part of command string for the given {@code person}'s details. - */ - public static String getPersonDetails(Person person) { - StringBuilder sb = new StringBuilder(); - sb.append(PREFIX_NAME + person.getName().fullName + " "); - sb.append(PREFIX_PHONE + person.getPhone().value + " "); - sb.append(PREFIX_EMAIL + person.getEmail().value + " "); - sb.append(PREFIX_ADDRESS + person.getAddress().value + " "); - person.getTags().stream().forEach( - s -> sb.append(PREFIX_TAG + s.tagName + " ") - ); - return sb.toString(); - } - - /** - * Returns the part of command string for the given {@code EditPersonDescriptor}'s details. - */ - public static String getEditPersonDescriptorDetails(EditPersonDescriptor descriptor) { - StringBuilder sb = new StringBuilder(); - descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" ")); - descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" ")); - descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" ")); - descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" ")); - if (descriptor.getTags().isPresent()) { - Set tags = descriptor.getTags().get(); - if (tags.isEmpty()) { - sb.append(PREFIX_TAG); - } else { - tags.forEach(s -> sb.append(PREFIX_TAG).append(s.tagName).append(" ")); - } - } - return sb.toString(); - } -} diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/seedu/address/testutil/TypicalIndexes.java deleted file mode 100644 index 1e613937657..00000000000 --- a/src/test/java/seedu/address/testutil/TypicalIndexes.java +++ /dev/null @@ -1,12 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.commons.core.index.Index; - -/** - * A utility class containing a list of {@code Index} objects to be used in tests. - */ -public class TypicalIndexes { - public static final Index INDEX_FIRST_PERSON = Index.fromOneBased(1); - public static final Index INDEX_SECOND_PERSON = Index.fromOneBased(2); - public static final Index INDEX_THIRD_PERSON = Index.fromOneBased(3); -} 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/seedu/workbook/AppParametersTest.java similarity index 98% rename from src/test/java/seedu/address/AppParametersTest.java rename to src/test/java/seedu/workbook/AppParametersTest.java index 61326b2d31a..b8a0170875b 100644 --- a/src/test/java/seedu/address/AppParametersTest.java +++ b/src/test/java/seedu/workbook/AppParametersTest.java @@ -1,4 +1,4 @@ -package seedu.address; +package seedu.workbook; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/seedu/address/commons/core/ConfigTest.java b/src/test/java/seedu/workbook/commons/core/ConfigTest.java similarity index 95% rename from src/test/java/seedu/address/commons/core/ConfigTest.java rename to src/test/java/seedu/workbook/commons/core/ConfigTest.java index 07cd7f73d53..3eb06410462 100644 --- a/src/test/java/seedu/address/commons/core/ConfigTest.java +++ b/src/test/java/seedu/workbook/commons/core/ConfigTest.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.workbook.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/seedu/workbook/commons/core/VersionTest.java similarity index 98% rename from src/test/java/seedu/address/commons/core/VersionTest.java rename to src/test/java/seedu/workbook/commons/core/VersionTest.java index 495cd231554..b9b6482d3b4 100644 --- a/src/test/java/seedu/address/commons/core/VersionTest.java +++ b/src/test/java/seedu/workbook/commons/core/VersionTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.core; +package seedu.workbook.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 seedu.workbook.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/seedu/workbook/commons/core/index/IndexTest.java similarity index 73% rename from src/test/java/seedu/address/commons/core/index/IndexTest.java rename to src/test/java/seedu/workbook/commons/core/index/IndexTest.java index a3ec6f8e747..10e843b9170 100644 --- a/src/test/java/seedu/address/commons/core/index/IndexTest.java +++ b/src/test/java/seedu/workbook/commons/core/index/IndexTest.java @@ -1,9 +1,9 @@ -package seedu.address.commons.core.index; +package seedu.workbook.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 seedu.workbook.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -39,22 +39,22 @@ public void createZeroBasedIndex() { @Test public void equals() { - final Index fifthPersonIndex = Index.fromOneBased(5); + final Index fifthInternshipIndex = Index.fromOneBased(5); // same values -> returns true - assertTrue(fifthPersonIndex.equals(Index.fromOneBased(5))); - assertTrue(fifthPersonIndex.equals(Index.fromZeroBased(4))); + assertTrue(fifthInternshipIndex.equals(Index.fromOneBased(5))); + assertTrue(fifthInternshipIndex.equals(Index.fromZeroBased(4))); // same object -> returns true - assertTrue(fifthPersonIndex.equals(fifthPersonIndex)); + assertTrue(fifthInternshipIndex.equals(fifthInternshipIndex)); // null -> returns false - assertFalse(fifthPersonIndex.equals(null)); + assertFalse(fifthInternshipIndex.equals(null)); // different types -> returns false - assertFalse(fifthPersonIndex.equals(5.0f)); + assertFalse(fifthInternshipIndex.equals(5.0f)); // different index -> returns false - assertFalse(fifthPersonIndex.equals(Index.fromOneBased(1))); + assertFalse(fifthInternshipIndex.equals(Index.fromOneBased(1))); } } diff --git a/src/test/java/seedu/address/commons/util/AppUtilTest.java b/src/test/java/seedu/workbook/commons/util/AppUtilTest.java similarity index 91% rename from src/test/java/seedu/address/commons/util/AppUtilTest.java rename to src/test/java/seedu/workbook/commons/util/AppUtilTest.java index 594de1e6365..e1921a3d841 100644 --- a/src/test/java/seedu/address/commons/util/AppUtilTest.java +++ b/src/test/java/seedu/workbook/commons/util/AppUtilTest.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package seedu.workbook.commons.util; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static seedu.address.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/address/commons/util/CollectionUtilTest.java b/src/test/java/seedu/workbook/commons/util/CollectionUtilTest.java similarity index 96% rename from src/test/java/seedu/address/commons/util/CollectionUtilTest.java rename to src/test/java/seedu/workbook/commons/util/CollectionUtilTest.java index b467a3dc025..285a80a329b 100644 --- a/src/test/java/seedu/address/commons/util/CollectionUtilTest.java +++ b/src/test/java/seedu/workbook/commons/util/CollectionUtilTest.java @@ -1,9 +1,9 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.commons.util.CollectionUtil.requireAllNonNull; +import static seedu.workbook.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/seedu/workbook/commons/util/ConfigUtilTest.java similarity index 94% rename from src/test/java/seedu/address/commons/util/ConfigUtilTest.java rename to src/test/java/seedu/workbook/commons/util/ConfigUtilTest.java index d2ab2839a52..421a53060ce 100644 --- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java +++ b/src/test/java/seedu/workbook/commons/util/ConfigUtilTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.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 seedu.workbook.commons.core.Config; +import seedu.workbook.commons.exceptions.DataConversionException; public class ConfigUtilTest { diff --git a/src/test/java/seedu/address/commons/util/FileUtilTest.java b/src/test/java/seedu/workbook/commons/util/FileUtilTest.java similarity index 84% rename from src/test/java/seedu/address/commons/util/FileUtilTest.java rename to src/test/java/seedu/workbook/commons/util/FileUtilTest.java index 1fe5478c756..b7a0a7e6cc8 100644 --- a/src/test/java/seedu/address/commons/util/FileUtilTest.java +++ b/src/test/java/seedu/workbook/commons/util/FileUtilTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/seedu/workbook/commons/util/JsonUtilTest.java similarity index 92% rename from src/test/java/seedu/address/commons/util/JsonUtilTest.java rename to src/test/java/seedu/workbook/commons/util/JsonUtilTest.java index d4907539dee..a978ab303f5 100644 --- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java +++ b/src/test/java/seedu/workbook/commons/util/JsonUtilTest.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.testutil.SerializableTestClass; +import seedu.workbook.testutil.TestUtil; /** * Tests JSON Read and Write diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/workbook/commons/util/StringUtilTest.java similarity index 98% rename from src/test/java/seedu/address/commons/util/StringUtilTest.java rename to src/test/java/seedu/workbook/commons/util/StringUtilTest.java index c56d407bf3f..6a638cec7cc 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/workbook/commons/util/StringUtilTest.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package seedu.workbook.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 seedu.workbook.testutil.Assert.assertThrows; import java.io.FileNotFoundException; diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/workbook/logic/LogicManagerTest.java similarity index 61% rename from src/test/java/seedu/address/logic/LogicManagerTest.java rename to src/test/java/seedu/workbook/logic/LogicManagerTest.java index ad923ac249a..8d7096e57cc 100644 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ b/src/test/java/seedu/workbook/logic/LogicManagerTest.java @@ -1,14 +1,15 @@ -package seedu.address.logic; +package seedu.workbook.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 seedu.workbook.commons.core.Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX; +import static seedu.workbook.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static seedu.workbook.logic.commands.CommandTestUtil.COMPANY_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.DATETIME_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.ROLE_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.STAGE_DESC_AMY; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.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 seedu.workbook.logic.commands.AddCommand; +import seedu.workbook.logic.commands.CommandResult; +import seedu.workbook.logic.commands.ListCommand; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.storage.JsonUserPrefsStorage; +import seedu.workbook.storage.JsonWorkBookStorage; +import seedu.workbook.storage.StorageManager; +import seedu.workbook.testutil.InternshipBuilder; public class LogicManagerTest { private static final IOException DUMMY_IO_EXCEPTION = new IOException("dummy exception"); @@ -43,10 +44,10 @@ public class LogicManagerTest { @BeforeEach public void setUp() { - JsonAddressBookStorage addressBookStorage = - new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json")); + JsonWorkBookStorage workBookStorage = + new JsonWorkBookStorage(temporaryFolder.resolve("workBook.json")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json")); - StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage); + StorageManager storage = new StorageManager(workBookStorage, userPrefsStorage); logic = new LogicManager(model, storage); } @@ -59,7 +60,7 @@ public void execute_invalidCommandFormat_throwsParseException() { @Test public void execute_commandExecutionError_throwsCommandException() { String deleteCommand = "delete 9"; - assertCommandException(deleteCommand, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + assertCommandException(deleteCommand, MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); } @Test @@ -70,27 +71,29 @@ public void execute_validCommand_success() throws Exception { @Test public void execute_storageThrowsIoException_throwsCommandException() { - // Setup LogicManager with JsonAddressBookIoExceptionThrowingStub - JsonAddressBookStorage addressBookStorage = - new JsonAddressBookIoExceptionThrowingStub(temporaryFolder.resolve("ioExceptionAddressBook.json")); + // Setup LogicManager with JsonWorkBookIoExceptionThrowingStub + JsonWorkBookStorage workBookStorage = + new JsonWorkBookIoExceptionThrowingStub(temporaryFolder.resolve("ioExceptionWorkBook.json")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("ioExceptionUserPrefs.json")); - StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage); + StorageManager storage = new StorageManager(workBookStorage, userPrefsStorage); logic = new LogicManager(model, storage); // Execute add command - String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY - + ADDRESS_DESC_AMY; - Person expectedPerson = new PersonBuilder(AMY).withTags().build(); + String addCommand = AddCommand.COMMAND_WORD + COMPANY_DESC_AMY + ROLE_DESC_AMY + + EMAIL_DESC_AMY + STAGE_DESC_AMY + DATETIME_DESC_AMY; + + Internship expectedInternship = new InternshipBuilder(AMY).withTags().build(); ModelManager expectedModel = new ModelManager(); - expectedModel.addPerson(expectedPerson); + expectedModel.addInternship(expectedInternship); + expectedModel.commitWorkBook(); String expectedMessage = LogicManager.FILE_OPS_ERROR_MESSAGE + DUMMY_IO_EXCEPTION; assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel); } @Test - public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() { - assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredPersonList().remove(0)); + public void getFilteredInternshipList_modifyList_throwsUnsupportedOperationException() { + assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredInternshipList().remove(0)); } /** @@ -129,7 +132,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.getWorkBook(), new UserPrefs()); assertCommandFailure(inputCommand, expectedException, expectedMessage, expectedModel); } @@ -149,13 +152,13 @@ private void assertCommandFailure(String inputCommand, Class new AddCommand(null)); + } + + @Test + public void execute_internshipAcceptedByModel_addSuccessful() throws Exception { + ModelStubAcceptingInternshipAdded modelStub = new ModelStubAcceptingInternshipAdded(); + Internship validInternship = new InternshipBuilder().build(); + + CommandResult commandResult = new AddCommand(validInternship).execute(modelStub); + + assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, validInternship), commandResult.getFeedbackToUser()); + assertEquals(Arrays.asList(validInternship), modelStub.internshipsAdded); + } + + @Test + public void execute_duplicateInternship_throwsCommandException() { + Internship validInternship = new InternshipBuilder().build(); + AddCommand addCommand = new AddCommand(validInternship); + ModelStub modelStub = new ModelStubWithInternship(validInternship); + + // CHECKSTYLE.OFF: SeparatorWrap + assertThrows( + CommandException.class, AddCommand.MESSAGE_DUPLICATE_INTERNSHIP, + () -> addCommand.execute(modelStub) + ); + // CHECKSTYLE.ON: SeparatorWrap + } + + @Test + public void equals() { + Internship alice = new InternshipBuilder().withCompany("Alice").build(); + Internship bob = new InternshipBuilder().withCompany("Bob").build(); + AddCommand addAliceCommand = new AddCommand(alice); + AddCommand addBobCommand = new AddCommand(bob); + + // same object -> returns true + assertTrue(addAliceCommand.equals(addAliceCommand)); + + // same values -> returns true + AddCommand addAliceCommandCopy = new AddCommand(alice); + assertTrue(addAliceCommand.equals(addAliceCommandCopy)); + + // different types -> returns false + assertFalse(addAliceCommand.equals(1)); + + // null -> returns false + assertFalse(addAliceCommand.equals(null)); + + // different internship -> returns false + assertFalse(addAliceCommand.equals(addBobCommand)); + } + + /** + * A default model stub that have all of the methods failing. + */ + private class ModelStub implements Model { + @Override + public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ReadOnlyUserPrefs getUserPrefs() { + throw new AssertionError("This method should not be called."); + } + + @Override + public GuiSettings getGuiSettings() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setGuiSettings(GuiSettings guiSettings) { + throw new AssertionError("This method should not be called."); + } + + @Override + public Path getWorkBookFilePath() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setWorkBookFilePath(Path workBookFilePath) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addInternship(Internship internship) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setWorkBook(ReadOnlyWorkBook newData) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ReadOnlyWorkBook getWorkBook() { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean hasInternship(Internship internship) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteInternship(Internship target) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setInternship(Internship target, Internship editedInternship) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getFilteredInternshipList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredInternshipList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean canUndoWorkBook() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void undoWorkBook() { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean canRedoWorkBook() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void redoWorkBook() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void commitWorkBook() { + throw new AssertionError("This method should not be called."); + } + } + + /** + * A Model stub that contains a single internship. + */ + private class ModelStubWithInternship extends ModelStub { + private final Internship internship; + + ModelStubWithInternship(Internship internship) { + requireNonNull(internship); + this.internship = internship; + } + + @Override + public boolean hasInternship(Internship internship) { + requireNonNull(internship); + return this.internship.isSameInternship(internship); + } + } + + /** + * A Model stub that always accept the internship being added. + */ + private class ModelStubAcceptingInternshipAdded extends ModelStub { + final ArrayList internshipsAdded = new ArrayList<>(); + + @Override + public boolean hasInternship(Internship internship) { + requireNonNull(internship); + return internshipsAdded.stream().anyMatch(internship::isSameInternship); + } + + @Override + public void addInternship(Internship internship) { + requireNonNull(internship); + internshipsAdded.add(internship); + } + + @Override + public void commitWorkBook() { + // called by {@code AddCommand#execute()} + } + + @Override + public ReadOnlyWorkBook getWorkBook() { + return new WorkBook(); + } + } + +} diff --git a/src/test/java/seedu/workbook/logic/commands/ClearCommandTest.java b/src/test/java/seedu/workbook/logic/commands/ClearCommandTest.java new file mode 100644 index 00000000000..74046fc160e --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/ClearCommandTest.java @@ -0,0 +1,34 @@ +package seedu.workbook.logic.commands; + +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.WorkBook; + +public class ClearCommandTest { + + @Test + public void execute_emptyWorkBook_success() { + Model model = new ModelManager(); + Model expectedModel = new ModelManager(); + expectedModel.commitWorkBook(); + + assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel); + } + + @Test + public void execute_nonEmptyWorkBook_success() { + Model model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + Model expectedModel = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + expectedModel.setWorkBook(new WorkBook()); + expectedModel.commitWorkBook(); + + assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel); + } + +} diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/workbook/logic/commands/CommandResultTest.java similarity index 98% rename from src/test/java/seedu/address/logic/commands/CommandResultTest.java rename to src/test/java/seedu/workbook/logic/commands/CommandResultTest.java index 4f3eb46e9ef..b4b2415d017 100644 --- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java +++ b/src/test/java/seedu/workbook/logic/commands/CommandResultTest.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package seedu.workbook.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/workbook/logic/commands/CommandTestUtil.java b/src/test/java/seedu/workbook/logic/commands/CommandTestUtil.java new file mode 100644 index 00000000000..ee177022cca --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/CommandTestUtil.java @@ -0,0 +1,158 @@ +package seedu.workbook.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.workbook.testutil.Assert.assertThrows; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.logic.commands.exceptions.CommandException; +import seedu.workbook.model.Model; +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.testutil.EditInternshipDescriptorBuilder; + +/** + * Contains helper methods for testing commands. + */ +public class CommandTestUtil { + + public static final String VALID_COMPANY_AMY = "Amy Bee"; + public static final String VALID_COMPANY_BOB = "Bob Choo"; + public static final String VALID_ROLE_AMY = "Software Engineer"; + public static final String VALID_ROLE_BOB = "Backend Engineer"; + 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_STAGE_AMY = "Technical Interview"; + public static final String VALID_STAGE_BOB = "HR Interview"; + public static final String VALID_DATETIME_AMY = "20-Oct-2022 10:00"; + public static final String VALID_DATETIME_BOB = "12-Oct-2022 15:30"; + public static final String VALID_TAG_HUSBAND = "husband"; + public static final String VALID_TAG_FRIEND = "friend"; + + public static final String COMPANY_DESC_AMY = " " + PREFIX_COMPANY + VALID_COMPANY_AMY; + public static final String COMPANY_DESC_BOB = " " + PREFIX_COMPANY + VALID_COMPANY_BOB; + public static final String ROLE_DESC_AMY = " " + PREFIX_ROLE + VALID_ROLE_AMY; + public static final String ROLE_DESC_BOB = " " + PREFIX_ROLE + VALID_ROLE_BOB; + public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY; + public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB; + public static final String STAGE_DESC_AMY = " " + PREFIX_STAGE + VALID_STAGE_AMY; + public static final String STAGE_DESC_BOB = " " + PREFIX_STAGE + VALID_STAGE_BOB; + public static final String DATETIME_DESC_AMY = " " + PREFIX_DATETIME + VALID_DATETIME_AMY; + public static final String DATETIME_DESC_BOB = " " + PREFIX_DATETIME + VALID_DATETIME_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; + + // CHECKSTYLE.OFF: LineLength + public static final String INVALID_COMPANY_DESC = " " + PREFIX_COMPANY + "James&"; // '&' not allowed in company name + public static final String NO_ARGS_COMPANY = " " + PREFIX_COMPANY + ""; // arguments must be present after company prefix + public static final String INVALID_ROLE_DESC = " " + PREFIX_ROLE + "James&"; // '&' not allowed in roles + public static final String NO_ARGS_ROLE = " " + PREFIX_ROLE + ""; // arguments must be present after role prefix + public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol + public static final String INVALID_STAGE_DESC = " " + PREFIX_STAGE + "H&Interview"; // '&' not allowed in stage + public static final String NO_ARGS_STAGE = " " + PREFIX_STAGE + ""; // arguments must be present after stage prefix + public static final String INVALID_DATETIME_DESC = " " + PREFIX_DATETIME + "12-20-2020 12:00"; // MMM instead of MM + // CHECKSTYLE.ON: LineLength + + public static final String PREAMBLE_WHITESPACE = "\t \r \n"; + public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble"; + + public static final EditCommand.EditInternshipDescriptor DESC_AMY; + public static final EditCommand.EditInternshipDescriptor DESC_BOB; + + static { + DESC_AMY = new EditInternshipDescriptorBuilder() + .withCompany(VALID_COMPANY_AMY) + .withRole(VALID_ROLE_AMY) + .withEmail(VALID_EMAIL_AMY) + .withTags(VALID_TAG_FRIEND).build(); + DESC_BOB = new EditInternshipDescriptorBuilder() + .withCompany(VALID_COMPANY_BOB) + .withRole(VALID_ROLE_BOB) + .withEmail(VALID_EMAIL_BOB) + .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); + } + + /** + * Executes the given {@code command}, confirms that
+ * - the returned {@link CommandResult} matches {@code expectedCommandResult}
+ * - the {@code actualModel} matches {@code expectedModel} + */ + public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult, + Model expectedModel) { + try { + CommandResult result = command.execute(actualModel); + assertEquals(expectedCommandResult, result); + assertEquals(expectedModel, actualModel); + } catch (CommandException ce) { + throw new AssertionError("Execution of command should not fail.", ce); + } + } + + /** + * Convenience wrapper to {@link #assertCommandSuccess(Command, Model, CommandResult, Model)} + * that takes a string {@code expectedMessage}. + */ + public static void assertCommandSuccess(Command command, Model actualModel, String expectedMessage, + Model expectedModel) { + CommandResult expectedCommandResult = new CommandResult(expectedMessage); + assertCommandSuccess(command, actualModel, expectedCommandResult, expectedModel); + } + + /** + * Executes the given {@code command}, confirms that
+ * - a {@code CommandException} is thrown
+ * - the CommandException message matches {@code expectedMessage}
+ * - the work book, filtered internship list and selected internship 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. + WorkBook expectedWorkBook = new WorkBook(actualModel.getWorkBook()); + List expectedFilteredList = new ArrayList<>(actualModel.getFilteredInternshipList()); + + assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel)); + assertEquals(expectedWorkBook, actualModel.getWorkBook()); + assertEquals(expectedFilteredList, actualModel.getFilteredInternshipList()); + } + /** + * Updates {@code model}'s filtered list to show only the internship at the given {@code targetIndex} in the + * {@code model}'s work book. + */ + public static void showInternshipAtIndex(Model model, Index targetIndex) { + assertTrue(targetIndex.getZeroBased() < model.getFilteredInternshipList().size()); + + Internship internship = model.getFilteredInternshipList().get(targetIndex.getZeroBased()); + final String[] splitCompany = internship.getCompany().name.split("\\s+"); + model.updateFilteredInternshipList(new CompanyContainsKeywordsPredicate(Arrays.asList(splitCompany[0]))); + + assertEquals(1, model.getFilteredInternshipList().size()); + } + + /** + * Updates {@code model}'s filtered list to show none of the internships in the {@code model}'s work book. + */ + public static void filterOutAllInternships(Model model) { + model.updateFilteredInternshipList(unused -> false); + assertEquals(0, model.getFilteredInternshipList().size()); + } + + /** + * Deletes the first internship in {@code model}'s filtered list from {@code model}'s work book. + */ + public static void deleteFirstInternship(Model model) { + Internship firstInternship = model.getFilteredInternshipList().get(0); + model.deleteInternship(firstInternship); + model.commitWorkBook(); + } +} diff --git a/src/test/java/seedu/workbook/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/workbook/logic/commands/DeleteCommandTest.java new file mode 100644 index 00000000000..1a1cdc55b8b --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/DeleteCommandTest.java @@ -0,0 +1,111 @@ +package seedu.workbook.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.CommandTestUtil.showInternshipAtIndex; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_SECOND_INTERNSHIP; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.commons.core.Messages; +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.internship.Internship; + +/** + * Contains integration tests (interaction with the Model) and unit tests for + * {@code DeleteCommand}. + */ +public class DeleteCommandTest { + + private Model model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + + @Test + public void execute_validIndexUnfilteredList_success() { + Internship internshipToDelete = model.getFilteredInternshipList().get(INDEX_FIRST_INTERNSHIP.getZeroBased()); + DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_INTERNSHIP); + + String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_INTERNSHIP_SUCCESS, internshipToDelete); + + ModelManager expectedModel = new ModelManager(model.getWorkBook(), new UserPrefs()); + expectedModel.deleteInternship(internshipToDelete); + expectedModel.commitWorkBook(); + + assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidIndexUnfilteredList_throwsCommandException() { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredInternshipList().size() + 1); + DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex); + + assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); + } + + @Test + public void execute_validIndexFilteredList_success() { + showInternshipAtIndex(model, INDEX_FIRST_INTERNSHIP); + + Internship internshipToDelete = model.getFilteredInternshipList().get(INDEX_FIRST_INTERNSHIP.getZeroBased()); + DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_INTERNSHIP); + + String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_INTERNSHIP_SUCCESS, internshipToDelete); + + Model expectedModel = new ModelManager(model.getWorkBook(), new UserPrefs()); + expectedModel.deleteInternship(internshipToDelete); + expectedModel.commitWorkBook(); + showNoInternship(expectedModel); + + assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidIndexFilteredList_throwsCommandException() { + showInternshipAtIndex(model, INDEX_FIRST_INTERNSHIP); + + Index outOfBoundIndex = INDEX_SECOND_INTERNSHIP; + // ensures that outOfBoundIndex is still in bounds of work book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getWorkBook().getInternshipList().size()); + + DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex); + + assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); + } + + @Test + public void equals() { + DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_INTERNSHIP); + DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_INTERNSHIP); + + // same object -> returns true + assertTrue(deleteFirstCommand.equals(deleteFirstCommand)); + + // same values -> returns true + DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_INTERNSHIP); + assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy)); + + // different types -> returns false + assertFalse(deleteFirstCommand.equals(1)); + + // null -> returns false + assertFalse(deleteFirstCommand.equals(null)); + + // different internship -> returns false + assertFalse(deleteFirstCommand.equals(deleteSecondCommand)); + } + + /** + * Updates {@code model}'s filtered list to show no one. + */ + private void showNoInternship(Model model) { + model.updateFilteredInternshipList(p -> false); + + assertTrue(model.getFilteredInternshipList().isEmpty()); + } +} diff --git a/src/test/java/seedu/workbook/logic/commands/EditCommandTest.java b/src/test/java/seedu/workbook/logic/commands/EditCommandTest.java new file mode 100644 index 00000000000..27539f3ec7b --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/EditCommandTest.java @@ -0,0 +1,185 @@ +package seedu.workbook.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.logic.commands.CommandTestUtil.DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.CommandTestUtil.filterOutAllInternships; +import static seedu.workbook.logic.commands.CommandTestUtil.showInternshipAtIndex; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_SECOND_INTERNSHIP; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.commons.core.Messages; +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.testutil.EditInternshipDescriptorBuilder; +import seedu.workbook.testutil.InternshipBuilder; + +/** + * Contains integration tests (interaction with the Model) and unit tests for + * EditCommand. + */ +public class EditCommandTest { + + private Model model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + + @Test + public void execute_allFieldsSpecifiedUnfilteredList_success() { + Internship editedInternship = new InternshipBuilder().build(); + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder(editedInternship).build(); + EditCommand editCommand = new EditCommand(INDEX_FIRST_INTERNSHIP, descriptor); + + String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship); + + Model expectedModel = new ModelManager(new WorkBook(model.getWorkBook()), new UserPrefs()); + expectedModel.setInternship(model.getFilteredInternshipList().get(0), editedInternship); + expectedModel.commitWorkBook(); + + assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_someFieldsSpecifiedUnfilteredList_success() { + Index indexLastInternship = Index.fromOneBased(model.getFilteredInternshipList().size()); + Internship lastInternship = model.getFilteredInternshipList().get(indexLastInternship.getZeroBased()); + + InternshipBuilder internshipInList = new InternshipBuilder(lastInternship); + Internship editedInternship = internshipInList.withCompany(VALID_COMPANY_BOB) + .withTags(VALID_TAG_HUSBAND).build(); + + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder().withCompany(VALID_COMPANY_BOB) + .withTags(VALID_TAG_HUSBAND).build(); + EditCommand editCommand = new EditCommand(indexLastInternship, descriptor); + + String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship); + + Model expectedModel = new ModelManager(new WorkBook(model.getWorkBook()), new UserPrefs()); + expectedModel.setInternship(lastInternship, editedInternship); + expectedModel.commitWorkBook(); + + assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_noFieldSpecifiedUnfilteredList_success() { + EditCommand editCommand = new EditCommand(INDEX_FIRST_INTERNSHIP, new EditInternshipDescriptor()); + Internship editedInternship = model.getFilteredInternshipList().get(INDEX_FIRST_INTERNSHIP.getZeroBased()); + + String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship); + + Model expectedModel = new ModelManager(new WorkBook(model.getWorkBook()), new UserPrefs()); + expectedModel.commitWorkBook(); + + assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_filteredList_success() { + showInternshipAtIndex(model, INDEX_FIRST_INTERNSHIP); + + Internship internshipInFilteredList = model.getFilteredInternshipList() + .get(INDEX_FIRST_INTERNSHIP.getZeroBased()); + Internship editedInternship = new InternshipBuilder(internshipInFilteredList).withCompany(VALID_COMPANY_BOB) + .build(); + EditCommand editCommand = new EditCommand(INDEX_FIRST_INTERNSHIP, + new EditInternshipDescriptorBuilder().withCompany(VALID_COMPANY_BOB).build()); + + String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship); + + Model expectedModel = new ModelManager(new WorkBook(model.getWorkBook()), new UserPrefs()); + expectedModel.setInternship(model.getFilteredInternshipList().get(0), editedInternship); + // since `edit` does not reset filtering anymore, and we changed the Company + // name in this test case no internships should match the original predicate + filterOutAllInternships(expectedModel); + expectedModel.commitWorkBook(); + + assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_duplicateInternshipUnfilteredList_failure() { + Internship firstInternship = model.getFilteredInternshipList().get(INDEX_FIRST_INTERNSHIP.getZeroBased()); + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder(firstInternship).build(); + EditCommand editCommand = new EditCommand(INDEX_SECOND_INTERNSHIP, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_INTERNSHIP); + } + + @Test + public void execute_duplicateInternshipFilteredList_failure() { + showInternshipAtIndex(model, INDEX_FIRST_INTERNSHIP); + + // edit internship in filtered list into a duplicate in work book + Internship internshipInList = model.getWorkBook().getInternshipList() + .get(INDEX_SECOND_INTERNSHIP.getZeroBased()); + EditCommand editCommand = new EditCommand(INDEX_FIRST_INTERNSHIP, + new EditInternshipDescriptorBuilder(internshipInList).build()); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_INTERNSHIP); + } + + @Test + public void execute_invalidInternshipIndexUnfilteredList_failure() { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredInternshipList().size() + 1); + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder().withCompany(VALID_COMPANY_BOB) + .build(); + EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor); + + assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); + } + + /** + * Edit filtered list where index is larger than size of filtered list, + * but smaller than size of work book + */ + @Test + public void execute_invalidInternshipIndexFilteredList_failure() { + showInternshipAtIndex(model, INDEX_FIRST_INTERNSHIP); + Index outOfBoundIndex = INDEX_SECOND_INTERNSHIP; + // ensures that outOfBoundIndex is still in bounds of work book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getWorkBook().getInternshipList().size()); + + EditCommand editCommand = new EditCommand(outOfBoundIndex, + new EditInternshipDescriptorBuilder().withCompany(VALID_COMPANY_BOB).build()); + + assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX); + } + + @Test + public void equals() { + final EditCommand standardCommand = new EditCommand(INDEX_FIRST_INTERNSHIP, DESC_AMY); + + // same values -> returns true + EditInternshipDescriptor copyDescriptor = new EditInternshipDescriptor(DESC_AMY); + EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_INTERNSHIP, copyDescriptor); + assertTrue(standardCommand.equals(commandWithSameValues)); + + // same object -> returns true + assertTrue(standardCommand.equals(standardCommand)); + + // null -> returns false + assertFalse(standardCommand.equals(null)); + + // different types -> returns false + assertFalse(standardCommand.equals(new ClearCommand())); + + // different index -> returns false + assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_INTERNSHIP, DESC_AMY))); + + // different descriptor -> returns false + assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_INTERNSHIP, DESC_BOB))); + } + +} diff --git a/src/test/java/seedu/workbook/logic/commands/EditInternshipDescriptorTest.java b/src/test/java/seedu/workbook/logic/commands/EditInternshipDescriptorTest.java new file mode 100644 index 00000000000..e95cbbc17c1 --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/EditInternshipDescriptorTest.java @@ -0,0 +1,51 @@ +package seedu.workbook.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.logic.commands.CommandTestUtil.DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.testutil.EditInternshipDescriptorBuilder; + +public class EditInternshipDescriptorTest { + + @Test + public void equals() { + // same values -> returns true + EditInternshipDescriptor descriptorWithSameValues = new EditInternshipDescriptor(DESC_AMY); + assertTrue(DESC_AMY.equals(descriptorWithSameValues)); + + // same object -> returns true + assertTrue(DESC_AMY.equals(DESC_AMY)); + + // null -> returns false + assertFalse(DESC_AMY.equals(null)); + + // different types -> returns false + assertFalse(DESC_AMY.equals(5)); + + // different values -> returns false + assertFalse(DESC_AMY.equals(DESC_BOB)); + + // different name -> returns false + EditInternshipDescriptor editedAmy = new EditInternshipDescriptorBuilder(DESC_AMY) + .withCompany(VALID_COMPANY_BOB).build(); + assertFalse(DESC_AMY.equals(editedAmy)); + + + // different email -> returns false + editedAmy = new EditInternshipDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build(); + assertFalse(DESC_AMY.equals(editedAmy)); + + + // different tags -> returns false + editedAmy = new EditInternshipDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build(); + assertFalse(DESC_AMY.equals(editedAmy)); + } +} diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/seedu/workbook/logic/commands/ExitCommandTest.java similarity index 60% rename from src/test/java/seedu/address/logic/commands/ExitCommandTest.java rename to src/test/java/seedu/workbook/logic/commands/ExitCommandTest.java index 9533c473875..e7f1290b251 100644 --- a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java +++ b/src/test/java/seedu/workbook/logic/commands/ExitCommandTest.java @@ -1,12 +1,12 @@ -package seedu.address.logic.commands; +package seedu.workbook.logic.commands; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT; import org.junit.jupiter.api.Test; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; public class ExitCommandTest { private Model model = new ModelManager(); diff --git a/src/test/java/seedu/workbook/logic/commands/FindCommandTest.java b/src/test/java/seedu/workbook/logic/commands/FindCommandTest.java new file mode 100644 index 00000000000..488beea3afd --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/FindCommandTest.java @@ -0,0 +1,124 @@ +package seedu.workbook.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.workbook.commons.core.Messages.MESSAGE_INTERNSHIPS_LISTED_OVERVIEW; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.testutil.TypicalInternships.ALICE; +import static seedu.workbook.testutil.TypicalInternships.BENSON; +import static seedu.workbook.testutil.TypicalInternships.CARL; +import static seedu.workbook.testutil.TypicalInternships.DANIEL; +import static seedu.workbook.testutil.TypicalInternships.ELLE; +import static seedu.workbook.testutil.TypicalInternships.FIONA; +import static seedu.workbook.testutil.TypicalInternships.GEORGE; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.InternshipComparator; +import seedu.workbook.model.internship.RoleContainsKeywordsPredicate; +import seedu.workbook.model.internship.StageContainsKeywordsPredicate; + +/** + * Contains integration tests (interaction with the Model) for {@code FindCommand}. + */ +public class FindCommandTest { + private Model model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + + @Test + public void equals() { + CompanyContainsKeywordsPredicate firstPredicate = + new CompanyContainsKeywordsPredicate(Collections.singletonList("first")); + CompanyContainsKeywordsPredicate secondPredicate = + new CompanyContainsKeywordsPredicate(Collections.singletonList("second")); + + FindCommand findFirstCommand = new FindCommand(firstPredicate); + FindCommand findSecondCommand = new FindCommand(secondPredicate); + + // same object -> returns true + assertTrue(findFirstCommand.equals(findFirstCommand)); + + // same values -> returns true + FindCommand findFirstCommandCopy = new FindCommand(firstPredicate); + assertTrue(findFirstCommand.equals(findFirstCommandCopy)); + + // different types -> returns false + assertFalse(findFirstCommand.equals(1)); + + // null -> returns false + assertFalse(findFirstCommand.equals(null)); + + // different internship -> returns false + assertFalse(findFirstCommand.equals(findSecondCommand)); + } + + + @Test + public void execute_multipleKeywords_multipleInternshipsFoundForCompany() { + String expectedMessage = String.format(MESSAGE_INTERNSHIPS_LISTED_OVERVIEW, 1); + Predicate predicate = preparePredicateForCompany("Carl Kurz"); + FindCommand command = new FindCommand(predicate); + expectedModel.updateFilteredInternshipList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + List expectedInternshipList = Arrays.asList(CARL); + Collections.sort(expectedInternshipList, new InternshipComparator()); + assertEquals(expectedInternshipList, model.getFilteredInternshipList()); + } + + @Test + public void execute_multipleKeywords_multipleInternshipsFoundForRole() { + String expectedMessage = String.format(MESSAGE_INTERNSHIPS_LISTED_OVERVIEW, 7); + Predicate predicate = preparePredicateForRole("Software Engineer"); + FindCommand command = new FindCommand(predicate); + expectedModel.updateFilteredInternshipList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + List expectedInternshipList = Arrays.asList(CARL, ELLE, FIONA, ALICE, BENSON, DANIEL, GEORGE); + Collections.sort(expectedInternshipList, new InternshipComparator()); + assertEquals(expectedInternshipList, model.getFilteredInternshipList()); + } + + @Test + public void execute_multipleKeywords_multipleInternshipsFoundForStage() { + String expectedMessage = String.format(MESSAGE_INTERNSHIPS_LISTED_OVERVIEW, 2); + Predicate predicate = preparePredicateForStage("Technical Interview"); + FindCommand command = new FindCommand(predicate); + expectedModel.updateFilteredInternshipList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + List expectedInternshipList = Arrays.asList(ALICE, DANIEL); + Collections.sort(expectedInternshipList, new InternshipComparator()); + assertEquals(expectedInternshipList, model.getFilteredInternshipList()); + } + + /** + * Parses {@code userInput} into a {@code CompanyContainsKeywordsPredicate}. + */ + private Predicate preparePredicateForCompany(String userInput) { + return new CompanyContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + } + + /** + * Parses {@code userInput} into a {@code RoleContainsKeywordsPredicate}. + */ + private Predicate preparePredicateForRole(String userInput) { + return new RoleContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + } + + /** + * Parses {@code userInput} into a {@code StageContainsKeywordsPredicate}. + */ + private Predicate preparePredicateForStage(String userInput) { + return new StageContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + } +} diff --git a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java b/src/test/java/seedu/workbook/logic/commands/HelpCommandTest.java similarity index 60% rename from src/test/java/seedu/address/logic/commands/HelpCommandTest.java rename to src/test/java/seedu/workbook/logic/commands/HelpCommandTest.java index 4904fc4352e..641a742cdfd 100644 --- a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java +++ b/src/test/java/seedu/workbook/logic/commands/HelpCommandTest.java @@ -1,12 +1,12 @@ -package seedu.address.logic.commands; +package seedu.workbook.logic.commands; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE; import org.junit.jupiter.api.Test; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; public class HelpCommandTest { private Model model = new ModelManager(); diff --git a/src/test/java/seedu/workbook/logic/commands/ListCommandTest.java b/src/test/java/seedu/workbook/logic/commands/ListCommandTest.java new file mode 100644 index 00000000000..64b0a516792 --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/ListCommandTest.java @@ -0,0 +1,39 @@ +package seedu.workbook.logic.commands; + +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.CommandTestUtil.showInternshipAtIndex; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; + +/** + * Contains integration tests (interaction with the Model) and unit tests for ListCommand. + */ +public class ListCommandTest { + + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + expectedModel = new ModelManager(model.getWorkBook(), new UserPrefs()); + } + + @Test + public void execute_listIsNotFiltered_showsSameList() { + assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel); + } + + @Test + public void execute_listIsFiltered_showsEverything() { + showInternshipAtIndex(model, INDEX_FIRST_INTERNSHIP); + assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel); + } +} diff --git a/src/test/java/seedu/workbook/logic/commands/RedoCommandTest.java b/src/test/java/seedu/workbook/logic/commands/RedoCommandTest.java new file mode 100644 index 00000000000..c3725d00cb8 --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/RedoCommandTest.java @@ -0,0 +1,50 @@ +package seedu.workbook.logic.commands; + +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.CommandTestUtil.deleteFirstInternship; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; + +/** + * Contains integration tests (interaction with the Model) and unit tests for RedoCommand. + */ +public class RedoCommandTest { + + private final Model model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + private final Model expectedModel = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + + @BeforeEach + public void setUp() { + // set up of both models' undo/redo history + deleteFirstInternship(model); + deleteFirstInternship(model); + model.undoWorkBook(); + model.undoWorkBook(); + + deleteFirstInternship(expectedModel); + deleteFirstInternship(expectedModel); + expectedModel.undoWorkBook(); + expectedModel.undoWorkBook(); + } + + @Test + public void execute() { + // multiple redoable states in model + expectedModel.redoWorkBook(); + assertCommandSuccess(new RedoCommand(), model, RedoCommand.MESSAGE_SUCCESS, expectedModel); + + // single redoable state in model + expectedModel.redoWorkBook(); + assertCommandSuccess(new RedoCommand(), model, RedoCommand.MESSAGE_SUCCESS, expectedModel); + + // no redoable state in model + assertCommandFailure(new RedoCommand(), model, RedoCommand.MESSAGE_FAILURE); + } +} diff --git a/src/test/java/seedu/workbook/logic/commands/UndoCommandTest.java b/src/test/java/seedu/workbook/logic/commands/UndoCommandTest.java new file mode 100644 index 00000000000..1b8c63511c6 --- /dev/null +++ b/src/test/java/seedu/workbook/logic/commands/UndoCommandTest.java @@ -0,0 +1,45 @@ +package seedu.workbook.logic.commands; + +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.workbook.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.workbook.logic.commands.CommandTestUtil.deleteFirstInternship; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.workbook.model.Model; +import seedu.workbook.model.ModelManager; +import seedu.workbook.model.UserPrefs; + +/** + * Contains integration tests (interaction with the Model) and unit tests for UndoCommand. + */ +public class UndoCommandTest { + private final Model model = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + private final Model expectedModel = new ModelManager(getTypicalWorkBook(), new UserPrefs()); + + @BeforeEach + public void setUp() { + // set up of models' undo/redo history + deleteFirstInternship(model); + deleteFirstInternship(model); + + deleteFirstInternship(expectedModel); + deleteFirstInternship(expectedModel); + } + + @Test + public void execute() { + // multiple undoable states in model + expectedModel.undoWorkBook(); + assertCommandSuccess(new UndoCommand(), model, UndoCommand.MESSAGE_SUCCESS, expectedModel); + + // single undoable state in model + expectedModel.undoWorkBook(); + assertCommandSuccess(new UndoCommand(), model, UndoCommand.MESSAGE_SUCCESS, expectedModel); + + // no undoable states in model + assertCommandFailure(new UndoCommand(), model, UndoCommand.MESSAGE_NO_CHANGES); + } +} diff --git a/src/test/java/seedu/workbook/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/workbook/logic/parser/AddCommandParserTest.java new file mode 100644 index 00000000000..99b37c1f069 --- /dev/null +++ b/src/test/java/seedu/workbook/logic/parser/AddCommandParserTest.java @@ -0,0 +1,164 @@ +package seedu.workbook.logic.parser; + +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.commands.CommandTestUtil.COMPANY_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.COMPANY_DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.DATETIME_DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_COMPANY_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_DATETIME_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_ROLE_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_STAGE_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY; +import static seedu.workbook.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static seedu.workbook.logic.commands.CommandTestUtil.ROLE_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.ROLE_DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.STAGE_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.STAGE_DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.TAG_DESC_FRIEND; +import static seedu.workbook.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_ROLE_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_STAGE_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static seedu.workbook.testutil.TypicalInternships.AMY; +import static seedu.workbook.testutil.TypicalInternships.BOB; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.logic.commands.AddCommand; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.testutil.InternshipBuilder; + +public class AddCommandParserTest { + private AddCommandParser parser = new AddCommandParser(); + + @Test + public void parse_allFieldsPresent_success() { + Internship expectedInternship = new InternshipBuilder(BOB).withTags(VALID_TAG_FRIEND).build(); + + // whitespace only preamble + assertParseSuccess(parser, + PREAMBLE_WHITESPACE + COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_BOB + + STAGE_DESC_BOB + DATETIME_DESC_BOB + TAG_DESC_FRIEND, + new AddCommand(expectedInternship)); + + // multiple company names - last company name accepted + assertParseSuccess(parser, COMPANY_DESC_AMY + COMPANY_DESC_BOB + ROLE_DESC_BOB + + EMAIL_DESC_BOB + STAGE_DESC_BOB + DATETIME_DESC_BOB + TAG_DESC_FRIEND, + new AddCommand(expectedInternship)); + + // multiple roles - last role accepted + assertParseSuccess(parser, COMPANY_DESC_BOB + ROLE_DESC_AMY + ROLE_DESC_BOB + EMAIL_DESC_BOB + + STAGE_DESC_BOB + DATETIME_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedInternship)); + + + // multiple emails - last email accepted + assertParseSuccess(parser, COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_AMY + EMAIL_DESC_BOB + + STAGE_DESC_BOB + DATETIME_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedInternship)); + + // multiple stages - last stage accepted + assertParseSuccess(parser, COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_BOB + + STAGE_DESC_AMY + STAGE_DESC_BOB + DATETIME_DESC_BOB + TAG_DESC_FRIEND, + new AddCommand(expectedInternship)); + + // multiple tags - all accepted + Internship expectedInternshipMultipleTags = new InternshipBuilder(BOB) + .withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND) + .build(); + assertParseSuccess(parser, COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_BOB + + STAGE_DESC_BOB + DATETIME_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + new AddCommand(expectedInternshipMultipleTags)); + } + + @Test + public void parse_optionalFieldsMissing_success() { + Internship expectedInternship = new InternshipBuilder(AMY).withDateTime("").withEmail("").withTags().build(); + assertParseSuccess(parser, + COMPANY_DESC_AMY + ROLE_DESC_AMY + STAGE_DESC_AMY, + new AddCommand(expectedInternship)); + } + + @Test + public void parse_compulsoryFieldMissing_failure() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); + + // missing company prefix + assertParseFailure(parser, + VALID_COMPANY_BOB + ROLE_DESC_BOB + STAGE_DESC_BOB, + expectedMessage); + + // missing role prefix + assertParseFailure(parser, + COMPANY_DESC_BOB + VALID_ROLE_BOB + STAGE_DESC_BOB, + expectedMessage); + + + // missing stage prefix + assertParseFailure(parser, + COMPANY_DESC_BOB + ROLE_DESC_BOB + VALID_STAGE_BOB, + expectedMessage); + + + // all prefixes missing + assertParseFailure(parser, + VALID_COMPANY_BOB + VALID_ROLE_BOB + VALID_STAGE_BOB, + expectedMessage); + } + + @Test + public void parse_invalidValue_failure() { + // invalid company + assertParseFailure(parser, + INVALID_COMPANY_DESC + ROLE_DESC_BOB + EMAIL_DESC_BOB + STAGE_DESC_BOB + + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + Company.MESSAGE_CONSTRAINTS); + + // invalid role + assertParseFailure(parser, + COMPANY_DESC_BOB + INVALID_ROLE_DESC + EMAIL_DESC_BOB + STAGE_DESC_BOB + + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + Role.MESSAGE_CONSTRAINTS); + + + // invalid email + assertParseFailure(parser, + COMPANY_DESC_BOB + ROLE_DESC_BOB + INVALID_EMAIL_DESC + STAGE_DESC_BOB + + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + Email.MESSAGE_CONSTRAINTS); + + // invalid stage + assertParseFailure(parser, + COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_BOB + INVALID_STAGE_DESC + + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + Stage.MESSAGE_CONSTRAINTS); + + // invalid DateTime + assertParseFailure(parser, + COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_BOB + STAGE_DESC_BOB + + INVALID_DATETIME_DESC + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + DateTime.MESSAGE_CONSTRAINTS); + + + // two invalid values, only first invalid value reported + assertParseFailure(parser, + INVALID_COMPANY_DESC + ROLE_DESC_BOB + EMAIL_DESC_BOB + STAGE_DESC_BOB, + Company.MESSAGE_CONSTRAINTS); + + // non-empty preamble + assertParseFailure(parser, + PREAMBLE_NON_EMPTY + COMPANY_DESC_BOB + ROLE_DESC_BOB + EMAIL_DESC_BOB + + STAGE_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/seedu/workbook/logic/parser/ArgumentTokenizerTest.java similarity index 99% rename from src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java rename to src/test/java/seedu/workbook/logic/parser/ArgumentTokenizerTest.java index c97308935f5..c82b2ec79ec 100644 --- a/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java +++ b/src/test/java/seedu/workbook/logic/parser/ArgumentTokenizerTest.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package seedu.workbook.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/seedu/workbook/logic/parser/CommandParserTestUtil.java similarity index 89% rename from src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java rename to src/test/java/seedu/workbook/logic/parser/CommandParserTestUtil.java index 9bf1ccf1cef..9f594952118 100644 --- a/src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java +++ b/src/test/java/seedu/workbook/logic/parser/CommandParserTestUtil.java @@ -1,9 +1,9 @@ -package seedu.address.logic.parser; +package seedu.workbook.logic.parser; import static org.junit.jupiter.api.Assertions.assertEquals; -import seedu.address.logic.commands.Command; -import seedu.address.logic.parser.exceptions.ParseException; +import seedu.workbook.logic.commands.Command; +import seedu.workbook.logic.parser.exceptions.ParseException; /** * Contains helper methods for testing command parsers. diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/workbook/logic/parser/DeleteCommandParserTest.java similarity index 66% rename from src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java rename to src/test/java/seedu/workbook/logic/parser/DeleteCommandParserTest.java index 27eaec84450..0428dfb1169 100644 --- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java +++ b/src/test/java/seedu/workbook/logic/parser/DeleteCommandParserTest.java @@ -1,13 +1,13 @@ -package seedu.address.logic.parser; +package seedu.workbook.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 seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; import org.junit.jupiter.api.Test; -import seedu.address.logic.commands.DeleteCommand; +import seedu.workbook.logic.commands.DeleteCommand; /** * As we are only doing white-box testing, our test cases do not cover path variations @@ -22,7 +22,7 @@ public class DeleteCommandParserTest { @Test public void parse_validArgs_returnsDeleteCommand() { - assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON)); + assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_INTERNSHIP)); } @Test diff --git a/src/test/java/seedu/workbook/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/workbook/logic/parser/EditCommandParserTest.java new file mode 100644 index 00000000000..dd75157a71e --- /dev/null +++ b/src/test/java/seedu/workbook/logic/parser/EditCommandParserTest.java @@ -0,0 +1,172 @@ +package seedu.workbook.logic.parser; + +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.commands.CommandTestUtil.COMPANY_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_COMPANY_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; +import static seedu.workbook.logic.commands.CommandTestUtil.TAG_DESC_FRIEND; +import static seedu.workbook.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_SECOND_INTERNSHIP; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_THIRD_INTERNSHIP; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.commons.core.index.Index; +import seedu.workbook.logic.commands.EditCommand; +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.Email; +import seedu.workbook.testutil.EditInternshipDescriptorBuilder; + +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); + + private EditCommandParser parser = new EditCommandParser(); + + @Test + public void parse_missingParts_failure() { + // no index specified + assertParseFailure(parser, VALID_COMPANY_AMY, MESSAGE_INVALID_FORMAT); + + // no field specified + assertParseFailure(parser, "1", EditCommand.MESSAGE_NOT_EDITED); + + // no index and no field specified + assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT); + } + + @Test + public void parse_invalidPreamble_failure() { + // negative index + assertParseFailure(parser, "-5" + COMPANY_DESC_AMY, MESSAGE_INVALID_FORMAT); + + // zero index + assertParseFailure(parser, "0" + COMPANY_DESC_AMY, MESSAGE_INVALID_FORMAT); + + // invalid arguments being parsed as preamble + assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT); + + // invalid prefix being parsed as preamble + assertParseFailure(parser, "1 i/ string", MESSAGE_INVALID_FORMAT); + } + + @Test + public void parse_invalidValue_failure() { + assertParseFailure(parser, "1" + INVALID_COMPANY_DESC, Company.MESSAGE_CONSTRAINTS); // invalid name + assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email + + // multiple invalid values, but only the first invalid value is captured + assertParseFailure(parser, + "1" + INVALID_COMPANY_DESC + INVALID_EMAIL_DESC, + Company.MESSAGE_CONSTRAINTS); + } + + @Test + public void parse_allFieldsSpecified_success() { + Index targetIndex = INDEX_SECOND_INTERNSHIP; + String userInput = targetIndex.getOneBased() + TAG_DESC_HUSBAND + + EMAIL_DESC_AMY + COMPANY_DESC_AMY + TAG_DESC_FRIEND; + + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder().withCompany(VALID_COMPANY_AMY) + .withEmail(VALID_EMAIL_AMY) + .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); + EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + + assertParseSuccess(parser, userInput, expectedCommand); + } + + @Test + public void parse_someFieldsSpecified_success() { + Index targetIndex = INDEX_FIRST_INTERNSHIP; + String userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY; + + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder() + .withEmail(VALID_EMAIL_AMY).build(); + EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + + assertParseSuccess(parser, userInput, expectedCommand); + } + + @Test + public void parse_oneFieldSpecified_success() { + // name + Index targetIndex = INDEX_THIRD_INTERNSHIP; + String userInput = targetIndex.getOneBased() + COMPANY_DESC_AMY; + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder().withCompany(VALID_COMPANY_AMY) + .build(); + EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + assertParseSuccess(parser, userInput, expectedCommand); + + + // email + userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY; + descriptor = new EditInternshipDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build(); + expectedCommand = new EditCommand(targetIndex, descriptor); + assertParseSuccess(parser, userInput, expectedCommand); + + + // tags + userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND; + descriptor = new EditInternshipDescriptorBuilder().withTags(VALID_TAG_FRIEND).build(); + expectedCommand = new EditCommand(targetIndex, descriptor); + assertParseSuccess(parser, userInput, expectedCommand); + } + + @Test + public void parse_multipleRepeatedFields_acceptsLast() { + Index targetIndex = INDEX_FIRST_INTERNSHIP; + String userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY + + TAG_DESC_FRIEND + EMAIL_DESC_AMY + TAG_DESC_FRIEND + + EMAIL_DESC_BOB + TAG_DESC_HUSBAND; + + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder() + .withEmail(VALID_EMAIL_BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND) + .build(); + EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + + assertParseSuccess(parser, userInput, expectedCommand); + } + + @Test + public void parse_invalidValueFollowedByValidValue_success() { + // no other valid values specified + Index targetIndex = INDEX_FIRST_INTERNSHIP; + String userInput = targetIndex.getOneBased() + INVALID_EMAIL_DESC + EMAIL_DESC_BOB; + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder().withEmail(VALID_EMAIL_BOB).build(); + EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + assertParseSuccess(parser, userInput, expectedCommand); + + // other valid values specified + userInput = targetIndex.getOneBased() + EMAIL_DESC_BOB; + descriptor = new EditInternshipDescriptorBuilder().withEmail(VALID_EMAIL_BOB) + .build(); + expectedCommand = new EditCommand(targetIndex, descriptor); + assertParseSuccess(parser, userInput, expectedCommand); + } + + @Test + public void parse_resetTags_success() { + Index targetIndex = INDEX_THIRD_INTERNSHIP; + String userInput = targetIndex.getOneBased() + TAG_EMPTY; + + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder().withTags().build(); + EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + + assertParseSuccess(parser, userInput, expectedCommand); + } +} diff --git a/src/test/java/seedu/workbook/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/workbook/logic/parser/FindCommandParserTest.java new file mode 100644 index 00000000000..6e5a85ea202 --- /dev/null +++ b/src/test/java/seedu/workbook/logic/parser/FindCommandParserTest.java @@ -0,0 +1,74 @@ +package seedu.workbook.logic.parser; + +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.logic.commands.CommandTestUtil.COMPANY_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.NO_ARGS_COMPANY; +import static seedu.workbook.logic.commands.CommandTestUtil.NO_ARGS_ROLE; +import static seedu.workbook.logic.commands.CommandTestUtil.NO_ARGS_STAGE; +import static seedu.workbook.logic.commands.CommandTestUtil.ROLE_DESC_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.STAGE_DESC_AMY; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.workbook.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.logic.commands.FindCommand; +import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate; +import seedu.workbook.model.internship.RoleContainsKeywordsPredicate; +import seedu.workbook.model.internship.StageContainsKeywordsPredicate; + +public class FindCommandParserTest { + + private FindCommandParser parser = new FindCommandParser(); + + @Test + public void parse_emptyArg_throwsParseException() { + assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_validArgs_returnsFindCommand() { + // no leading and trailing whitespaces + FindCommand expectedCompanyFindCommand = + new FindCommand(new CompanyContainsKeywordsPredicate(Arrays.asList("Amy", "Bee"))); + assertParseSuccess(parser, COMPANY_DESC_AMY, expectedCompanyFindCommand); + + FindCommand expectedStageFindCommand = + new FindCommand(new StageContainsKeywordsPredicate(Arrays.asList("Technical", "Interview"))); + assertParseSuccess(parser, STAGE_DESC_AMY, expectedStageFindCommand); + + FindCommand expectedRoleFindCommand = + new FindCommand(new RoleContainsKeywordsPredicate(Arrays.asList("Software", "Engineer"))); + assertParseSuccess(parser, ROLE_DESC_AMY, expectedRoleFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, COMPANY_DESC_AMY, expectedCompanyFindCommand); + assertParseSuccess(parser, STAGE_DESC_AMY, expectedStageFindCommand); + assertParseSuccess(parser, ROLE_DESC_AMY, expectedRoleFindCommand); + } + + @Test + public void parse_invalidArgs_throwsParseException() { + // no searching for company and role in the same command + assertParseFailure(parser, COMPANY_DESC_AMY + + ROLE_DESC_AMY, String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + + //no prefix provided + assertParseFailure(parser, "amy bee", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_emptyArguments_throwsParseException() { + assertParseFailure(parser, NO_ARGS_COMPANY, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + + assertParseFailure(parser, NO_ARGS_ROLE, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + + assertParseFailure(parser, NO_ARGS_STAGE, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + +} diff --git a/src/test/java/seedu/workbook/logic/parser/ParserUtilTest.java b/src/test/java/seedu/workbook/logic/parser/ParserUtilTest.java new file mode 100644 index 00000000000..645528362cd --- /dev/null +++ b/src/test/java/seedu/workbook/logic/parser/ParserUtilTest.java @@ -0,0 +1,141 @@ +package seedu.workbook.logic.parser; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.tag.Tag; + +public class ParserUtilTest { + private static final String INVALID_COMPANY = "R@chel"; + private static final String INVALID_EMAIL = "example.com"; + + private static final String VALID_COMPANY = "Rachel Walker"; + 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 WHITESPACE = " \t\r\n"; + + @Test + public void parseIndex_invalidInput_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseIndex("10 a")); + } + + @Test + public void parseIndex_outOfRangeInput_throwsParseException() { + assertThrows(ParseException.class, MESSAGE_INVALID_INDEX, () + -> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1))); + } + + @Test + public void parseIndex_validInput_success() throws Exception { + // No whitespaces + assertEquals(INDEX_FIRST_INTERNSHIP, ParserUtil.parseIndex("1")); + + // Leading and trailing whitespaces + assertEquals(INDEX_FIRST_INTERNSHIP, ParserUtil.parseIndex(" 1 ")); + } + + @Test + public void parseCompany_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseCompany((String) null)); + } + + @Test + public void parseCompany_invalidValue_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseCompany(INVALID_COMPANY)); + } + + @Test + public void parseCompany_validValueWithoutWhitespace_returnsCompany() throws Exception { + Company expectedCompany = new Company(VALID_COMPANY); + assertEquals(expectedCompany, ParserUtil.parseCompany(VALID_COMPANY)); + } + + @Test + public void parseCompany_validValueWithWhitespace_returnsTrimmedCompany() throws Exception { + String companyWithWhitespace = WHITESPACE + VALID_COMPANY + WHITESPACE; + Company expectedCompany = new Company(VALID_COMPANY); + assertEquals(expectedCompany, ParserUtil.parseCompany(companyWithWhitespace)); + } + + @Test + public void parseEmail_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseEmail((String) null)); + } + + @Test + public void parseEmail_invalidValue_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseEmail(INVALID_EMAIL)); + } + + @Test + public void parseEmail_validValueWithoutWhitespace_returnsEmail() throws Exception { + Email expectedEmail = new Email(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); + assertEquals(expectedEmail, ParserUtil.parseEmail(emailWithWhitespace)); + } + + @Test + public void parseTag_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseTag(null)); + } + + @Test + public void parseTag_validValueWithoutWhitespace_returnsTag() throws Exception { + Tag expectedTag = new Tag(VALID_TAG_1); + assertEquals(expectedTag, ParserUtil.parseTag(VALID_TAG_1)); + } + + @Test + public void parseTag_validValueWithWhitespace_returnsTrimmedTag() throws Exception { + String tagWithWhitespace = WHITESPACE + VALID_TAG_1 + WHITESPACE; + Tag expectedTag = new Tag(VALID_TAG_1); + assertEquals(expectedTag, ParserUtil.parseTag(tagWithWhitespace)); + } + + @Test + public void parseTags_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseTags(null)); + } + + @Test + public void parseTags_emptyCollection_returnsEmptySet() throws Exception { + assertTrue(ParserUtil.parseTags(Collections.emptyList()).isEmpty()); + } + + @Test + public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception { + Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, VALID_TAG_2)); + Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2))); + + assertEquals(expectedTagSet, actualTagSet); + } + + @Test + public void parseTags_collectionWithSomeEmptyTags_returnsTagSetWithoutEmptyTags() throws Exception { + Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, WHITESPACE, VALID_TAG_2)); + Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2))); + + assertEquals(expectedTagSet, actualTagSet); + } +} diff --git a/src/test/java/seedu/workbook/logic/parser/WorkBookParserTest.java b/src/test/java/seedu/workbook/logic/parser/WorkBookParserTest.java new file mode 100644 index 00000000000..787a9d8b7bf --- /dev/null +++ b/src/test/java/seedu/workbook/logic/parser/WorkBookParserTest.java @@ -0,0 +1,118 @@ +package seedu.workbook.logic.parser; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.workbook.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static seedu.workbook.logic.commands.CommandTestUtil.COMPANY_DESC_AMY; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.logic.commands.AddCommand; +import seedu.workbook.logic.commands.ClearCommand; +import seedu.workbook.logic.commands.DeleteCommand; +import seedu.workbook.logic.commands.EditCommand; +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.logic.commands.ExitCommand; +import seedu.workbook.logic.commands.FindCommand; +import seedu.workbook.logic.commands.HelpCommand; +import seedu.workbook.logic.commands.ListCommand; +import seedu.workbook.logic.commands.RedoCommand; +import seedu.workbook.logic.commands.UndoCommand; +import seedu.workbook.logic.parser.exceptions.ParseException; +import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.testutil.EditInternshipDescriptorBuilder; +import seedu.workbook.testutil.InternshipBuilder; +import seedu.workbook.testutil.InternshipUtil; + +public class WorkBookParserTest { + + private final WorkBookParser parser = new WorkBookParser(); + + @Test + public void parseCommand_add() throws Exception { + Internship internship = new InternshipBuilder().build(); + AddCommand command = (AddCommand) parser.parseCommand(InternshipUtil.getAddCommand(internship)); + assertEquals(new AddCommand(internship), command); + } + + @Test + public void parseCommand_clear() throws Exception { + assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand); + assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand); + } + + @Test + public void parseCommand_delete() throws Exception { + DeleteCommand command = (DeleteCommand) parser.parseCommand( + DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_INTERNSHIP.getOneBased()); + assertEquals(new DeleteCommand(INDEX_FIRST_INTERNSHIP), command); + } + + @Test + public void parseCommand_edit() throws Exception { + Internship internship = new InternshipBuilder().build(); + EditInternshipDescriptor descriptor = new EditInternshipDescriptorBuilder(internship).build(); + EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " " + + INDEX_FIRST_INTERNSHIP.getOneBased() + " " + + InternshipUtil.getEditInternshipDescriptorDetails(descriptor)); + assertEquals(new EditCommand(INDEX_FIRST_INTERNSHIP, descriptor), command); + } + + @Test + public void parseCommand_exit() throws Exception { + assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand); + assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand); + } + + @Test + public void parseCommand_undo() throws Exception { + assertTrue(parser.parseCommand(UndoCommand.COMMAND_WORD) instanceof UndoCommand); + assertTrue(parser.parseCommand(UndoCommand.COMMAND_WORD + " 3") instanceof UndoCommand); + } + + @Test + public void parseCommand_redo() throws Exception { + assertTrue(parser.parseCommand(RedoCommand.COMMAND_WORD) instanceof RedoCommand); + assertTrue(parser.parseCommand(RedoCommand.COMMAND_WORD + " 3") instanceof RedoCommand); + } + + @Test + public void parseCommand_find() throws Exception { + List keywords = Arrays.asList("Amy", "Bee"); + FindCommand command = (FindCommand) parser.parseCommand( + FindCommand.COMMAND_WORD + " " + COMPANY_DESC_AMY); + assertEquals(new FindCommand(new CompanyContainsKeywordsPredicate(keywords)), command); + } + + @Test + public void parseCommand_help() throws Exception { + assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand); + assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand); + } + + @Test + public void parseCommand_list() throws Exception { + assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand); + assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand); + } + + // CHECKSTYLE.OFF: SeparatorWrap + @Test + public void parseCommand_unrecognisedInput_throwsParseException() { + assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), + () -> parser.parseCommand("")); + } + // CHECKSTYLE.ON: SeparatorWrap + + @Test + 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/seedu/workbook/model/ModelManagerTest.java similarity index 52% rename from src/test/java/seedu/address/model/ModelManagerTest.java rename to src/test/java/seedu/workbook/model/ModelManagerTest.java index 2cf1418d116..cad8ba537cf 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/workbook/model/ModelManagerTest.java @@ -1,12 +1,12 @@ -package seedu.address.model; +package seedu.workbook.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 seedu.workbook.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.ALICE; +import static seedu.workbook.testutil.TypicalInternships.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 seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate; +import seedu.workbook.testutil.WorkBookBuilder; 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 WorkBook(), new WorkBook(modelManager.getWorkBook())); } @Test @@ -37,14 +37,14 @@ public void setUserPrefs_nullUserPrefs_throwsNullPointerException() { @Test public void setUserPrefs_validUserPrefs_copiesUserPrefs() { UserPrefs userPrefs = new UserPrefs(); - userPrefs.setAddressBookFilePath(Paths.get("address/book/file/path")); + userPrefs.setWorkBookFilePath(Paths.get("work/book/file/path")); userPrefs.setGuiSettings(new GuiSettings(1, 2, 3, 4)); modelManager.setUserPrefs(userPrefs); assertEquals(userPrefs, modelManager.getUserPrefs()); // Modifying userPrefs should not modify modelManager's userPrefs UserPrefs oldUserPrefs = new UserPrefs(userPrefs); - userPrefs.setAddressBookFilePath(Paths.get("new/address/book/file/path")); + userPrefs.setWorkBookFilePath(Paths.get("new/work/book/file/path")); assertEquals(oldUserPrefs, modelManager.getUserPrefs()); } @@ -61,47 +61,47 @@ public void setGuiSettings_validGuiSettings_setsGuiSettings() { } @Test - public void setAddressBookFilePath_nullPath_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> modelManager.setAddressBookFilePath(null)); + public void setWorkBookFilePath_nullPath_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> modelManager.setWorkBookFilePath(null)); } @Test - public void setAddressBookFilePath_validPath_setsAddressBookFilePath() { - Path path = Paths.get("address/book/file/path"); - modelManager.setAddressBookFilePath(path); - assertEquals(path, modelManager.getAddressBookFilePath()); + public void setWorkBookFilePath_validPath_setsWorkBookFilePath() { + Path path = Paths.get("work/book/file/path"); + modelManager.setWorkBookFilePath(path); + assertEquals(path, modelManager.getWorkBookFilePath()); } @Test - public void hasPerson_nullPerson_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> modelManager.hasPerson(null)); + public void hasInternship_nullInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> modelManager.hasInternship(null)); } @Test - public void hasPerson_personNotInAddressBook_returnsFalse() { - assertFalse(modelManager.hasPerson(ALICE)); + public void hasInternship_internshipNotInWorkBook_returnsFalse() { + assertFalse(modelManager.hasInternship(ALICE)); } @Test - public void hasPerson_personInAddressBook_returnsTrue() { - modelManager.addPerson(ALICE); - assertTrue(modelManager.hasPerson(ALICE)); + public void hasInternship_internshipInWorkBook_returnsTrue() { + modelManager.addInternship(ALICE); + assertTrue(modelManager.hasInternship(ALICE)); } @Test - public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() { - assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0)); + public void getFilteredInternshipList_modifyList_throwsUnsupportedOperationException() { + assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredInternshipList().remove(0)); } @Test public void equals() { - AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build(); - AddressBook differentAddressBook = new AddressBook(); + WorkBook workBook = new WorkBookBuilder().withInternship(ALICE).withInternship(BENSON).build(); + WorkBook differentWorkBook = new WorkBook(); UserPrefs userPrefs = new UserPrefs(); // same values -> returns true - modelManager = new ModelManager(addressBook, userPrefs); - ModelManager modelManagerCopy = new ModelManager(addressBook, userPrefs); + modelManager = new ModelManager(workBook, userPrefs); + ModelManager modelManagerCopy = new ModelManager(workBook, userPrefs); assertTrue(modelManager.equals(modelManagerCopy)); // same object -> returns true @@ -113,20 +113,20 @@ public void equals() { // different types -> returns false assertFalse(modelManager.equals(5)); - // different addressBook -> returns false - assertFalse(modelManager.equals(new ModelManager(differentAddressBook, userPrefs))); + // different workBook -> returns false + assertFalse(modelManager.equals(new ModelManager(differentWorkBook, userPrefs))); // different filteredList -> returns false - String[] keywords = ALICE.getName().fullName.split("\\s+"); - modelManager.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(keywords))); - assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs))); + String[] keywords = ALICE.getCompany().name.split("\\s+"); + modelManager.updateFilteredInternshipList(new CompanyContainsKeywordsPredicate(Arrays.asList(keywords))); + assertFalse(modelManager.equals(new ModelManager(workBook, userPrefs))); // resets modelManager to initial state for upcoming tests - modelManager.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + modelManager.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS); // different userPrefs -> returns false UserPrefs differentUserPrefs = new UserPrefs(); - differentUserPrefs.setAddressBookFilePath(Paths.get("differentFilePath")); - assertFalse(modelManager.equals(new ModelManager(addressBook, differentUserPrefs))); + differentUserPrefs.setWorkBookFilePath(Paths.get("differentFilePath")); + assertFalse(modelManager.equals(new ModelManager(workBook, differentUserPrefs))); } } diff --git a/src/test/java/seedu/address/model/UserPrefsTest.java b/src/test/java/seedu/workbook/model/UserPrefsTest.java similarity index 68% rename from src/test/java/seedu/address/model/UserPrefsTest.java rename to src/test/java/seedu/workbook/model/UserPrefsTest.java index b1307a70d52..c0112c8e5c9 100644 --- a/src/test/java/seedu/address/model/UserPrefsTest.java +++ b/src/test/java/seedu/workbook/model/UserPrefsTest.java @@ -1,6 +1,6 @@ -package seedu.address.model; +package seedu.workbook.model; -import static seedu.address.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -13,9 +13,9 @@ public void setGuiSettings_nullGuiSettings_throwsNullPointerException() { } @Test - public void setAddressBookFilePath_nullPath_throwsNullPointerException() { + public void setWorkBookFilePath_nullPath_throwsNullPointerException() { UserPrefs userPrefs = new UserPrefs(); - assertThrows(NullPointerException.class, () -> userPrefs.setAddressBookFilePath(null)); + assertThrows(NullPointerException.class, () -> userPrefs.setWorkBookFilePath(null)); } } diff --git a/src/test/java/seedu/workbook/model/WorkBookTest.java b/src/test/java/seedu/workbook/model/WorkBookTest.java new file mode 100644 index 00000000000..39440c6b335 --- /dev/null +++ b/src/test/java/seedu/workbook/model/WorkBookTest.java @@ -0,0 +1,101 @@ +package seedu.workbook.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.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.ALICE; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.exceptions.DuplicateInternshipException; +import seedu.workbook.testutil.InternshipBuilder; + +public class WorkBookTest { + + private final WorkBook workBook = new WorkBook(); + + @Test + public void constructor() { + assertEquals(Collections.emptyList(), workBook.getInternshipList()); + } + + @Test + public void resetData_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> workBook.resetData(null)); + } + + @Test + public void resetData_withValidReadOnlyWorkBook_replacesData() { + WorkBook newData = getTypicalWorkBook(); + workBook.resetData(newData); + assertEquals(newData, workBook); + } + + @Test + public void resetData_withDuplicateInternships_throwsDuplicateInternshipException() { + // Two internships with the same identity fields + Internship editedAlice = new InternshipBuilder(ALICE).withTags(VALID_TAG_HUSBAND) + .build(); + List newInternships = Arrays.asList(ALICE, editedAlice); + WorkBookStub newData = new WorkBookStub(newInternships); + + assertThrows(DuplicateInternshipException.class, () -> workBook.resetData(newData)); + } + + @Test + public void hasInternship_nullInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> workBook.hasInternship(null)); + } + + @Test + public void hasInternship_internshipNotInWorkBook_returnsFalse() { + assertFalse(workBook.hasInternship(ALICE)); + } + + @Test + public void hasInternship_internshipInWorkBook_returnsTrue() { + workBook.addInternship(ALICE); + assertTrue(workBook.hasInternship(ALICE)); + } + + @Test + public void hasInternship_internshipWithSameIdentityFieldsInWorkBook_returnsTrue() { + workBook.addInternship(ALICE); + Internship editedAlice = new InternshipBuilder(ALICE).withTags(VALID_TAG_HUSBAND) + .build(); + assertTrue(workBook.hasInternship(editedAlice)); + } + + @Test + public void getInternshipList_modifyList_throwsUnsupportedOperationException() { + assertThrows(UnsupportedOperationException.class, () -> workBook.getInternshipList().remove(0)); + } + + /** + * A stub ReadOnlyWorkBook whose internships list can violate interface constraints. + */ + private static class WorkBookStub implements ReadOnlyWorkBook { + private final ObservableList internships = FXCollections.observableArrayList(); + + WorkBookStub(Collection internships) { + this.internships.setAll(internships); + } + + @Override + public ObservableList getInternshipList() { + return internships; + } + } + +} diff --git a/src/test/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicateTest.java b/src/test/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicateTest.java new file mode 100644 index 00000000000..9af1a081bd5 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicateTest.java @@ -0,0 +1,74 @@ +package seedu.workbook.model.internship; + +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 seedu.workbook.testutil.InternshipBuilder; + +public class CompanyContainsKeywordsPredicateTest { + + @Test + public void equals() { + List firstPredicateKeywordList = Collections.singletonList("first"); + List secondPredicateKeywordList = Arrays.asList("first", "second"); + + CompanyContainsKeywordsPredicate firstPredicate = new CompanyContainsKeywordsPredicate( + firstPredicateKeywordList); + CompanyContainsKeywordsPredicate secondPredicate = new CompanyContainsKeywordsPredicate( + secondPredicateKeywordList); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + CompanyContainsKeywordsPredicate firstPredicateCopy = new CompanyContainsKeywordsPredicate( + firstPredicateKeywordList); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different internship -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_companyContainsKeywords_returnsTrue() { + // One keyword + CompanyContainsKeywordsPredicate predicate = new CompanyContainsKeywordsPredicate( + Collections.singletonList("Jane")); + assertTrue(predicate.test(new InternshipBuilder().withCompany("Jane Street").build())); + + // Multiple keywords + predicate = new CompanyContainsKeywordsPredicate(Arrays.asList("Jane", "Street")); + assertTrue(predicate.test(new InternshipBuilder().withCompany("Jane Street").build())); + + + // Mixed-case keywords + predicate = new CompanyContainsKeywordsPredicate(Arrays.asList("jAnE", "sTreeT")); + assertTrue(predicate.test(new InternshipBuilder().withCompany("Jane Street").build())); + } + + @Test + public void test_companyDoesNotContainKeywords_returnsFalse() { + + + // Non-matching keyword + CompanyContainsKeywordsPredicate predicate = new CompanyContainsKeywordsPredicate(Arrays.asList("Fairprice")); + assertFalse(predicate.test(new InternshipBuilder().withCompany("Jane Street").build())); + + // Keywords match phone, email and address, but does not match company + predicate = new CompanyContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com")); + assertFalse(predicate.test(new InternshipBuilder().withCompany("Meta") + .withEmail("alice@email.com").build())); + } +} diff --git a/src/test/java/seedu/workbook/model/internship/CompanyTest.java b/src/test/java/seedu/workbook/model/internship/CompanyTest.java new file mode 100644 index 00000000000..7b2354d3003 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/CompanyTest.java @@ -0,0 +1,40 @@ +package seedu.workbook.model.internship; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class CompanyTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new Company(null)); + } + + @Test + public void constructor_invalidName_throwsIllegalArgumentException() { + String invalidName = ""; + assertThrows(IllegalArgumentException.class, () -> new Company(invalidName)); + } + + @Test + public void isValidName() { + // null name + assertThrows(NullPointerException.class, () -> Company.isValidCompany(null)); + + // invalid name + assertFalse(Company.isValidCompany("")); // empty string + assertFalse(Company.isValidCompany(" ")); // spaces only + assertFalse(Company.isValidCompany("^")); // only non-alphanumeric characters + assertFalse(Company.isValidCompany("meta*")); // contains non-alphanumeric characters + + // valid name + assertTrue(Company.isValidCompany("Meta")); // alphabets only + assertTrue(Company.isValidCompany("12345")); // numbers only + assertTrue(Company.isValidCompany("2Sigma")); // alphanumeric characters + assertTrue(Company.isValidCompany("Capital Tan")); // with capital letters + assertTrue(Company.isValidCompany("David Roger Jackson Ray Jr 2nd Nice Company Name")); // long names + } +} diff --git a/src/test/java/seedu/workbook/model/internship/DateTimeTest.java b/src/test/java/seedu/workbook/model/internship/DateTimeTest.java new file mode 100644 index 00000000000..2439cfe2599 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/DateTimeTest.java @@ -0,0 +1,45 @@ +package seedu.workbook.model.internship; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class DateTimeTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new DateTime(null)); + } + @Test + public void isValidDateTime() { + // null DateTime + assertThrows(NullPointerException.class, () -> DateTime.isValidDateTime(null)); + + // blank DateTime + assertFalse(DateTime.isValidDateTime(" ")); // spaces only + + // missing parts to DateTime input + assertFalse(DateTime.isValidDateTime("20-Nov-2022")); // missing time + assertFalse(DateTime.isValidDateTime("20 Nov 2022")); // missing hyphen + assertFalse(DateTime.isValidDateTime("18:00")); // no date provided only time + + // invalid parts + assertFalse(DateTime.isValidDateTime("20 18:00")); // missing full date + assertFalse(DateTime.isValidDateTime("20-Oct-2022 18-00")); // hyphen when putting in time + assertFalse(DateTime.isValidDateTime("20Oct2022 18:00")); // missing hyphens in the date + assertFalse(DateTime.isValidDateTime("20-Ja-2022 17:00")); // only two letters in month + assertFalse(DateTime.isValidDateTime("20--Oct-2022 19:00")); // double '-' symbol + assertFalse(DateTime.isValidDateTime("20--Oct-2022-19:00")); // '-' symbol used in the wrong part + assertFalse(DateTime.isValidDateTime("-20-Oct-2022 19:00")); // date starts with a hyphen + assertFalse(DateTime.isValidDateTime("-20-Oct-2022 19:00-")); // DateTime ends with a hyphen + assertFalse(DateTime.isValidDateTime("20:Oct:2022 19:00")); // Date uses ':' as separator instead of '-' + assertFalse(DateTime.isValidDateTime("2-Nov-20 19:00")); // year part of the date only has two chars + + + // valid email + assertTrue(DateTime.isValidDateTime("02-Feb-2022 18:00")); // follows the correct dd-mmm-yyyy hh:mm format + } +} + diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/seedu/workbook/model/internship/EmailTest.java similarity index 90% rename from src/test/java/seedu/address/model/person/EmailTest.java rename to src/test/java/seedu/workbook/model/internship/EmailTest.java index bbcc6c8c98e..bb62dca39bd 100644 --- a/src/test/java/seedu/address/model/person/EmailTest.java +++ b/src/test/java/seedu/workbook/model/internship/EmailTest.java @@ -1,8 +1,8 @@ -package seedu.address.model.person; +package seedu.workbook.model.internship; 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 seedu.workbook.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -13,11 +13,6 @@ public void constructor_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> new Email(null)); } - @Test - public void constructor_invalidEmail_throwsIllegalArgumentException() { - String invalidEmail = ""; - assertThrows(IllegalArgumentException.class, () -> new Email(invalidEmail)); - } @Test public void isValidEmail() { @@ -25,7 +20,6 @@ public void isValidEmail() { assertThrows(NullPointerException.class, () -> Email.isValidEmail(null)); // blank email - assertFalse(Email.isValidEmail("")); // empty string assertFalse(Email.isValidEmail(" ")); // spaces only // missing parts diff --git a/src/test/java/seedu/workbook/model/internship/InternshipTest.java b/src/test/java/seedu/workbook/model/internship/InternshipTest.java new file mode 100644 index 00000000000..ec88742643e --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/InternshipTest.java @@ -0,0 +1,107 @@ +package seedu.workbook.model.internship; + +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.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_DATETIME_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_ROLE_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_STAGE_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.ALICE; +import static seedu.workbook.testutil.TypicalInternships.BOB; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.testutil.InternshipBuilder; + +public class InternshipTest { + + @Test + public void asObservableList_modifyList_throwsUnsupportedOperationException() { + Internship internship = new InternshipBuilder().build(); + assertThrows(UnsupportedOperationException.class, () -> internship.getTags().remove(0)); + } + + @Test + public void isSameInternship() { + // same object -> returns true + assertTrue(ALICE.isSameInternship(ALICE)); + + // null -> returns false + assertFalse(ALICE.isSameInternship(null)); + + // different role same stage, returns false + Internship editedAlice = new InternshipBuilder(ALICE).withRole(VALID_ROLE_BOB).build(); + assertFalse(ALICE.isSameInternship(editedAlice)); + + // different company same stage, returns false + Internship editedAliceCompanyOnly = new InternshipBuilder(ALICE).withCompany(VALID_COMPANY_BOB).build(); + assertFalse(ALICE.isSameInternship(editedAliceCompanyOnly)); + + // same company and role, different stage -> returns true as company and role are defining factors of + // the same internship application + Internship editedAliceCompanyAndRole = new InternshipBuilder(ALICE).withStage(VALID_STAGE_BOB).build(); + assertTrue(ALICE.isSameInternship(editedAliceCompanyAndRole)); + + // company differs in case, all other attributes same -> returns true + Internship editedBob = new InternshipBuilder(BOB).withCompany(VALID_COMPANY_BOB.toLowerCase()).build(); + assertTrue(BOB.isSameInternship(editedBob)); + + // company has trailing spaces, all other attributes same -> returns false + String companyWithTrailingSpaces = VALID_COMPANY_BOB + " "; + editedBob = new InternshipBuilder(BOB).withCompany(companyWithTrailingSpaces).build(); + assertFalse(BOB.isSameInternship(editedBob)); + } + + @Test + public void equals() { + // same values -> returns true + Internship aliceCopy = new InternshipBuilder(ALICE).build(); + assertTrue(ALICE.equals(aliceCopy)); + + // same object -> returns true + assertTrue(ALICE.equals(ALICE)); + + // null -> returns false + assertFalse(ALICE.equals(null)); + + // different type -> returns false + assertFalse(ALICE.equals(5)); + + // different internship -> returns false + assertFalse(ALICE.equals(BOB)); + + // different company -> returns false + Internship editedAlice = new InternshipBuilder(ALICE).withCompany(VALID_COMPANY_BOB).build(); + assertFalse(ALICE.equals(editedAlice)); + + + // different email -> returns false + editedAlice = new InternshipBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build(); + assertFalse(ALICE.equals(editedAlice)); + + // different stage -> returns false + editedAlice = new InternshipBuilder(ALICE).withStage(VALID_STAGE_BOB).build(); + assertFalse(ALICE.equals(editedAlice)); + + // different role -> returns false + editedAlice = new InternshipBuilder(ALICE).withRole(VALID_ROLE_BOB).build(); + assertFalse(ALICE.equals(editedAlice)); + + // different datetime -> returns false + editedAlice = new InternshipBuilder(ALICE).withDateTime(VALID_DATETIME_BOB).build(); + assertFalse(ALICE.equals(editedAlice)); + + // different tags -> returns false + editedAlice = new InternshipBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build(); + assertFalse(ALICE.equals(editedAlice)); + } + + @Test + public void hashCodeTest() { + assertEquals(new InternshipBuilder(ALICE).build().hashCode(), new InternshipBuilder(ALICE).build().hashCode()); + } +} diff --git a/src/test/java/seedu/workbook/model/internship/RoleContainsKeywordPredicateTest.java b/src/test/java/seedu/workbook/model/internship/RoleContainsKeywordPredicateTest.java new file mode 100644 index 00000000000..ca8c1596d30 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/RoleContainsKeywordPredicateTest.java @@ -0,0 +1,72 @@ +package seedu.workbook.model.internship; + +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 seedu.workbook.testutil.InternshipBuilder; + +public class RoleContainsKeywordPredicateTest { + + @Test + public void equals() { + List firstPredicateKeywordList = Collections.singletonList("first"); + List secondPredicateKeywordList = Arrays.asList("first", "second"); + + RoleContainsKeywordsPredicate firstPredicate = new RoleContainsKeywordsPredicate( + firstPredicateKeywordList); + RoleContainsKeywordsPredicate secondPredicate = new RoleContainsKeywordsPredicate( + secondPredicateKeywordList); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + RoleContainsKeywordsPredicate firstPredicateCopy = new RoleContainsKeywordsPredicate( + firstPredicateKeywordList); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different internship -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_roleContainsKeywords_returnsTrue() { + // One keyword + RoleContainsKeywordsPredicate predicate = new RoleContainsKeywordsPredicate( + Collections.singletonList("Software")); + assertTrue(predicate.test(new InternshipBuilder().withRole("Software Engineer").build())); + + // Multiple keywords + predicate = new RoleContainsKeywordsPredicate(Arrays.asList("Software", "Engineer")); + assertTrue(predicate.test(new InternshipBuilder().withRole("Software Engineer").build())); + + // Mixed-case keywords + predicate = new RoleContainsKeywordsPredicate(Arrays.asList("sOfTwaRe", "EnGineEr")); + assertTrue(predicate.test(new InternshipBuilder().withRole("Software Engineer").build())); + } + + @Test + public void test_companyDoesNotContainKeywords_returnsFalse() { + + // Non-matching keyword + RoleContainsKeywordsPredicate predicate = new RoleContainsKeywordsPredicate(Arrays.asList("Backend")); + assertFalse(predicate.test(new InternshipBuilder().withRole("Software Engineer").build())); + + // Keywords match phone and email but does not match role + predicate = new RoleContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com")); + assertFalse(predicate.test(new InternshipBuilder().withRole("Software Engineer") + .withEmail("alice@email.com").build())); + } +} diff --git a/src/test/java/seedu/workbook/model/internship/RoleTest.java b/src/test/java/seedu/workbook/model/internship/RoleTest.java new file mode 100644 index 00000000000..8b2cea9bad8 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/RoleTest.java @@ -0,0 +1,41 @@ +package seedu.workbook.model.internship; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class RoleTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new Role(null)); + } + + @Test + public void constructor_invalidName_throwsIllegalArgumentException() { + String invalidName = ""; + assertThrows(IllegalArgumentException.class, () -> new Role(invalidName)); + } + + @Test + public void isValidName() { + // null name + assertThrows(NullPointerException.class, () -> Role.isValidRole(null)); + + // invalid name + assertFalse(Role.isValidRole("")); // empty string + assertFalse(Role.isValidRole(" ")); // spaces only + assertFalse(Role.isValidRole("^")); // only non-alphanumeric characters + assertFalse(Role.isValidRole("frontend engineer*")); // contains non-alphanumeric characters + + // valid name + assertTrue(Role.isValidRole("Engineer")); // alphabets only + assertTrue(Role.isValidRole("12345")); // numbers only + assertTrue(Role.isValidRole("5th Engineer")); // alphanumeric characters + assertTrue(Role.isValidRole("Backend Developer")); // with capital letters + assertTrue(Role.isValidRole("Backend Developer Software Engineer Quant Trader CEO")); // long names + } + +} diff --git a/src/test/java/seedu/workbook/model/internship/StageContainsKeywordsPredicateTest.java b/src/test/java/seedu/workbook/model/internship/StageContainsKeywordsPredicateTest.java new file mode 100644 index 00000000000..1177716d229 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/StageContainsKeywordsPredicateTest.java @@ -0,0 +1,72 @@ +package seedu.workbook.model.internship; + +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 seedu.workbook.testutil.InternshipBuilder; + +public class StageContainsKeywordsPredicateTest { + + @Test + public void equals() { + List firstPredicateKeywordList = Collections.singletonList("first"); + List secondPredicateKeywordList = Arrays.asList("first", "second"); + + StageContainsKeywordsPredicate firstPredicate = new StageContainsKeywordsPredicate( + firstPredicateKeywordList); + StageContainsKeywordsPredicate secondPredicate = new StageContainsKeywordsPredicate( + secondPredicateKeywordList); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + StageContainsKeywordsPredicate firstPredicateCopy = new StageContainsKeywordsPredicate( + firstPredicateKeywordList); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different internship -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_stageContainsKeywords_returnsTrue() { + // One keyword + StageContainsKeywordsPredicate predicate = new StageContainsKeywordsPredicate( + Collections.singletonList("Interview")); + assertTrue(predicate.test(new InternshipBuilder().withCompany("Technical Interview").build())); + + // Multiple keywords + predicate = new StageContainsKeywordsPredicate(Arrays.asList("Technical", "Interview")); + assertTrue(predicate.test(new InternshipBuilder().withStage("Technical Interview").build())); + + // Mixed-case keywords + predicate = new StageContainsKeywordsPredicate(Arrays.asList("tEcHnicAl", "inTeRviEw")); + assertTrue(predicate.test(new InternshipBuilder().withStage("Technical Interview").build())); + } + + @Test + public void test_companyDoesNotContainKeywords_returnsFalse() { + + // Non-matching keyword + StageContainsKeywordsPredicate predicate = new StageContainsKeywordsPredicate(Arrays.asList("Assessment")); + assertFalse(predicate.test(new InternshipBuilder().withStage("Phone Interview").build())); + + // Keywords match phone, email and address, but does not match company + predicate = new StageContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com")); + assertFalse(predicate.test(new InternshipBuilder().withStage("Interview") + .withEmail("alice@email.com").build())); + } +} diff --git a/src/test/java/seedu/workbook/model/internship/StageTest.java b/src/test/java/seedu/workbook/model/internship/StageTest.java new file mode 100644 index 00000000000..2e1a92928bb --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/StageTest.java @@ -0,0 +1,40 @@ +package seedu.workbook.model.internship; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class StageTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new Stage(null)); + } + + @Test + public void constructor_invalidName_throwsIllegalArgumentException() { + String invalidName = ""; + assertThrows(IllegalArgumentException.class, () -> new Stage(invalidName)); + } + + @Test + public void isValidName() { + // null name + assertThrows(NullPointerException.class, () -> Stage.isValidStage(null)); + + // invalid name + assertFalse(Stage.isValidStage("")); // empty string + assertFalse(Stage.isValidStage(" ")); // spaces only + assertFalse(Stage.isValidStage("^")); // only non-alphanumeric characters + assertFalse(Stage.isValidStage("Interview*")); // contains non-alphanumeric characters + + // valid name + assertTrue(Stage.isValidStage("Phone Interview")); // alphabets only + assertTrue(Stage.isValidStage("12345")); // numbers only + assertTrue(Stage.isValidStage("3rd Technical Interview")); // alphanumeric characters + assertTrue(Stage.isValidStage("BEHAVIOURAL INTERVIEW")); // with capital letters + assertTrue(Stage.isValidStage("Coding with the CTO of the company intense interview")); // long names + } +} diff --git a/src/test/java/seedu/workbook/model/internship/UniqueInternshipListTest.java b/src/test/java/seedu/workbook/model/internship/UniqueInternshipListTest.java new file mode 100644 index 00000000000..cf59bad2753 --- /dev/null +++ b/src/test/java/seedu/workbook/model/internship/UniqueInternshipListTest.java @@ -0,0 +1,183 @@ +package seedu.workbook.model.internship; + +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.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.ALICE; +import static seedu.workbook.testutil.TypicalInternships.BOB; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.model.internship.exceptions.DuplicateInternshipException; +import seedu.workbook.model.internship.exceptions.InternshipNotFoundException; +import seedu.workbook.testutil.InternshipBuilder; + +public class UniqueInternshipListTest { + + private final UniqueInternshipList uniqueInternshipList = new UniqueInternshipList(); + + @Test + public void contains_nullInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueInternshipList.contains(null)); + } + + @Test + public void contains_internshipNotInList_returnsFalse() { + assertFalse(uniqueInternshipList.contains(ALICE)); + } + + @Test + public void contains_internshipInList_returnsTrue() { + uniqueInternshipList.add(ALICE); + assertTrue(uniqueInternshipList.contains(ALICE)); + } + + @Test + public void contains_internshipWithSameIdentityFieldsInList_returnsTrue() { + uniqueInternshipList.add(ALICE); + Internship editedAlice = new InternshipBuilder(ALICE).withTags(VALID_TAG_HUSBAND) + .build(); + assertTrue(uniqueInternshipList.contains(editedAlice)); + } + + @Test + public void add_nullInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueInternshipList.add(null)); + } + + @Test + public void add_duplicateInternship_throwsDuplicateInternshipException() { + uniqueInternshipList.add(ALICE); + assertThrows(DuplicateInternshipException.class, () -> uniqueInternshipList.add(ALICE)); + } + + @Test + public void setInternship_nullTargetInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueInternshipList.setInternship(null, ALICE)); + } + + @Test + public void setInternship_nullEditedInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueInternshipList.setInternship(ALICE, null)); + } + + @Test + public void setInternship_targetInternshipNotInList_throwsInternshipNotFoundException() { + assertThrows(InternshipNotFoundException.class, () -> uniqueInternshipList.setInternship(ALICE, ALICE)); + } + + @Test + public void setInternship_editedInternshipIsSameInternship_success() { + uniqueInternshipList.add(ALICE); + uniqueInternshipList.setInternship(ALICE, ALICE); + UniqueInternshipList expectedUniqueInternshipList = new UniqueInternshipList(); + expectedUniqueInternshipList.add(ALICE); + assertEquals(expectedUniqueInternshipList, uniqueInternshipList); + } + + @Test + public void setInternship_editedInternshipHasSameIdentity_success() { + uniqueInternshipList.add(ALICE); + Internship editedAlice = new InternshipBuilder(ALICE).withTags(VALID_TAG_HUSBAND) + .build(); + uniqueInternshipList.setInternship(ALICE, editedAlice); + UniqueInternshipList expectedUniqueInternshipList = new UniqueInternshipList(); + expectedUniqueInternshipList.add(editedAlice); + assertEquals(expectedUniqueInternshipList, uniqueInternshipList); + } + + @Test + public void setInternship_editedInternshipHasDifferentIdentity_success() { + uniqueInternshipList.add(ALICE); + uniqueInternshipList.setInternship(ALICE, BOB); + UniqueInternshipList expectedUniqueInternshipList = new UniqueInternshipList(); + expectedUniqueInternshipList.add(BOB); + assertEquals(expectedUniqueInternshipList, uniqueInternshipList); + } + + @Test + public void setInternship_editedInternshipHasNonUniqueIdentity_throwsDuplicateInternshipException() { + uniqueInternshipList.add(ALICE); + uniqueInternshipList.add(BOB); + assertThrows(DuplicateInternshipException.class, () -> uniqueInternshipList.setInternship(ALICE, BOB)); + } + + @Test + public void remove_nullInternship_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueInternshipList.remove(null)); + } + + @Test + public void remove_internshipDoesNotExist_throwsInternshipNotFoundException() { + assertThrows(InternshipNotFoundException.class, () -> uniqueInternshipList.remove(ALICE)); + } + + @Test + public void remove_existingInternship_removesInternship() { + uniqueInternshipList.add(ALICE); + uniqueInternshipList.remove(ALICE); + UniqueInternshipList expectedUniqueInternshipList = new UniqueInternshipList(); + assertEquals(expectedUniqueInternshipList, uniqueInternshipList); + } + + // CHECKSTYLE.OFF: SeparatorWrap + @Test + public void setInternships_nullUniqueInternshipList_throwsNullPointerException() { + assertThrows( + NullPointerException.class, + () -> uniqueInternshipList.setInternships((UniqueInternshipList) null) + ); + } + // CHECKSTYLE.ON: SeparatorWrap + + @Test + public void setInternships_uniqueInternshipList_replacesOwnListWithProvidedUniqueInternshipList() { + uniqueInternshipList.add(ALICE); + UniqueInternshipList expectedUniqueInternshipList = new UniqueInternshipList(); + expectedUniqueInternshipList.add(BOB); + uniqueInternshipList.setInternships(expectedUniqueInternshipList); + assertEquals(expectedUniqueInternshipList, uniqueInternshipList); + } + + @Test + public void setInternships_nullList_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueInternshipList.setInternships((List) null)); + } + + @Test + public void setInternships_list_replacesOwnListWithProvidedList() { + uniqueInternshipList.add(ALICE); + List internshipList = Collections.singletonList(BOB); + uniqueInternshipList.setInternships(internshipList); + UniqueInternshipList expectedUniqueInternshipList = new UniqueInternshipList(); + expectedUniqueInternshipList.add(BOB); + assertEquals(expectedUniqueInternshipList, uniqueInternshipList); + } + + // CHECKSTYLE.OFF: SeparatorWrap + @Test + public void setInternships_listWithDuplicateInternships_throwsDuplicateInternshipException() { + List listWithDuplicateInternships = Arrays.asList(ALICE, ALICE); + assertThrows( + DuplicateInternshipException.class, + () -> uniqueInternshipList.setInternships(listWithDuplicateInternships) + ); + } + // CHECKSTYLE.ON: SeparatorWrap + + // CHECKSTYLE.OFF: SeparatorWrap + @Test + public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() { + assertThrows( + UnsupportedOperationException.class, + () -> uniqueInternshipList.asUnmodifiableObservableList().remove(0) + ); + } + // CHECKSTYLE.ON: SeparatorWrap +} diff --git a/src/test/java/seedu/workbook/model/tag/TagTest.java b/src/test/java/seedu/workbook/model/tag/TagTest.java new file mode 100644 index 00000000000..f4a0eb4d431 --- /dev/null +++ b/src/test/java/seedu/workbook/model/tag/TagTest.java @@ -0,0 +1,34 @@ +package seedu.workbook.model.tag; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.workbook.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class TagTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new Tag(null)); + } + + @Test + public void isValidTagName() { + // null tag name + assertThrows(NullPointerException.class, () -> Tag.isValidTagName(null)); + } + + @Test + public void equals() { + Tag tagOne = new Tag("Same name"); + Tag tagTwo = new Tag("Same name"); + + // Compare two tag objects of same tagName + assertTrue(tagOne.equals(tagTwo)); + + // Compare two same tag objects + assertTrue(tagOne.equals(tagOne)); + + } + +} diff --git a/src/test/java/seedu/workbook/storage/JsonAdaptedInternshipTest.java b/src/test/java/seedu/workbook/storage/JsonAdaptedInternshipTest.java new file mode 100644 index 00000000000..7fb55b8bbc5 --- /dev/null +++ b/src/test/java/seedu/workbook/storage/JsonAdaptedInternshipTest.java @@ -0,0 +1,117 @@ +package seedu.workbook.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.workbook.storage.JsonAdaptedInternship.MISSING_FIELD_MESSAGE_FORMAT; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.BENSON; + +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; + +public class JsonAdaptedInternshipTest { + private static final String INVALID_COMPANY = "R@chel"; + private static final String INVALID_ROLE = "R@chel"; + private static final String INVALID_STAGE = "H@ Interview"; + private static final String INVALID_DATETIME = "12-02-2022 12:00"; + private static final String INVALID_EMAIL = "example.com"; + + private static final String VALID_COMPANY = BENSON.getCompany().toString(); + private static final String VALID_ROLE = BENSON.getRole().toString(); + private static final String VALID_EMAIL = BENSON.getEmail().toString(); + private static final String VALID_STAGE = BENSON.getStage().toString(); + private static final String VALID_DATETIME = BENSON.getDateTime().toString(); + private static final List VALID_LANGUAGE_TAGS = BENSON.getLanguageTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList()); + private static final List VALID_TAGS = BENSON.getTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList()); + + @Test + public void toModelType_validInternshipDetails_returnsInternship() throws Exception { + JsonAdaptedInternship internship = new JsonAdaptedInternship(BENSON); + assertEquals(BENSON, internship.toModelType()); + } + + @Test + public void toModelType_invalidCompany_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(INVALID_COMPANY, VALID_ROLE, + VALID_EMAIL, VALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = Company.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_nullCompany_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(null, VALID_ROLE, + VALID_EMAIL, VALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Company.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_invalidRole_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, INVALID_ROLE, + VALID_EMAIL, VALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = Role.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_nullRole_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, null, VALID_EMAIL, + VALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Role.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_invalidEmail_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, VALID_ROLE, + INVALID_EMAIL, VALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = Email.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_nullEmail_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, VALID_ROLE, null, + VALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_invalidStage_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, VALID_ROLE, + VALID_EMAIL, null, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Stage.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_nullStage_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, VALID_ROLE, + VALID_EMAIL, INVALID_STAGE, VALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = Stage.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + + @Test + public void toModelType_invalidDateTime_throwsIllegalValueException() { + JsonAdaptedInternship internship = new JsonAdaptedInternship(VALID_COMPANY, VALID_ROLE, + VALID_EMAIL, VALID_STAGE, INVALID_DATETIME, VALID_LANGUAGE_TAGS, VALID_TAGS); + String expectedMessage = DateTime.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, internship::toModelType); + } + +} diff --git a/src/test/java/seedu/workbook/storage/JsonSerializableWorkBookTest.java b/src/test/java/seedu/workbook/storage/JsonSerializableWorkBookTest.java new file mode 100644 index 00000000000..5eb051c08f1 --- /dev/null +++ b/src/test/java/seedu/workbook/storage/JsonSerializableWorkBookTest.java @@ -0,0 +1,47 @@ +package seedu.workbook.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.workbook.testutil.Assert.assertThrows; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; + +import seedu.workbook.commons.exceptions.IllegalValueException; +import seedu.workbook.commons.util.JsonUtil; +import seedu.workbook.model.WorkBook; +import seedu.workbook.testutil.TypicalInternships; + +public class JsonSerializableWorkBookTest { + + private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableWorkBookTest"); + private static final Path TYPICAL_INTERNSHIPS_FILE = TEST_DATA_FOLDER.resolve("typicalInternshipsWorkBook.json"); + private static final Path INVALID_INTERNSHIP_FILE = TEST_DATA_FOLDER.resolve("invalidInternshipWorkBook.json"); + private static final Path DUPLICATE_INTERNSHIP_FILE = TEST_DATA_FOLDER.resolve("duplicateInternshipWorkBook.json"); + + @Test + public void toModelType_typicalInternshipsFile_success() throws Exception { + JsonSerializableWorkBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_INTERNSHIPS_FILE, + JsonSerializableWorkBook.class).get(); + WorkBook workBookFromFile = dataFromFile.toModelType(); + WorkBook typicalInternshipsWorkBook = TypicalInternships.getTypicalWorkBook(); + assertEquals(workBookFromFile, typicalInternshipsWorkBook); + } + + @Test + public void toModelType_invalidInternshipFile_throwsIllegalValueException() throws Exception { + JsonSerializableWorkBook dataFromFile = JsonUtil.readJsonFile(INVALID_INTERNSHIP_FILE, + JsonSerializableWorkBook.class).get(); + assertThrows(IllegalValueException.class, dataFromFile::toModelType); + } + + @Test + public void toModelType_duplicateInternships_throwsIllegalValueException() throws Exception { + JsonSerializableWorkBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_INTERNSHIP_FILE, + JsonSerializableWorkBook.class).get(); + assertThrows(IllegalValueException.class, JsonSerializableWorkBook.MESSAGE_DUPLICATE_INTERNSHIP, + dataFromFile::toModelType); + } + +} diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/workbook/storage/JsonUserPrefsStorageTest.java similarity index 93% rename from src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java rename to src/test/java/seedu/workbook/storage/JsonUserPrefsStorageTest.java index 16f33f4a6bb..6a6f140a2c7 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/seedu/workbook/storage/JsonUserPrefsStorageTest.java @@ -1,8 +1,8 @@ -package seedu.address.storage; +package seedu.workbook.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.workbook.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 seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.model.UserPrefs; public class JsonUserPrefsStorageTest { @@ -73,7 +73,7 @@ public void readUserPrefs_extraValuesInFile_extraValuesIgnored() throws DataConv private UserPrefs getTypicalUserPrefs() { UserPrefs userPrefs = new UserPrefs(); userPrefs.setGuiSettings(new GuiSettings(1000, 500, 300, 100)); - userPrefs.setAddressBookFilePath(Paths.get("addressbook.json")); + userPrefs.setWorkBookFilePath(Paths.get("workbook.json")); return userPrefs; } diff --git a/src/test/java/seedu/workbook/storage/JsonWorkBookStorageTest.java b/src/test/java/seedu/workbook/storage/JsonWorkBookStorageTest.java new file mode 100644 index 00000000000..8ddd0cdfd92 --- /dev/null +++ b/src/test/java/seedu/workbook/storage/JsonWorkBookStorageTest.java @@ -0,0 +1,110 @@ +package seedu.workbook.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static seedu.workbook.testutil.Assert.assertThrows; +import static seedu.workbook.testutil.TypicalInternships.ALICE; +import static seedu.workbook.testutil.TypicalInternships.HOON; +import static seedu.workbook.testutil.TypicalInternships.IDA; +import static seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import seedu.workbook.commons.exceptions.DataConversionException; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.WorkBook; + +public class JsonWorkBookStorageTest { + private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonWorkBookStorageTest"); + + @TempDir + public Path testFolder; + + @Test + public void readWorkBook_nullFilePath_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> readWorkBook(null)); + } + + private java.util.Optional readWorkBook(String filePath) throws Exception { + return new JsonWorkBookStorage(Paths.get(filePath)).readWorkBook(addToTestDataPathIfNotNull(filePath)); + } + + private Path addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) { + return prefsFileInTestDataFolder != null + ? TEST_DATA_FOLDER.resolve(prefsFileInTestDataFolder) + : null; + } + + @Test + public void read_missingFile_emptyResult() throws Exception { + assertFalse(readWorkBook("NonExistentFile.json").isPresent()); + } + + @Test + public void read_notJsonFormat_exceptionThrown() { + assertThrows(DataConversionException.class, () -> readWorkBook("notJsonFormatWorkBook.json")); + } + + @Test + public void readWorkBook_invalidInternshipWorkBook_throwDataConversionException() { + assertThrows(DataConversionException.class, () -> readWorkBook("invalidInternshipWorkBook.json")); + } + + @Test + public void readWorkBook_invalidWorkBook_throwDataConversionException() { + assertThrows(DataConversionException.class, () -> readWorkBook("invalidAndValidInternshipWorkBook.json")); + } + + @Test + public void readAndSaveWorkBook_allInOrder_success() throws Exception { + Path filePath = testFolder.resolve("TempWorkBook.json"); + WorkBook original = getTypicalWorkBook(); + JsonWorkBookStorage jsonWorkBookStorage = new JsonWorkBookStorage(filePath); + + // Save in new file and read back + jsonWorkBookStorage.saveWorkBook(original, filePath); + ReadOnlyWorkBook readBack = jsonWorkBookStorage.readWorkBook(filePath).get(); + assertEquals(original, new WorkBook(readBack)); + + // Modify data, overwrite exiting file, and read back + original.addInternship(HOON); + original.removeInternship(ALICE); + jsonWorkBookStorage.saveWorkBook(original, filePath); + readBack = jsonWorkBookStorage.readWorkBook(filePath).get(); + assertEquals(original, new WorkBook(readBack)); + + // Save and read without specifying file path + original.addInternship(IDA); + jsonWorkBookStorage.saveWorkBook(original); // file path not specified + readBack = jsonWorkBookStorage.readWorkBook().get(); // file path not specified + assertEquals(original, new WorkBook(readBack)); + + } + + @Test + public void saveWorkBook_nullWorkBook_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> saveWorkBook(null, "SomeFile.json")); + } + + /** + * Saves {@code workBook} at the specified {@code filePath}. + */ + private void saveWorkBook(ReadOnlyWorkBook workBook, String filePath) { + try { + new JsonWorkBookStorage(Paths.get(filePath)) + .saveWorkBook(workBook, addToTestDataPathIfNotNull(filePath)); + } catch (IOException ioe) { + throw new AssertionError("There should not be an error writing to the file.", ioe); + } + } + + @Test + public void saveWorkBook_nullFilePath_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> saveWorkBook(new WorkBook(), null)); + } +} diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/workbook/storage/StorageManagerTest.java similarity index 60% rename from src/test/java/seedu/address/storage/StorageManagerTest.java rename to src/test/java/seedu/workbook/storage/StorageManagerTest.java index 99a16548970..2ba127e5993 100644 --- a/src/test/java/seedu/address/storage/StorageManagerTest.java +++ b/src/test/java/seedu/workbook/storage/StorageManagerTest.java @@ -1,8 +1,8 @@ -package seedu.address.storage; +package seedu.workbook.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 seedu.workbook.testutil.TypicalInternships.getTypicalWorkBook; 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 seedu.workbook.commons.core.GuiSettings; +import seedu.workbook.model.ReadOnlyWorkBook; +import seedu.workbook.model.UserPrefs; +import seedu.workbook.model.WorkBook; public class StorageManagerTest { @@ -24,9 +24,9 @@ public class StorageManagerTest { @BeforeEach public void setUp() { - JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(getTempFilePath("ab")); + JsonWorkBookStorage workBookStorage = new JsonWorkBookStorage(getTempFilePath("ab")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(getTempFilePath("prefs")); - storageManager = new StorageManager(addressBookStorage, userPrefsStorage); + storageManager = new StorageManager(workBookStorage, userPrefsStorage); } private Path getTempFilePath(String fileName) { @@ -48,21 +48,21 @@ public void prefsReadSave() throws Exception { } @Test - public void addressBookReadSave() throws Exception { + public void workBookReadSave() throws Exception { /* * Note: This is an integration test that verifies the StorageManager is properly wired to the - * {@link JsonAddressBookStorage} class. - * More extensive testing of UserPref saving/reading is done in {@link JsonAddressBookStorageTest} class. + * {@link JsonWorkBookStorage} class. + * More extensive testing of UserPref saving/reading is done in {@link JsonWorkBookStorageTest} class. */ - AddressBook original = getTypicalAddressBook(); - storageManager.saveAddressBook(original); - ReadOnlyAddressBook retrieved = storageManager.readAddressBook().get(); - assertEquals(original, new AddressBook(retrieved)); + WorkBook original = getTypicalWorkBook(); + storageManager.saveWorkBook(original); + ReadOnlyWorkBook retrieved = storageManager.readWorkBook().get(); + assertEquals(original, new WorkBook(retrieved)); } @Test - public void getAddressBookFilePath() { - assertNotNull(storageManager.getAddressBookFilePath()); + public void getWorkBookFilePath() { + assertNotNull(storageManager.getWorkBookFilePath()); } } diff --git a/src/test/java/seedu/address/testutil/Assert.java b/src/test/java/seedu/workbook/testutil/Assert.java similarity index 97% rename from src/test/java/seedu/address/testutil/Assert.java rename to src/test/java/seedu/workbook/testutil/Assert.java index 9863093bd6e..fc5d33865cc 100644 --- a/src/test/java/seedu/address/testutil/Assert.java +++ b/src/test/java/seedu/workbook/testutil/Assert.java @@ -1,4 +1,4 @@ -package seedu.address.testutil; +package seedu.workbook.testutil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.function.Executable; diff --git a/src/test/java/seedu/workbook/testutil/EditInternshipDescriptorBuilder.java b/src/test/java/seedu/workbook/testutil/EditInternshipDescriptorBuilder.java new file mode 100644 index 00000000000..a86c30b793c --- /dev/null +++ b/src/test/java/seedu/workbook/testutil/EditInternshipDescriptorBuilder.java @@ -0,0 +1,107 @@ +package seedu.workbook.testutil; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.tag.Tag; + +/** + * A utility class to help with building EditInternshipDescriptor objects. + */ +public class EditInternshipDescriptorBuilder { + + private EditInternshipDescriptor descriptor; + + public EditInternshipDescriptorBuilder() { + descriptor = new EditInternshipDescriptor(); + } + + public EditInternshipDescriptorBuilder(EditInternshipDescriptor descriptor) { + this.descriptor = new EditInternshipDescriptor(descriptor); + } + + /** + * Returns an {@code EditInternshipDescriptor} with fields containing {@code internship}'s details + */ + public EditInternshipDescriptorBuilder(Internship internship) { + descriptor = new EditInternshipDescriptor(); + descriptor.setCompany(internship.getCompany()); + descriptor.setRole(internship.getRole()); + descriptor.setEmail(internship.getEmail()); + descriptor.setStage(internship.getStage()); + descriptor.setDate(internship.getDateTime()); + descriptor.setLanguageTags(internship.getLanguageTags()); + descriptor.setTags(internship.getTags()); + } + + /** + * Sets the {@code Company} of the {@code EditInternshipDescriptor} that we are building. + */ + public EditInternshipDescriptorBuilder withCompany(String name) { + descriptor.setCompany(new Company(name)); + return this; + } + + /** + * Sets the {@code Role} of the {@code EditInternshipDescriptor} that we are building. + */ + public EditInternshipDescriptorBuilder withRole(String role) { + descriptor.setRole(new Role(role)); + return this; + } + + /** + * Sets the {@code Email} of the {@code EditInternshipDescriptor} that we are building. + */ + public EditInternshipDescriptorBuilder withEmail(String email) { + descriptor.setEmail(new Email(email)); + return this; + } + + /** + * Sets the {@code Stage} of the {@code EditInternshipDescriptor} that we are building. + */ + public EditInternshipDescriptorBuilder withStage(String stage) { + descriptor.setStage(new Stage(stage)); + return this; + } + /** + * Sets the {@code DateTime} of the {@code EditInternshipDescriptor} that we are building. + */ + public EditInternshipDescriptorBuilder withDateTime(String dateTime) { + descriptor.setDate(new DateTime(dateTime)); + return this; + } + + /** + * Parses the {@code languageTags} into a {@code Set} and set it to the {@code EditInternshipDescriptor} + * that we are building. + */ + public EditInternshipDescriptorBuilder withLanguageTags(String... languageTags) { + Set languageTagSet = Stream.of(languageTags).map(Tag::new).collect(Collectors.toSet()); + descriptor.setLanguageTags(languageTagSet); + return this; + } + + /** + * Parses the {@code tags} into a {@code Set} and set it to the {@code EditInternshipDescriptor} + * that we are building. + */ + public EditInternshipDescriptorBuilder withTags(String... tags) { + Set tagSet = Stream.of(tags).map(Tag::new).collect(Collectors.toSet()); + descriptor.setTags(tagSet); + return this; + } + + public EditInternshipDescriptor build() { + return descriptor; + } +} diff --git a/src/test/java/seedu/workbook/testutil/InternshipBuilder.java b/src/test/java/seedu/workbook/testutil/InternshipBuilder.java new file mode 100644 index 00000000000..ce07ab7fbe1 --- /dev/null +++ b/src/test/java/seedu/workbook/testutil/InternshipBuilder.java @@ -0,0 +1,122 @@ +package seedu.workbook.testutil; + +import java.util.HashSet; +import java.util.Set; + +import seedu.workbook.model.internship.Company; +import seedu.workbook.model.internship.DateTime; +import seedu.workbook.model.internship.Email; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.internship.Role; +import seedu.workbook.model.internship.Stage; +import seedu.workbook.model.tag.Tag; +import seedu.workbook.model.util.SampleDataUtil; + +/** + * A utility class to help with building Internship objects. + */ +public class InternshipBuilder { + + public static final String DEFAULT_COMPANY = "Meta"; + public static final String DEFAULT_ROLE = "God Developer"; + public static final String DEFAULT_EMAIL = "amy@gmail.com"; + public static final String DEFAULT_STAGE = "Technical Interview"; + public static final String DEFAULT_DATETIME = ""; + + private Company company; + private Role role; + private Email email; + private Stage stage; + private DateTime dateTime; + private Set languageTags; + private Set tags; + + /** + * Creates a {@code InternshipBuilder} with the default details. + */ + public InternshipBuilder() { + company = new Company(DEFAULT_COMPANY); + role = new Role(DEFAULT_ROLE); + email = new Email(DEFAULT_EMAIL); + stage = new Stage(DEFAULT_STAGE); + dateTime = new DateTime(DEFAULT_DATETIME); + languageTags = new HashSet<>(); + tags = new HashSet<>(); + } + + /** + * Initializes the InternshipBuilder with the data of {@code internshipToCopy}. + */ + public InternshipBuilder(Internship internshipToCopy) { + company = internshipToCopy.getCompany(); + role = internshipToCopy.getRole(); + email = internshipToCopy.getEmail(); + stage = internshipToCopy.getStage(); + dateTime = internshipToCopy.getDateTime(); + languageTags = new HashSet<>(internshipToCopy.getLanguageTags()); + tags = new HashSet<>(internshipToCopy.getTags()); + } + + /** + * Sets the {@code Company} of the {@code Internship} that we are building. + */ + public InternshipBuilder withCompany(String company) { + this.company = new Company(company); + return this; + } + + /** + * Sets the {@code Role} of the {@code Internship} that we are building. + */ + public InternshipBuilder withRole(String role) { + this.role = new Role(role); + return this; + } + + /** + * Parses the {@code languageTags} into a {@code Set} and set it to the + * {@code Internship} that we are building. + */ + public InternshipBuilder withLanguageTags(String... languageTags) { + this.languageTags = SampleDataUtil.getTagSet(languageTags); + return this; + } + + /** + * Parses the {@code tags} into a {@code Set} and set it to the + * {@code Internship} that we are building. + */ + public InternshipBuilder withTags(String... tags) { + this.tags = SampleDataUtil.getTagSet(tags); + return this; + } + + /** + * Sets the {@code Email} of the {@code Internship} that we are building. + */ + public InternshipBuilder withEmail(String email) { + this.email = new Email(email); + return this; + } + + /** + * Sets the {@code Stage} of the {@code Internship} that we are building. + */ + public InternshipBuilder withStage(String stage) { + this.stage = new Stage(stage); + return this; + } + + /** + * Sets the {@code DateTime} of the {@code Internship} that we are building. + */ + public InternshipBuilder withDateTime(String dateTime) { + this.dateTime = new DateTime(dateTime); + return this; + } + + public Internship build() { + return new Internship(company, role, email, stage, dateTime, languageTags, tags); + } + +} diff --git a/src/test/java/seedu/workbook/testutil/InternshipUtil.java b/src/test/java/seedu/workbook/testutil/InternshipUtil.java new file mode 100644 index 00000000000..f7df3932406 --- /dev/null +++ b/src/test/java/seedu/workbook/testutil/InternshipUtil.java @@ -0,0 +1,78 @@ +package seedu.workbook.testutil; + + +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE; +import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.Set; + +import seedu.workbook.logic.commands.AddCommand; +import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor; +import seedu.workbook.model.internship.Internship; +import seedu.workbook.model.tag.Tag; + +/** + * A utility class for Internship. + */ +public class InternshipUtil { + + /** + * Returns an add command string for adding the {@code internship}. + */ + public static String getAddCommand(Internship internship) { + return AddCommand.COMMAND_WORD + " " + getInternshipDetails(internship); + } + + /** + * Returns the part of command string for the given {@code internship}'s details. + */ + public static String getInternshipDetails(Internship internship) { + StringBuilder sb = new StringBuilder(); + sb.append(PREFIX_COMPANY + internship.getCompany().name + " "); + sb.append(PREFIX_ROLE + internship.getRole().value + " "); + sb.append(PREFIX_EMAIL + internship.getEmail().value + " "); + sb.append(PREFIX_STAGE + internship.getStage().value + " "); + sb.append(PREFIX_DATETIME + internship.getDateTime().value + " "); + internship.getLanguageTags().stream().forEach( + s -> sb.append(PREFIX_LANGUAGE_TAG + s.tagName + " ") + ); + internship.getTags().stream().forEach( + s -> sb.append(PREFIX_TAG + s.tagName + " ") + ); + return sb.toString(); + } + + /** + * Returns the part of command string for the given {@code EditInternshipDescriptor}'s details. + */ + public static String getEditInternshipDescriptorDetails(EditInternshipDescriptor descriptor) { + StringBuilder sb = new StringBuilder(); + descriptor.getCompany().ifPresent(company -> sb.append(PREFIX_COMPANY).append(company.name).append(" ")); + descriptor.getRole().ifPresent(role -> sb.append(PREFIX_ROLE).append(role.value).append(" ")); + descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" ")); + descriptor.getStage().ifPresent(stage -> sb.append(PREFIX_STAGE).append(stage.value).append(" ")); + descriptor.getDate().ifPresent(dateTime -> sb.append(PREFIX_DATETIME).append(dateTime.value).append(" ")); + if (descriptor.getLanguageTags().isPresent()) { + Set languageTags = descriptor.getLanguageTags().get(); + if (languageTags.isEmpty()) { + sb.append(PREFIX_LANGUAGE_TAG).append(" "); + } else { + languageTags.forEach(s -> sb.append(PREFIX_LANGUAGE_TAG).append(s.tagName).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/SerializableTestClass.java b/src/test/java/seedu/workbook/testutil/SerializableTestClass.java similarity index 98% rename from src/test/java/seedu/address/testutil/SerializableTestClass.java rename to src/test/java/seedu/workbook/testutil/SerializableTestClass.java index f5a66340489..4671b67cf3a 100644 --- a/src/test/java/seedu/address/testutil/SerializableTestClass.java +++ b/src/test/java/seedu/workbook/testutil/SerializableTestClass.java @@ -1,4 +1,4 @@ -package seedu.address.testutil; +package seedu.workbook.testutil; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/workbook/testutil/TestUtil.java similarity index 57% rename from src/test/java/seedu/address/testutil/TestUtil.java rename to src/test/java/seedu/workbook/testutil/TestUtil.java index 896d103eb0b..fc394134d5a 100644 --- a/src/test/java/seedu/address/testutil/TestUtil.java +++ b/src/test/java/seedu/workbook/testutil/TestUtil.java @@ -1,13 +1,13 @@ -package seedu.address.testutil; +package seedu.workbook.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 seedu.workbook.commons.core.index.Index; +import seedu.workbook.model.Model; +import seedu.workbook.model.internship.Internship; /** * A utility class for test cases. @@ -33,23 +33,23 @@ public static Path getFilePathInSandboxFolder(String fileName) { } /** - * Returns the middle index of the person in the {@code model}'s person list. + * Returns the middle index of the internship in the {@code model}'s internship list. */ public static Index getMidIndex(Model model) { - return Index.fromOneBased(model.getFilteredPersonList().size() / 2); + return Index.fromOneBased(model.getFilteredInternshipList().size() / 2); } /** - * Returns the last index of the person in the {@code model}'s person list. + * Returns the last index of the internship in the {@code model}'s internship list. */ public static Index getLastIndex(Model model) { - return Index.fromOneBased(model.getFilteredPersonList().size()); + return Index.fromOneBased(model.getFilteredInternshipList().size()); } /** - * Returns the person in the {@code model}'s person list at {@code index}. + * Returns the internship in the {@code model}'s internship list at {@code index}. */ - public static Person getPerson(Model model, Index index) { - return model.getFilteredPersonList().get(index.getZeroBased()); + public static Internship getInternship(Model model, Index index) { + return model.getFilteredInternshipList().get(index.getZeroBased()); } } diff --git a/src/test/java/seedu/workbook/testutil/TypicalIndexes.java b/src/test/java/seedu/workbook/testutil/TypicalIndexes.java new file mode 100644 index 00000000000..5715533440d --- /dev/null +++ b/src/test/java/seedu/workbook/testutil/TypicalIndexes.java @@ -0,0 +1,12 @@ +package seedu.workbook.testutil; + +import seedu.workbook.commons.core.index.Index; + +/** + * A utility class containing a list of {@code Index} objects to be used in tests. + */ +public class TypicalIndexes { + public static final Index INDEX_FIRST_INTERNSHIP = Index.fromOneBased(1); + public static final Index INDEX_SECOND_INTERNSHIP = Index.fromOneBased(2); + public static final Index INDEX_THIRD_INTERNSHIP = Index.fromOneBased(3); +} diff --git a/src/test/java/seedu/workbook/testutil/TypicalInternships.java b/src/test/java/seedu/workbook/testutil/TypicalInternships.java new file mode 100644 index 00000000000..8ec6306c2cc --- /dev/null +++ b/src/test/java/seedu/workbook/testutil/TypicalInternships.java @@ -0,0 +1,118 @@ +package seedu.workbook.testutil; + +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_COMPANY_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_DATETIME_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_DATETIME_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_ROLE_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_ROLE_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_STAGE_AMY; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_STAGE_BOB; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static seedu.workbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.internship.Internship; + + +/** + * A utility class containing a list of {@code Internship} objects to be used in tests. + */ +public class TypicalInternships { + + public static final Internship ALICE = new InternshipBuilder() + .withCompany("Alice Pauline") + .withRole("Software Engineer") + .withEmail("alice@example.com") + .withStage("Technical Interview") + .withDateTime("12-Oct-2022 12:00") + .withTags("friends").build(); + public static final Internship BENSON = new InternshipBuilder() + .withCompany("Benson Meier") + .withRole("Software Engineer") + .withEmail("johnd@example.com") + .withStage("HR Interview") + .withDateTime("12-Dec-2022 14:00") + .withLanguageTags("Java", "Python") + .withTags("owesMoney", "friends").build(); + public static final Internship CARL = new InternshipBuilder() + .withCompany("Carl Kurz") + .withRole("Software Engineer") + .withEmail("heinz@example.com") + .withStage("Rejected").build(); + + public static final Internship DANIEL = new InternshipBuilder() + .withCompany("Daniel Meier") + .withRole("Software Engineer") + .withEmail("cornelia@example.com") + .withStage("Technical Interview") + .withTags("friends").build(); + public static final Internship ELLE = new InternshipBuilder() + .withCompany("Elle Meyer") + .withRole("Software Engineer") + .withEmail("werner@example.com") + .withStage("Application Sent").build(); + public static final Internship FIONA = new InternshipBuilder() + .withCompany("Fiona Kunz") + .withRole("Software Engineer") + .withEmail("lydia@example.com") + .withStage("Online Assessment").build(); + public static final Internship GEORGE = new InternshipBuilder() + .withCompany("George Best") + .withRole("Software Engineer") + .withEmail("anna@example.com") + .withStage("Team Lead Interview").build(); + + + // Manually added + public static final Internship HOON = new InternshipBuilder() + .withCompany("Hoon Meier") + .withRole("Software Engineer") + .withEmail("stefan@example.com").build(); + public static final Internship IDA = new InternshipBuilder() + .withCompany("Ida Mueller") + .withRole("Software Engineer") + .withEmail("hans@example.com").build(); + + + // Manually added - Internship's details found in {@code CommandTestUtil} + public static final Internship AMY = new InternshipBuilder() + .withCompany(VALID_COMPANY_AMY) + .withRole(VALID_ROLE_AMY) + .withEmail(VALID_EMAIL_AMY) + .withStage(VALID_STAGE_AMY) + .withDateTime(VALID_DATETIME_AMY) + .withTags(VALID_TAG_FRIEND).build(); + public static final Internship BOB = new InternshipBuilder() + .withCompany(VALID_COMPANY_BOB) + .withRole(VALID_ROLE_BOB) + .withEmail(VALID_EMAIL_BOB) + .withStage(VALID_STAGE_BOB) + .withDateTime(VALID_DATETIME_BOB) + .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); + + public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER + + private TypicalInternships() {} // prevents instantiation + + /** + * Returns an {@code WorkBook} with all the typical internships. + */ + public static WorkBook getTypicalWorkBook() { + WorkBook ab = new WorkBook(); + for (Internship internship : getTypicalInternships()) { + ab.addInternship(internship); + } + return ab; + } + + public static List getTypicalInternships() { + return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE)); + } +} diff --git a/src/test/java/seedu/workbook/testutil/WorkBookBuilder.java b/src/test/java/seedu/workbook/testutil/WorkBookBuilder.java new file mode 100644 index 00000000000..9c4b44a7354 --- /dev/null +++ b/src/test/java/seedu/workbook/testutil/WorkBookBuilder.java @@ -0,0 +1,34 @@ +package seedu.workbook.testutil; + +import seedu.workbook.model.WorkBook; +import seedu.workbook.model.internship.Internship; + +/** + * A utility class to help with building WorkBook objects. + * Example usage:
+ * {@code WorkBook ab = new WorkBookBuilder().withInternship("John", "Doe").build();} + */ +public class WorkBookBuilder { + + private WorkBook workBook; + + public WorkBookBuilder() { + workBook = new WorkBook(); + } + + public WorkBookBuilder(WorkBook workBook) { + this.workBook = workBook; + } + + /** + * Adds a new {@code Internship} to the {@code WorkBook} that we are building. + */ + public WorkBookBuilder withInternship(Internship internship) { + workBook.addInternship(internship); + return this; + } + + public WorkBook build() { + return workBook; + } +} diff --git a/src/test/java/seedu/address/ui/TestFxmlObject.java b/src/test/java/seedu/workbook/ui/TestFxmlObject.java similarity index 96% rename from src/test/java/seedu/address/ui/TestFxmlObject.java rename to src/test/java/seedu/workbook/ui/TestFxmlObject.java index 5ecd82656f2..b10410fd40b 100644 --- a/src/test/java/seedu/address/ui/TestFxmlObject.java +++ b/src/test/java/seedu/workbook/ui/TestFxmlObject.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.workbook.ui; import javafx.beans.DefaultProperty; diff --git a/src/test/java/seedu/address/ui/UiPartTest.java b/src/test/java/seedu/workbook/ui/UiPartTest.java similarity index 97% rename from src/test/java/seedu/address/ui/UiPartTest.java rename to src/test/java/seedu/workbook/ui/UiPartTest.java index 33d82d911b8..311add255df 100644 --- a/src/test/java/seedu/address/ui/UiPartTest.java +++ b/src/test/java/seedu/workbook/ui/UiPartTest.java @@ -1,8 +1,8 @@ -package seedu.address.ui; +package seedu.workbook.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 seedu.workbook.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 seedu.workbook.MainApp; public class UiPartTest { diff --git a/src/test/resources/view/UiPartTest/validFile.fxml b/src/test/resources/view/UiPartTest/validFile.fxml index bab836af0db..8500bb664e9 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..9066bbeb323 100644 --- a/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml +++ b/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml @@ -1,6 +1,6 @@ - Hello World!