By: Team T12-2 Since: Aug 2018 Licence: MIT
- 1. Setting Up
- 2. Introduction
- 3. Design
- 4. Implementation
- 4.1. Undo/Redo Feature
- 4.2. Additional Information Feature
- 4.3. Design Considerations:
- 4.4. Add Medical History Features
- 4.5. Edit Medical History Feature
- 4.6. AddAppointment Feature
- 4.7. AddMedicalReport Feature
- 4.8. EditMedicalReport Feature
- 4.9. Find Feature
- 4.10. Sort Feature
- 4.11. Data Encryption
- 4.12. Design Considerations
- 4.13. Logging
- 4.14. Configuration
- 5. Documentation
- 6. Testing
- 7. Dev Ops
- Appendix A: Suggested Programming Tasks to Get Started
- Appendix B: Product Scope
- Appendix C: User Stories
- Appendix D: Use Cases
- D.1. Use Case: Viewing of Available Commands:
help - D.2. Use Case: Adding a Patient:
add - D.3. Use Case: Listing All Patients:
list - D.4. Use Case: Editing Basic Information of Patient:
edit - D.5. Use Case: Deleting a Patient:
delete - D.6. Use Case: Selecting a Patient:
select - D.7. Use Case: Adding Additional Information of Patient:
addinfo - D.8. Use Case: Adding of Medical History:
addhist - D.9. Use Case: Editing of Medical History:
edithist - D.10. Use Case: Adding an Appointment for a Patient:
addappt - D.11. Use Case: Editing an Appointment for a Patient:
editappt - D.12. Use Case: Deleting an Appointment for a Patient:
deleteappt - D.13. Use Case: Clearing Appointments for All Patients:
clearappts - D.14. Use Case: Adding of Medical Report:
addreport - D.15. Use Case: Editing of Medical Report:
editreport - D.16. Use Case: Finding Patients by Categories:
find - D.17. Use Case: Sorting Patients List:
sort - D.18. Use Case: Data Encryption:
encrypt
- D.1. Use Case: Viewing of Available Commands:
- Appendix E: Non Functional Requirements
- Appendix F: Glossary
- Appendix G: Product Survey
- Appendix H: Instructions for Manual Testing
- H.1. Launch and Shutdown
- H.2. Deleting a Person
- H.3. Adding Additional Information to a Person
- H.4. Adding Appointment to a Patient
- H.5. Editing Appointment for a Patient
- H.6. Deleting Appointment for a Patient
- H.7. Clearing Appointments for All Patients
- H.8. Adding Medical History to Patient
- H.9. Editing Medical History of Patient
- H.10. Adding Medical Report to a Patient
- H.11. Editing an Existing Medical Report of a Patient
- H.12. Filtering Patients List by find
- H.13. Sorting Patients List by sort
- H.14. Encryption
-
JDK
9or later⚠️ JDK 10on Windows will fail to run tests in headless mode due to a JavaFX bug. Windows developers are highly recommended to use JDK9. -
IntelliJ IDE
ℹ️IntelliJ by default has Gradle and JavaFx plugins installed.
Do not disable them. If you have disabled them, go toFile>Settings>Pluginsto re-enable them.
-
Fork this repo, and clone the fork to your computer
-
Open IntelliJ (if you are not in the welcome screen, click
File>Close Projectto close the existing project dialog first) -
Set up the correct JDK version for Gradle
-
Click
Configure>Project Defaults>Project Structure -
Click
New…and find the directory of the JDK
-
-
Click
Import Project -
Locate the
build.gradlefile and select it. ClickOK -
Click
Open as Project -
Click
OKto accept the default settings -
Open a console and run the command
gradlew processResources(Mac/Linux:./gradlew processResources). It should finish with theBUILD SUCCESSFULmessage.
This will generate all resources required by the application and tests.
-
Run the
seedu.address.MainAppand try a few commands -
Run the tests to ensure they all pass.
This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,
-
Go to
File>Settings…(Windows/Linux), orIntelliJ IDEA>Preferences…(macOS) -
Select
Editor>Code Style>Java -
Click on the
Importstab to set the order-
For
Class count to use import with '*'andNames count to use static import with '*': Set to999to prevent IntelliJ from contracting the import statements -
For
Import Layout: The order isimport static all other imports,import java.*,import javax.*,import org.*,import com.*,import all other imports. Add a<blank line>between eachimport
-
Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.
After forking the repo, the documentation will still have the SE-EDU branding and refer to the se-edu/addressbook-level4 repo.
If you plan to develop this fork as a separate product (i.e. instead of contributing to se-edu/addressbook-level4), you should do the following:
-
Configure the site-wide documentation settings in
build.gradle, such as thesite-name, to suit your own project. -
Replace the URL in the attribute
repoURLinDeveloperGuide.adocandUserGuide.adocwith the URL of your fork.
Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.
After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).
|
ℹ️
|
Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork. |
Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).
|
ℹ️
|
Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based) |
When you are ready to start coding,
-
Get some sense of the overall design by reading Section 3.1, “Architecture”.
-
Take a look at Appendix A, Suggested Programming Tasks to Get Started.
Health Book (or some other name that we will be deciding later) is an address book application that is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place. Command Line Interface is utilized mainly for the input, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI.
Health Book is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place.
With many patients to attend to, healthcare professionals need to focus much of their attention and care on their patients and less on administrative matters. Health Book is a one-stop application for healthcare professionals to create, read, update or delete (CRUD) patient’s information, reducing the need for long and troublesome paperwork and simplifying administrative work.
Command Line Interface is utilized mainly for the input, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book also aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI.
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
|
💡
|
The .pptx files used to create diagrams in this document can be found in the diagrams folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture.
|
Main has only one class called MainApp. It is responsible for,
-
At app launch: Initializes the components in the correct sequence, and connects them up with each other.
-
At shut down: Shuts down the components and invokes cleanup method where necessary.
Commons represents a collection of classes used by multiple other components. Two of those classes play important roles at the architecture level.
-
EventsCenter: This class (written using Google’s Event Bus library) is used by components to communicate with other components using events (i.e. a form of Event Driven design) -
LogsCenter: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
Each of the four components
-
Defines its API in an
interfacewith the same name as the Component. -
Exposes its functionality using a
{Component Name}Managerclass.
For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.
The Sequence Diagram below shows how the components interact for the scenario where the user issues the command delete 1.
|
ℹ️
|
Note how the Model simply raises a AddressBookChangedEvent when the Address Book data are changed, instead of asking the Storage to save the updates to the hard disk.
|
The diagram below shows how the EventsCenter reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
|
ℹ️
|
Note how the event is propagated through the EventsCenter to the Storage and UI without Model having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components.
|
The sections below give more details of each component.
API : Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, PersonListPanel, StatusBarFooter, BrowserPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.
The UI component uses 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 is specified in MainWindow.fxml
The UI component,
-
Executes user commands using the
Logiccomponent. -
Binds itself to some data in the
Modelso that the UI can auto-update when data in theModelchange. -
Responds to events raised from various parts of the App and updates the UI accordingly.
API :
Logic.java
-
Logicuses theAddressBookParserclass to parse the user command. -
This results in a
Commandobject which is executed by theLogicManager. -
The command execution can affect the
Model(e.g. adding a person) and/or raise events. -
The result of the command execution is encapsulated as a
CommandResultobject which is passed back to theUi.
Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.
API : Model.java
The Model,
-
stores a
UserPrefobject that represents the user’s preferences. -
stores the Address Book data.
-
exposes an unmodifiable
ObservableList<Person>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. -
does not depend on any of the other three components.
API : Storage.java
The Storage component,
-
can save
UserPrefobjects in json format and read it back. -
can save the Address Book data in xml format and read it back.
This section describes some noteworthy details on how certain features are implemented.
The undo/redo mechanism is facilitated by VersionedAddressBook.
It extends AddressBook with an undo/redo history, stored internally as an addressBookStateList and currentStatePointer.
Additionally, it implements the following operations:
-
VersionedAddressBook#commit()— Saves the current address book state in its history. -
VersionedAddressBook#undo()— Restores the previous address book state from its history. -
VersionedAddressBook#redo()— Restores a previously undone address book state from its history.
These operations are exposed in the Model interface as Model#commitAddressBook(), Model#undoAddressBook() and Model#redoAddressBook() respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook will be initialized with the initial address book state, and the currentStatePointer pointing to that single address book state.
Step 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 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.
|
ℹ️
|
If a command fails its execution, it will not call Model#commitAddressBook(), so the address book state will not be saved into the addressBookStateList.
|
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.
|
ℹ️
|
If the currentStatePointer is at index 0, pointing to the initial address book state, then there are no previous address book states to restore. The undo command uses Model#canUndoAddressBook() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
|
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.
|
ℹ️
|
If the currentStatePointer is at index addressBookStateList.size() - 1, pointing to the latest address book state, then there are no undone address book 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.
|
Step 5. The user then decides to execute the command list. Commands that do not modify the address book, such as list, will usually not call Model#commitAddressBook(), Model#undoAddressBook() or Model#redoAddressBook(). Thus, the addressBookStateList remains unchanged.
Step 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. We designed it this way because it no longer makes sense to redo the add n/David … command. This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
-
Alternative 1 (current choice): Saves the entire address 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). -
Cons: We must ensure that the implementation of each individual command are correct.
-
-
Alternative 1 (current choice): Use a list to store the history of address book states.
-
Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.
-
Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both
HistoryManagerandVersionedAddressBook.
-
-
Alternative 2: Use
HistoryManagerfor undo/redo-
Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.
-
Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as
HistoryManagernow needs to do two different things.
-
The addinfo command is facilitated by the LogicManager which calls upon AddressBookParser for the execution of commands. It extends the AddressBookParser with the addinfo command.
The command takes in an index which represents the Person in the list displayed in the PersonCardList view. This is followed by a pre-defined list of arguments that user can input to tell the program which attribute of the person will be added/edited using the AddInfoCommandParser (For eg. the argument g/ tells the command that the Gender attribute of the Person at index will be edited).
The command then looks for the String after the arguments which represents the data to be added. This data will be checked for validity using the ParserUtil class. If the data is valid, the respective class will be initialized (For eg. the commmand g/M is valid as it stands for changing the Gender of Person to Male. Since the data M is valid, the Gender class will be initialized). If the data is not valid however, an ParseException will be thrown warning users that the input data is not valid.
Upon handling all the arguments, an addInfoPersonDescriptor object will be created. This is essentially a facade object that contains all the attributes of the Person to be edited, with its updated attributes. There will then be a mapping of the addInfoPersonDescriptor to a new Person object facilitated by the method AddInfoCommand#createEditedPerson.
Finally, the Model#updatePerson "copies" attribute of the new Person object created above to the Person to be edited by calling the VersionedAddressBook#updatePerson which sets the new Person object to the Person to be edited using UniquePersonList#SetPerson.
Given below is an example usage scenario and how the addinfo command works at each step.
Step 1. User executes addinfo 5 ic/S1234567Z g/M d/01-01-1970 to modify the Nric, Gender, and DateOfBirth attributes of the 5th person in the PersonCardList view.
|
ℹ️
|
If any of the arguments contain invalid data, the program will not process any data. For instance, addinfo 1 i/S1234567Z d/20-20-19872 g/M will not change the Nric attribute of the Person at index 1 as the date of birth argument contains erroneous date.
|
Step 2. The AddressBookParser makes a call to AddInfoCommandParser together with the String input.
Step 3. The AddInfoCommandParser then looks out for the pre-determined set of arguments in the String input. If any of the arguments are found, data after the argument will be extracted.
Step 4. The ParserUtil class then checks for the validity of the data being extracted and parsed. If the data is valid, the class for that data will be initialized and added into an AddInfoPersonDescriptor object. If the data is not valid, a ParseException will be thrown, which will be handled by the UIManager requesting user the correct the data.
Step 5. A Person object will be retrieved from the lastShownList at the appropriate index. The retrieved Person object will then retrieve the updated information from the AddInfoPersonDescriptor object created previously.
Step 6. The Person will now have an updated additional information.
The following sequence diagram summarizes what happens when an user executes a new command:
-
Alternative 1: Store all data type as
String.-
Pros: Easy to implement; easy to understand
-
Cons: Hard to enforce valid data input (Can only be done with Regular Expression, which can be very tedious);
Stringis not useful in getting accessory information and operations (eg. Storing Date of Birth inStringmakes calculating age and sorting by Date of Birth difficult).
-
-
Alternative 2 (current choice): Use custom data type for each additional information (enumeration, LocalDate etc).
-
Pros: Easier to enforce valid data input; accessory information can be retrieved from and accessory operations can be executed on those data types.
-
Cons: More difficult to implement; adds unnecessary complexity (especially with enumeration).
-
The addhist mechanism is facilitated by VersionedAddressBook.
The addhist command first takes in the index of the patient followed by the prefixes of information to be stored in the medical history.
The user input will go through AddHistCommandParser.java and AddressBookParser.java to ensure user input conforms to the expected format.
It is then returned as an AddHistCommand object for execution.
In AddHistCommand.java, the execute method will run.
The list of patients is retrieved from model.getFilteredPersonList() and stored under lastShownList.
Using the index specified in the command, the patient at that index will be the personToEdit for its medical history.
The method model.updatePerson() and model.updateFilteredPersonList() will update the contents of the patient’s medical history.
Execution ends when CommandResult(generateSuccessMessage(editedPerson)) generates a success message after medical history has been added.
Additionally, it implements the following operations:
-
Model#getFilteredPersonList()— Obtains the entire current list of persons that is being displayed to the user -
VersionedAddressBook#updatePerson()— Updates the specified person with the new data. -
indicateAddressBookChanged()— Raises an event to indicate the AddressBook in the model has changed
These operations are exposed in the Model interface as Model#updatePerson(), Model#updateFilteredPersonList() and Model#commitAddressBook() respectively.
Given below is an example usage scenario and how the addhist mechanism behaves at each step.
Step 1. The user launches the application. If it is the first time he/she is launching it, the VersionedAddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the VersionedAddressBook will be launched with the data he has previously saved in his previous launch.
Step 2. The user executes addhist 1 hsd/ 10-10-2010 hsa/Alcohol hsc/ Kuwait hsds/d command to add an entry of medical history to the 1st person in the list that the address book is currently showing. The addhist command obtains the data of the person that the user is trying to change based on the index that the user has input.
Step 3. The addhist command will obtain the set of entries in the medical history that the person previously had, copy it to a new set of medical history entries, and add the medical history which the user wants to add into the new set.
Step 4. The addhist command will call Model#updatePerson() to update the person with this new set of medical history entries. The addhist command will also call Model#updateFilteredPersonList() to update the list that is being showed to the user.
Step 5. Lastly, the addhist command will call Model#commitAddressBook() to update the addressBookStateList and currentStatePointer.
The following diagram shows how the addhist command works:
The edithist mechanism works almost similarly to the addhist mechanism.
It is also facilitated by VersionedAddressBook.
The edithist command first takes in the index of the patient followed by the date of the entry the user is about to edit,
followed by the prefixes of information to be stored in that medical history entry chosen.
The user input will go through EditHistCommandParser.java and AddressBookParser.java to ensure user input conforms to the expected format.
It is then returned as an EditHistCommand object for execution.
In EditHistCommand.java, the execute method will run.
The list of patients is retrieved from model.getFilteredPersonList() and stored under lastShownList.
Using the index specified in the command, the patient at that index will be the personToEdit for its medical history.
The method model.updatePerson() and model.updateFilteredPersonList() will update the contents of the patient’s medical history.
Execution ends when CommandResult(generateSuccessMessage(editedPerson)) generates a success message after medical history has been added.
Additionally, it implements the following operations:
-
Model#getFilteredPersonList()— Obtains the entire current list of persons that is being displayed to the user -
VersionedAddressBook#updatePerson()— Updates the specified person with the new data. -
indicateAddressBookChanged()— Raises an event to indicate the AddressBook in the model has changed
These operations are exposed in the Model interface as Model#updatePerson(), Model#updateFilteredPersonList() and Model#commitAddressBook() respectively.
Given below is an example usage scenario and how the edithist mechanism behaves at each step.
Step 1. The user launches the application. If it is the first time he/she is launching it, the VersionedAddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the VersionedAddressBook will be launched with the data he has previously saved in his previous launch.
Step 2. The user will find a medical history entry of a person to edit.
Step 3. The user executes edithist 1 hsod/10-10-2010 hsd/10-10-2015 hsa/Chocolate hsc/Russia hsds/a command to edit the entry of medical history of the 1st person in the list with the date of 10-10-2010 that the address book is currently showing.
The edithist command obtains the data of the person that the user is trying to change based on the index that the user has input.
Step 3. The edithist command will obtain the set of entries in the medical history that the person previously had, copy it to a new set of medical history entries, and in the middle of that, make the necessary changes to the entry chosen.
Step 4. The edithist command will call Model#updatePerson() to update the person with this new set of medical history entries. The edithist command will also call Model#updateFilteredPersonList() to update the list that is being showed to the user.
Step 5. Lastly, the edithist command will call Model#commitAddressBook() to update the addressBookStateList and currentStatePointer.
The addappt mechanism is facilitated by AddressBook and VersionedAddressBook. It implements the following operations:
-
AddressBook#getFilteredPersonList()— Obtains the entire current list of patients that is being displayed to the user -
AddressBook#updatePerson()— Updates the specified person with the new data. -
AddressBook#updateFilteredPersonList()— Shows a filtered list of patients. -
VersionedAddressBook#commit()— Updates the specified patient with the new data.
These operations are exposed in the Model interface as Model#getFilteredPersonList(), Model#updatePerson(), Model#updateFilteredPersonList() and Model#commitAddressBook() respectively.
Given below is an example usage scenario and how the addappt mechanism behaves at each step.
Step 1. The user launches the application. If it is the first time he/she is launching it, the AddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the AddressBook will be launched with the data he has previously saved in his previous launch.
Step 2. The user executes addappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan command to add an appointment to the 1st patient in the list that the address book is currently showing. The addappt command obtains the data of the patient that the user is trying to update by calling Model#getFilteredPersonList() and getting the patient’s data based on the index the user has provided.
Step 3. The addappt command will first check if there is an invalid appointment given i.e. end date and time before start date and time, and also if there is an appointment timing clash between the appointment to be added and existing appointments for the patient. If there are such cases, a CommandException will be thrown with the appropriate message to be shown in the GUI.
Step 4. The addappt command will obtain the patient’s existing set of appointments, copy it to a new set of appointments, and add the appointment which the user wants to add into the new set.
Step 5. The addappt command will call Model#updatePerson() to update the patient with this new set of appointments. The addappt command will also call Model#updateFilteredPersonList() to update the list that is being showed to the user to show all patients. Lastly, the addappt command will call Model#commitAddressBook() to update the addressBookStateList and currentStatePointer.
The following sequence diagram captures the interactions that goes on between multiple classes during the addappt operation :
The following activity diagram shows the workflow for both the user and the system during the addappt operation:
-
Alternative 1 (current choice): Use a Treeset with a comparator function to store appointments in order of start time
-
Pros: Easy to display through the information panel as appointments can be shown through a JavaFX VBox, which automatically resizes based on how many appointments the specified patient has
-
Cons: The Treeset storing the appointments can be modified easily wherever it is passed, thus violating the observer pattern. Care must be taken not to modify the treeset inappropriately.
-
-
Alternative 2: Use an ObservableList to store appointments
-
Pros: Makes use of the observer pattern to pass an unmodifiable ObservableList to wherever it is needed, thus preventing inappropriate modification.
-
Cons: Must be displayed through a JavaFX ListView, which is difficult to resize based on how many appointments the specified patient has, thus hampering user experience.
-
The addreport mechanism is facilitated by VersionedAddressBook.
Additionally, it implements the following operations:
-
Model#getFilteredPersonList()— Obtains the entire current list of persons that is being displayed to the user -
VersionedAddressBook#updatePerson()— Updates the specified person with the new data. -
indicateAddressBookChanged() — Raises an event to indicate the AddressBook in the model has changed.
These operations are exposed in the Model interface as Model#updatePerson(), Model#updateFilteredPersonList() and Model#commitAddressBook() respectively.
Given below is an example usage scenario and how the addreport mechanism behaves at each step.
Step 1. The user launches the application. If it is the first time he/she is launching it, the VersionedAddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the VersionedAddressBook will be launched with the data he has previously saved in his previous launch.
Step 2. The user executes addreport 1 t/Asthma d/01-01-2018 i/Prescribed XXX medicine, next appointment on 02-02-2018 command to add a medical report to the person at index 1 in the list that the address book is currently showing. The addreport command obtains the data of the person that the user is trying to change based on the index that the user has input.
Step 3. The addreport command will obtain the set of medical reports that the person previously had, copy it to a new set of reports, and add the report which the user wants to add into the new set.
Step 4. The addreport command will call Model#updatePerson() to update the person with this new set of reports. The addreport command will call Model#updateFilteredPersonList() to update the list that the user is shown.
Step 5. The addreport command will call Model#commitAddressBook() to update the addressBookStateList and currentStatePointer.
The following sequence diagram shows how the addreport operation works:
The editreport mechanism is facilitated by VersionedAddressBook.
Additionally, it implements the following operations:
-
Model#getFilteredPersonList()— Obtains the entire current list of persons that is being displayed to the user -
VersionedAddressBook#updatePerson()— Updates the specified person with the new data. -
indicateAddressBookChanged() — Raises an event to indicate the AddressBook in the model has changed.
These operations are exposed in the Model interface as Model#updatePerson(), Model#updateFilteredPersonList() and Model#commitAddressBook() respectively.
Given below is an example usage scenario and how the editreport mechanism behaves at each step.
Step 1. The user launches the application. If it is the first time he/she is launching it, the VersionedAddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the VersionedAddressBook will be launched with the data he has previously saved in his previous launch.
Step 2. The user will find a medical report of a patient to edit.
Step 3. The user executes editreport 1 ot/Asthma od/01-01-2018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment on 03-03-2018 command to edit the existing medical report of the person at index 1 in the list titled Asthma and dated 01-01-2018. The editreport command obtains the data of the person that the user is trying to change based on the index that the user has input.
Step 3. The editreport command will obtain the set of medical reports that the person previously had, copy it to a new set of medical reports and make the necessary changes to the medical report chosen.
Step 4. The editreport command will call Model#updatePerson() to update the person with this new set of medical reports. The editreport command will also call Model#updateFilteredPersonList() to update the list that is being showed to the user.
Step 5. Lastly, the editreport command will call Model#commitAddressBook() to update the addressBookStateList and currentStatePointer.
The find mechanism is facilitated by ModelManager. It extends AddressBook and filters the internalList of patients in UniquePersonList. Additionally,
it implements ModelManager#updateFilteredPersonList() and ModelManager#getFilteredPersonList() operations with the the 2 input parameters (prefix and keyword) before finding the patients
accordingly.
This operation is exposed in the Model interface as Model#updateFilteredPersonList() and Model#getFilteredPersonList().
Given below is an example usage scenario and how the find mechanism behaves at each step.
Step 1. A doctor launches the application for the first time. If it hs/her first time launching the Health Book, the VersionedAddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the VersionedAddressBook will be launched with the data he has previously saved in his previous launch.
|
❗
|
The list that the doctor will be implementing the find command on will be the full patient list and details stored in the database.
|
Step 2. The doctor executes find hsa/ alcohol nut command to to filter patients who are allergic to alcohol and nut recorded in the whole Health Book. The find command obtains the detail of the patient and keywords of the user input.
|
|
If the command format is invalid, an error message will be shown to prompt the user of the correct format. |
Step 3. The find command parser will translate the input hsa/ into method AllergyContainsKeywordsPredicate which find patients with "alcohol" and "nut" predicates in their allergy.
|
ℹ️
|
There must be more than one keyword and the prefix is case sensitive. |
Step 4. The find command will call Model#updateFilteredPersonList() to generate a patients list containing patients with "alcohol" and "nut" predicates in their allergy detail.
Step 5. The find command will then call Model#getFilteredPersonList() to show the filtered list in the interface.
The following sequence diagram summarizes the activity when a user (doctor) executes a new find command:
The sort mechanism is facilitated by ModelManager. It extends AddressBook and sorts the internalList of patients in UniquePersonList. Additionally,
it implements ModelManager#updateSortedPersonList operation with the 2 input parameters (prefix and order) before sorting the patients
accordingly.
This operation is exposed in the Model interface as Model#updateSortedPersonList().
Given below is an example usage scenario and how the sort mechanism behaves at each step.
Step 1. A doctor launches the application for the first time. If it hs/her first time launching the Health Book, the VersionedAddressBook will be initialized with a sample address book data. If he/she has launched it and has made changes before, the VersionedAddressBook will be launched with the data he has previously saved in his previous launch.
|
❗
|
The list that the doctor will be implementing the sort command on will be the current patient list as shown in the interface. |
Step 2. The doctor executes sort n/ 2 command to generate a sorted and reversed list of patients according to their names. The sort command obtains the doctor’s prefix and order input
|
|
If the command format is invalid, an error message will be shown to prompt the user of the correct format. |
Step 3. The sort command will call Model#updateSortedPersonList() to update the person list with the doctor’s input of prefix and order.
Step 4. The patients list will then be sorted by sortPersons() in UniquePersonList.
Step 5. The final patient list result generated will be sorted accordingly to the doctor’s input: Patient list sorted by their names in the reverse order.
The following sequence diagram summarizes the activity when a user (doctor) executes a new sort command:
-
Alternative 1 (current choice): Uses comparator on List data structure to sort the observable filtered list through sort method implemented in
UniquePersonList.-
Pros: Easy to implement.
-
Cons: Many different comparators need to be done for each of the different categories.
-
-
Alternative 2: Patient list can be stored in a set instead of list
-
Pros: This reduces the implementation comparators as the patient list will be sorted by names by default when using set.
-
Cons: Accessing individual data (especially when editing specific patient data) will be tedious and challenging to extract.
-
The encryption library used is Apache Santuario. It extends the existing XmlUtil with methods that encrypt and decrypt .xml files.
Using AES 128-bit symmetric encryption, the encryption mechanism is facilitated by XmlUtil, SecurityKey and the file preferences.json.
|
ℹ️
|
While the file preferences.json file is not used during the actual encryption process, the file is used to initialize the attributes of UserPrefs object which determines the encryption process.
|
Upon running the program, MainApp#initSecretKey checks if encryption has been enabled using value of the attribute encryption in UserPrefs object. If it is true, encryption is enabled and the method then checks if key file exist. The method will attempt to read the key file using SecretKeyUtil#ReadSecretKey and save the key into a SecretKey object should there be an existing key file.
However, if encryption is not enabled, or should there be an error reading the key file, or that the key file does not exist, MainApp#initSecretKey will then proceed to generate a new SecretKey object using SecretKetUtil#getSecretKey.
Next, MainApp#initModelManager will be executed. This method will also check if encryption has been enabled using preferences.json file. If encryption is enabled, it will attempt to look for healthbook_encrypted.xml file. If healthbook_encrypted.xml file exist, the same method will first load the .xml file using XmlUtil#loadEncryptedXmlFile, before attempting to decrypt the encrypted .xml file using the SecretKey object with the method XmlUtil#decryptDocument. A temporary healthbook.xml will be generated to be consumed by the program.
However, if healthbook_encrypted.xml does not exist, MainApp#initModeManager assumes that user runs the program for the first time, and proceed to load in sample data. If the healthbook_encrypted.xml does exist, but could not be decrypted successfully, Health Book will be launched without any patient data. An error pertaining to the failure to decrypt the .xml file will also be logged.
Upon exiting the program, MainApp#stop checks if the encryption has been enabled. If the encryption has been enabled, it will call XmlUtil#loadDecryptedXmlFile which loads the temporary healthbook.xml file before encrypting the temporary healthbook.xml file with XmlUtil#encryptDocument method. It will then proceed to destroy the temporary healthbook.xml file and generate a key file based on the SecretKey object and the encrypted healthbook_encrypted.xml file.
When users execute the encrypt command, the AddressBookParser returns EncryptCommand object to the LogicManager, which in turn executes the EncryptCommand#execute method. This method in turn gets the UserPref via Model#getUserPref and executes the toggleEncryption method, which in turn sets the encryption attribute in UserPref to either true or false, thereby enabling or disabling encryption.
The following sequence diagram shows how the encryption works when the application is launched:
Given below is an example usage scenario on how encrypt works at each step:
Step 1. A doctor launches the application for the the first time (by default encryption is disabled). A SecretKey is generated.
Step 2. The doctor added in some new patient data.
Step 3. The doctor executes encrypt.
Step 4. The doctor exits the program.
Step 5. Before the application fully exits, the MainApp#stop method asserts that encryption has been enabled. A temporary healthbook.xml file is generated. The same method will call XmlUtil#loadDecryptedXmlFile to load the temporary healthbook.xml before calling XmlUtil#encryptDocument to encrypt the file data. A key file is generated containing the SecretKey used for the encryption.
Step 6. MainApp#stop then deletes the temporary healthbook.xml file before fully exiting the application.
-
Alternative 1 (current choice): Encrypted
.xmlfile will be decrypted and stored as a temporary filehealthbook.xml, which will be used by the application during startup to load the saved patient data.-
Pros: Easy to implement - no major changes required for input/output operations.
-
Cons: Users are still able to retrieve the unencrypted file when using the application.
-
-
Alternative 2: Encrypted
.xmlfile will be decrypted, with the decrypted data being processed by the application immediately for the loading of saved patient data.-
Pros: Unencrypted
.xmlfile will never be retrievable. -
Cons: Difficult to implement given the time constraint, as it involves major restructuring of the input/output operation of the application.
-
We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevelsetting in the configuration file (See Section 4.14, “Configuration”) -
The
Loggerfor a class can be obtained usingLogsCenter.getLogger(Class)which will log messages according to the specified logging level -
Currently log messages are output through:
Consoleand to a.logfile.
Logging Levels
-
SEVERE: Critical problem detected which may possibly cause the termination of the application -
WARNING: Can continue, but with caution -
INFO: Information showing the noteworthy actions by the App -
FINE: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
We use asciidoc for writing documentation.
|
ℹ️
|
We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting. |
See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits.
Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.
See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.
We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.
Here are the steps to convert the project documentation files to PDF format.
-
Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the
docs/directory to HTML format. -
Go to your generated HTML files in the
build/docsfolder, right click on them and selectOpen with→Google Chrome. -
Within Chrome, click on the
Printoption in Chrome’s menu. -
Set the destination to
Save as PDF, then clickSaveto save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.
The build.gradle file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.
|
💡
|
Attributes left unset in the build.gradle file will use their default value, if any.
|
| Attribute name | Description | Default value |
|---|---|---|
|
The name of the website. If set, the name will be displayed near the top of the page. |
not set |
|
URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar. |
not set |
|
Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items. |
not set |
Each .adoc file may also specify some file-specific asciidoc attributes which affects how the file is rendered.
Asciidoctor’s built-in attributes may be specified and used as well.
|
💡
|
Attributes left unset in .adoc files will use their default value, if any.
|
| Attribute name | Description | Default value |
|---|---|---|
|
Site section that the document belongs to.
This will cause the associated item in the navigation bar to be highlighted.
One of: * Official SE-EDU projects only |
not set |
|
Set this attribute to remove the site navigation bar. |
not set |
The files in docs/stylesheets are the CSS stylesheets of the site.
You can modify them to change some properties of the site’s design.
The files in docs/templates controls the rendering of .adoc files into HTML5.
These template files are written in a mixture of Ruby and Slim.
|
|
Modifying the template files in |
There are three ways to run tests.
|
💡
|
The most reliable way to run tests is the 3rd one. The first two methods might fail some GUI tests due to platform/resolution-specific idiosyncrasies. |
Method 1: Using IntelliJ JUnit test runner
-
To run all tests, right-click on the
src/test/javafolder and chooseRun 'All Tests' -
To run a subset of tests, you can right-click on a test package, test class, or a test and choose
Run 'ABC'
Method 2: Using Gradle
-
Open a console and run the command
gradlew clean allTests(Mac/Linux:./gradlew clean allTests)
|
ℹ️
|
See UsingGradle.adoc for more info on how to run tests using Gradle. |
Method 3: Using Gradle (headless)
Thanks to the TestFX library we use, our GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.
To run tests in headless mode, open a console and run the command gradlew clean headless allTests (Mac/Linux: ./gradlew clean headless allTests)
We have two types of tests:
-
GUI Tests - These are tests involving the GUI. They include,
-
System Tests that test the entire App by simulating user actions on the GUI. These are in the
systemtestspackage. -
Unit tests that test the individual components. These are in
seedu.address.uipackage.
-
-
Non-GUI Tests - These are tests not involving the GUI. They include,
-
Unit tests targeting the lowest level methods/classes.
e.g.seedu.address.commons.StringUtilTest -
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 -
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
-
See UsingGradle.adoc to learn how to use Gradle for build automation.
We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.
We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.
When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See UsingNetlify.adoc for more details.
Here are the steps to create a new release.
-
Update the version number in
MainApp.java. -
Generate a JAR file using Gradle.
-
Tag the repo with the version number. e.g.
v0.1 -
Create a new release using GitHub and upload the JAR file you created.
A project often depends on third-party libraries. For example, Address Book depends on the Jackson library for XML parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
a. Include those libraries in the repo (this bloats the repo size)
b. Require developers to download those libraries manually (this creates extra work for developers)
Suggested path for new programmers:
-
First, add small local-impact (i.e. the impact of the change does not go beyond the component) enhancements to one component at a time. Some suggestions are given in Section A.1, “Improving Each Component”.
-
Next, add a feature that touches multiple components to learn how to implement an end-to-end feature across all components. Section A.2, “Creating a New Command:
remark” explains how to go about adding such a feature.
Each individual exercise in this section is component-based (i.e. you would not need to modify the other components to get it to work).
Scenario: You are in charge of logic. During dog-fooding, your team realize that it is troublesome for the user to type the whole command in order to execute a command. Your team devise some strategies to help cut down the amount of typing necessary, and one of the suggestions was to implement aliases for the command words. Your job is to implement such aliases.
|
💡
|
Do take a look at Section 3.3, “Logic Component” before attempting to modify the Logic component.
|
-
Add a shorthand equivalent alias for each of the individual commands. For example, besides typing
clear, the user can also typecto remove all persons in the list.-
Hints
-
Just like we store each individual command word constant
COMMAND_WORDinside*Command.java(e.g.FindCommand#COMMAND_WORD,DeleteCommand#COMMAND_WORD), you need a new constant for aliases as well (e.g.FindCommand#COMMAND_ALIAS). -
AddressBookParseris responsible for analyzing command words.
-
-
Solution
-
Modify the switch statement in
AddressBookParser#parseCommand(String)such that both the proper command word and alias can be used to execute the same intended command. -
Add new tests for each of the aliases that you have added.
-
Update the user guide to document the new aliases.
-
See this PR for the full solution.
-
-
Scenario: You are in charge of model. One day, the logic-in-charge approaches you for help. He wants to implement a command such that the user is able to remove a particular tag from everyone in the address book, but the model API does not support such a functionality at the moment. Your job is to implement an API method, so that your teammate can use your API to implement his command.
|
💡
|
Do take a look at Section 3.4, “Model Component” before attempting to modify the Model component.
|
-
Add a
removeTag(Tag)method. The specified tag will be removed from everyone in the address book.-
Hints
-
The
Modeland theAddressBookAPI need to be updated. -
Think about how you can use SLAP to design the method. Where should we place the main logic of deleting tags?
-
Find out which of the existing API methods in
AddressBookandPersonclasses can be used to implement the tag removal logic.AddressBookallows you to update a person, andPersonallows you to update the tags.
-
-
Solution
-
Implement a
removeTag(Tag)method inAddressBook. Loop through each person, and remove thetagfrom each person. -
Add a new API method
deleteTag(Tag)inModelManager. YourModelManagershould callAddressBook#removeTag(Tag). -
Add new tests for each of the new public methods that you have added.
-
See this PR for the full solution.
-
-
Scenario: You are in charge of ui. During a beta testing session, your team is observing how the users use your address book application. You realize that one of the users occasionally tries to delete non-existent tags from a contact, because the tags all look the same visually, and the user got confused. Another user made a typing mistake in his command, but did not realize he had done so because the error message wasn’t prominent enough. A third user keeps scrolling down the list, because he keeps forgetting the index of the last person in the list. Your job is to implement improvements to the UI to solve all these problems.
|
💡
|
Do take a look at Section 3.2, “UI Component” before attempting to modify the UI component.
|
-
Use different colors for different tags inside person cards. For example,
friendstags can be all in brown, andcolleaguestags can be all in yellow.Before
After
-
Hints
-
The tag labels are created inside the
PersonCardconstructor (new Label(tag.tagName)). JavaFX’sLabelclass allows you to modify the style of each Label, such as changing its color. -
Use the .css attribute
-fx-background-colorto add a color. -
You may wish to modify
DarkTheme.cssto include some pre-defined colors using css, especially if you have experience with web-based css.
-
-
Solution
-
You can modify the existing test methods for
PersonCard's to include testing the tag’s color as well. -
See this PR for the full solution.
-
The PR uses the hash code of the tag names to generate a color. This is deliberately designed to ensure consistent colors each time the application runs. You may wish to expand on this design to include additional features, such as allowing users to set their own tag colors, and directly saving the colors to storage, so that tags retain their colors even if the hash code algorithm changes.
-
-
-
-
Modify
NewResultAvailableEventsuch thatResultDisplaycan show a different style on error (currently it shows the same regardless of errors).Before
After
-
Hints
-
NewResultAvailableEventis raised byCommandBoxwhich also knows whether the result is a success or failure, and is caught byResultDisplaywhich is where we want to change the style to. -
Refer to
CommandBoxfor an example on how to display an error.
-
-
Solution
-
Modify
NewResultAvailableEvent's constructor so that users of the event can indicate whether an error has occurred. -
Modify
ResultDisplay#handleNewResultAvailableEvent(NewResultAvailableEvent)to react to this event appropriately. -
You can write two different kinds of tests to ensure that the functionality works:
-
The unit tests for
ResultDisplaycan be modified to include verification of the color. -
The system tests
AddressBookSystemTest#assertCommandBoxShowsDefaultStyle() and AddressBookSystemTest#assertCommandBoxShowsErrorStyle()to include verification forResultDisplayas well.
-
-
See this PR for the full solution.
-
Do read the commits one at a time if you feel overwhelmed.
-
-
-
-
Modify the
StatusBarFooterto show the total number of people in the address book.Before
After
-
Hints
-
StatusBarFooter.fxmlwill need a newStatusBar. Be sure to set theGridPane.columnIndexproperly for eachStatusBarto avoid misalignment! -
StatusBarFooterneeds to initialize the status bar on application start, and to update it accordingly whenever the address book is updated.
-
-
Solution
-
Modify the constructor of
StatusBarFooterto take in the number of persons when the application just started. -
Use
StatusBarFooter#handleAddressBookChangedEvent(AddressBookChangedEvent)to update the number of persons whenever there are new changes to the addressbook. -
For tests, modify
StatusBarFooterHandleby adding a state-saving functionality for the total number of people status, just like what we did for save location and sync status. -
For system tests, modify
AddressBookSystemTestto also verify the new total number of persons status bar. -
See this PR for the full solution.
-
-
Scenario: You are in charge of storage. For your next project milestone, your team plans to implement a new feature of saving the address book to the cloud. However, the current implementation of the application constantly saves the address book after the execution of each command, which is not ideal if the user is working on limited internet connection. Your team decided that the application should instead save the changes to a temporary local backup file first, and only upload to the cloud after the user closes the application. Your job is to implement a backup API for the address book storage.
|
💡
|
Do take a look at Section 3.5, “Storage Component” before attempting to modify the Storage component.
|
-
Add a new method
backupAddressBook(ReadOnlyAddressBook), so that the address book can be saved in a fixed temporary location.-
Hint
-
Add the API method in
AddressBookStorageinterface. -
Implement the logic in
StorageManagerandXmlAddressBookStorageclass.
-
-
Solution
-
See this PR for the full solution.
-
-
By creating this command, you will get a chance to learn how to implement a feature end-to-end, touching all major components of the app.
Scenario: You are a software maintainer for addressbook, as the former developer team has moved on to new projects. The current users of your application have a list of new feature requests that they hope the software will eventually have. The most popular request is to allow adding additional comments/notes about a particular contact, by providing a flexible remark field for each contact, rather than relying on tags alone. After designing the specification for the remark command, you are convinced that this feature is worth implementing. Your job is to implement the remark command.
Edits the remark for a person specified in the INDEX.
Format: remark INDEX r/[REMARK]
Examples:
-
remark 1 r/Likes to drink coffee.
Edits the remark for the first person toLikes to drink coffee. -
remark 1 r/
Removes the remark for the first person.
Let’s start by teaching the application how to parse a remark command. We will add the logic of remark later.
Main:
-
Add a
RemarkCommandthat extendsCommand. Upon execution, it should just throw anException. -
Modify
AddressBookParserto accept aRemarkCommand.
Tests:
-
Add
RemarkCommandTestthat tests thatexecute()throws an Exception. -
Add new test method to
AddressBookParserTest, which tests that typing "remark" returns an instance ofRemarkCommand.
Let’s teach the application to parse arguments that our remark command will accept. E.g. 1 r/Likes to drink coffee.
Main:
-
Modify
RemarkCommandto take in anIndexandStringand print those two parameters as the error message. -
Add
RemarkCommandParserthat knows how to parse two arguments, one index and one with prefix 'r/'. -
Modify
AddressBookParserto use the newly implementedRemarkCommandParser.
Tests:
-
Modify
RemarkCommandTestto test theRemarkCommand#equals()method. -
Add
RemarkCommandParserTestthat tests different boundary values forRemarkCommandParser. -
Modify
AddressBookParserTestto test that the correct command is generated according to the user input.
Let’s add a placeholder on all our PersonCard s to display a remark for each person later.
Main:
-
Add a
Labelwith any random text insidePersonListCard.fxml. -
Add FXML annotation in
PersonCardto tie the variable to the actual label.
Tests:
-
Modify
PersonCardHandleso that future tests can read the contents of the remark label.
We have to properly encapsulate the remark in our Person class. Instead of just using a String, let’s follow the conventional class structure that the codebase already uses by adding a Remark class.
Main:
-
Add
Remarkto model component (you can copy fromAddress, remove the regex and change the names accordingly). -
Modify
RemarkCommandto now take in aRemarkinstead of aString.
Tests:
-
Add test for
Remark, to test theRemark#equals()method.
Now we have the Remark class, we need to actually use it inside Person.
Main:
-
Add
getRemark()inPerson. -
You may assume that the user will not be able to use the
addandeditcommands to modify the remarks field (i.e. the person will be created without a remark). -
Modify
SampleDataUtilto add remarks for the sample data (delete yourhealthbook.xmlso that the application will load the sample data when you launch it.)
We now have Remark s for Person s, but they will be gone when we exit the application. Let’s modify XmlAdaptedPerson to include a Remark field so that it will be saved.
Main:
-
Add a new Xml field for
Remark.
Tests:
-
Fix
invalidAndValidPersonAddressBook.xml,typicalPersonsAddressBook.xml,validAddressBook.xmletc., such that the XML tests will not fail due to a missing<remark>element.
Since Person can now have a Remark, we should add a helper method to PersonBuilder, so that users are able to create remarks when building a Person.
Tests:
-
Add a new method
withRemark()forPersonBuilder. This method will create a newRemarkfor the person that it is currently building. -
Try and use the method on any sample
PersoninTypicalPersons.
Our remark label in PersonCard is still a placeholder. Let’s bring it to life by binding it with the actual remark field.
Main:
-
Modify
PersonCard's constructor to bind theRemarkfield to thePerson's remark.
Tests:
-
Modify
GuiTestAssert#assertCardDisplaysPerson(…)so that it will compare the now-functioning remark label.
We now have everything set up… but we still can’t modify the remarks. Let’s finish it up by adding in actual logic for our remark command.
Main:
-
Replace the logic in
RemarkCommand#execute()(that currently just throws anException), with the actual logic to modify the remarks of a person.
Tests:
-
Update
RemarkCommandTestto test that theexecute()logic works.
See this PR for the step-by-step solution.
Health Book is an address book application that is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place. Command Line Interface is utilized mainly for the input, while GUI is used mainly to display the output. By combining these 2 interfaces, Health Book aims to provide healthcare professionals with the speed and efficiency obtained from a CLI while retaining the systematic view of information through the GUI.
Target user profile: Health Book is catered for healthcare professionals who seek to retrieve their patients’ personal information and health-related information all in one place.
-
has a need to manage a significant number of patients
-
prefer desktop apps over other types
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: With many patients to attend to, healthcare professionals need to focus much of their attention and care on their patients and less on administrative matters. Health Book is a one-stop application for healthcare professionals to create, read, update or delete (CRUD) patient’s information, reducing the need for long and troublesome paperwork and simplifying administrative work.
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
|
doctor |
see usage instructions |
refer to instructions when I forget how to use the App |
|
doctor |
add, edit, and delete patients and their medical information |
keep track of my patients and not prescribe them the wrong medication |
|
doctor |
find a patient by name |
locate details of patients without having to go through the entire list |
|
doctor |
filter out patients by certain personal details |
saves time in contacting patients with desired personal details |
|
doctor |
filter out patients by certain medical details |
saves time in administering patients with desired medical details |
|
doctor |
sort patients by patient details by lexicographical order |
goes through the patient list which is listed systematic manner to facilitate administration |
|
doctor |
have a platform to view my patients' past medical history |
compare with their current symptoms to predict future health risks |
|
doctor |
know my patient’s drug allergy if he/she has any |
prescribe the drugs without causing other medical conditions |
|
doctor |
know if there is any follow-up actions for a particular patient, or if the medical case for the patient has closed |
know if the patient has been discharged |
|
doctor |
have a sorted list of all my patients in terms of their personal particulars/medical information (allergies, blood type, address, last visited country) and past medical history |
assess them more quickly and easily, and understand the past medical issues that my patients faced |
|
doctor |
see all my patient’s appointments if there is any |
remind my patients to come for appointments days in advance |
|
doctor |
manage my patient’s appointments and add, edit or delete appointments |
track their appointments and ensure there are no scheduling clashes |
|
doctor |
add a list of medical reports for every patient |
refer to them in the future for medicine prescription |
|
doctor |
edit a patient’s medical report |
rectify any mistakes made in the medical report |
|
doctor |
have an inventory list |
keep track and replenish stocks |
|
doctor |
have image functionality in the feature (medical history) |
view X-rays and scans where applicable to provide better diagnosis |
|
doctor |
rank patients’ past illnesses in terms of severity (medical history) |
efficiently perform certain checkups to ensure their condition is kept in check |
|
doctor |
be able to see all appointments for the day and how many people have appointments |
I can schedule appointments easily when people call in and request for an appointment, I can schedule them an empty timeslot |
|
doctor |
be able to see where patients live on a map |
I can do house visits easily and deliver medication to them |
|
doctor |
see the patients' prescriptions given to them by previous doctors they have visited for each entry in their medical history (medical history) |
understand how their medical condition is based on medication taken |
|
doctor |
encrypt all my patients’ info |
my patients’ data will be protected from hackers |
|
doctor |
import/export files to other computers |
send patients’ data to other hospitals if the patient transfers there |
(For all use cases below, the System is the Health Book, unless specified otherwise)
MSS
-
User requests to see a list of available commands.
-
System displays the list of commands that the user can enter.
Use case ends.
MSS
-
User requests to add a patient into the System.
-
System adds the patient into the System and displays a message that the addition is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to add patient.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of adding a patient.
Use case ends.
-
MSS
-
User requests to see a list of all patients in the System.
-
System shows user a list of all patients.
Use case ends.
Extensions
-
2a. List is empty.
-
2a1. System shows user a message that there are no patients entered yet and prompts user to add patient.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to edit a specific patient in the list with updated details.
-
System updates the patient’s information with the new details and displays a message that the edit is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to edit patient.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of editing a patient.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to delete a person in the list using the patient’s index.
-
System deletes the user who has that index and displays a message that deletion is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to delete patient.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of editing a patient.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User selects a patient to view his/her information.
-
System shows the information of the specified patient.
Use case ends.
Extensions
-
1a. User provides an invalid index for the list.
-
1a1. System shows an error message that the index is invalid.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to add optional information for patient.
-
System adds optional information for the patient and displays a message that entry for optional information is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to add optional information i.e. wrong command or invalid data for the fields.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of adding optional information. System will ignore invalid commands or data and process only the valid commands and data.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
Assume that user has already requested the System to display a list of medical reports for a patient.
MSS
-
User requests to add medical history for patient.
-
System edits medical history for the patient and displays a message that shows success of medical history added.
Use case ends.
Extensions
-
1a. User uses the wrong format to edit medical report.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of editing medical report.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. User provides an invalid date format in the command.
-
1c1. System shows an error message that the date format must comply with dd-MM-yyyy format.
Use case ends.
-
-
1d. User provides an invalid discharge status in the command.
-
1d1. System shows an error message that the discharge status is invalid.
Use case ends.
-
Assume that user has already requested the System to display a list of medical reports for a patient.
MSS
-
User requests to edit existing medical history for patient.
-
System edits medical history for the patient and displays a message that shows success of medical history edited.
Use case ends.
Extensions
-
1a. User uses the wrong format to edit medical report.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of editing medical report.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. User provides an invalid date format in the command.
-
1c1. System shows an error message that the date format must comply with dd-MM-yyyy format.
Use case ends.
-
-
1d. User provides an invalid discharge status in the command.
-
1d1. System shows an error message that the discharge status is invalid.
Use case ends.
-
-
1e. User targets a non-existent medical history date in the command.
-
1e1. System shows an error message that the specified date does not belong to any existing medical history.
Use case ends.
-
-
1f. User provides a new medical history date that is already present in the command.
-
1f1. System shows an error message that the specified new date already exists.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to add an appointment into patient’s schedule.
-
System adds the appointment into patient’s schedule and displays a message that the addition is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to add appointment i.e. missing fields or having invalid data for fields
-
1a1. System shows an error message that the format is wrong and gives user an example on the correct format of adding appointment.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. Patient’s schedule already has an appointment which overlaps with the new appointment in terms of timing.
-
1c1. System shows an error message that there is a timing clash between the new appointment and another appointment already in the patient’s schedule.
Use case ends.
-
-
1d. User enters an appointment with the end date and time before or equal to the start date and time.
-
1d1. System shows an error message that the end date and time for an appointment needs to be after the start date and time.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to edit an appointment in the patient’s schedule with new details.
-
System updates the appointment in the patient’s schedule with the new details and displays a message that edit is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to edit appointment i.e. missing all fields or having invalid data for fields
-
1a1. System shows an error message that the format is wrong and gives user an example on the correct format of editing appointment.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. Patient’s schedule already has an appointment which overlaps with the new appointment in terms of timing.
-
1c1. System shows an error message that there is a timing clash between the new appointment and another appointment already in the patient’s schedule.
Use case ends.
-
-
1d. User requests to edit an appointment that does not exist for the specified patient.
-
1d1. System shows an error message that the patient does not have an appointment with the start date and time that the user is requesting to edit.
Use case ends.
-
-
1e. User edits an appointment to have the end date and time before or equal to the start date and time.
-
1e1. System shows an error message that the end date and time for an appointment needs to be after the start date and time.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to delete an appointment in the patient’s schedule.
-
System deletes the appointment in the patient’s schedule and displays a message that deletion is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to delete appointment i.e. missing fields or having invalid data for fields.
-
1a1. System shows an error message that the format is wrong and gives user an example on the correct format of deleting appointment.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. User requests to delete an appointment that does not exist for the specified patient.
-
1c1. System shows an error message that the patient does not have an appointment with the start date and time that the user is requesting to delete.
Use case ends.
-
MSS
-
User requests to delete all appointments that end on or before a specific date for all patients in the health book.
-
System deletes the respective appointments for all patients and displays a message that deletion is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to clear appointments i.e. missing field or having invalid data for field.
-
1a1. System shows an error message that the format is wrong and gives user an example on the correct format of clearing appointments.
Use case ends.
-
-
1b. User requests to clear appointments that do not exist i.e. there are no appointments that end on or before the specified date.
-
1b1. System shows an error message that there are no appointments that end on or before the specified date to be deleted.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
MSS
-
User requests to add medical report for patient.
-
System adds medical report for the patient and displays a message that addition of medical report is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to add medical report.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of adding medical report.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. User provides an invalid title or information format in the command.
-
1c1. System shows an error message that the title or information format can take any values and must not be blank.
Use case ends.
-
-
1d. User provides an invalid date format in the command.
-
1d1. System shows an error message that the date format must comply with dd-MM-yyyy format.
Use case ends.
-
-
1e. User tries to add a medical report with the same title and date of an existing medical report.
-
1e1. System shows an error message that there already exists a medical report with the same title and date.
Use case ends.
-
Assume that user has already requested the System to display a list of medical reports for a patient.
MSS
-
User requests to edit medical report for patient.
-
System edits medical report for the patient and displays a message that edit of medical report is successful.
Use case ends.
Extensions
-
1a. User uses the wrong format to edit medical report.
-
1a1. System shows error message that format is wrong and gives user an example on the correct format of editing medical report.
Use case ends.
-
-
1b. User provides an invalid index for the list.
-
1b1. System shows an error message that the index is invalid.
Use case ends.
-
-
1c. User provides an invalid title or information format in the command.
-
1c1. System shows an error message that the title or information format can take any values and must not be blank.
Use case ends.
-
-
1d. User provides an invalid date format in the command.
-
1d1. System shows an error message that the date format must comply with dd-MM-yyyy format.
Use case ends.
-
-
1e. User tries to edit a medical report to one which has the same title and date of an existing medical report.
-
1e1. System shows an error message that there already exists a medical report with the same title and date.
Use case ends.
-
MSS
-
User requests to filter patients in the list by a category. (eg. name, phone, blood type, medical information)
-
System shows user a list of patients who are in requested category.
Use case ends.
Extensions
-
1a. User uses the wrong format to find patient (i.e. Keying in the wrong parameters after "find")".
-
1a1. System shows error message that format is wrong and shows correct format of finding patients.
Use case ends.
-
-
1b. User provides an category where the prefix to the category is not available i.e. "z/"
-
1b1. System shows an error message that category is invalid and shows correct format with available prefixes.
Use case ends.
-
-
1c. User provides keyword that does not correspond to any patient.
-
1c1. System shows an error message that such patient does not exist.
Use case ends.
-
-
1d. User did not provide a category or a keyword.
-
1d1. System shows an error message that the format is wrong and shows correct format of finding a patient.
Use case ends.
-
Assume that user has already requested the System to display a list of patients.
|
ℹ️
|
This list refers to the latest list displayed on the interface before the command execution. |
MSS
-
User requests to sort the patients by a category and order.
-
System displays a sorted list (by specified order) of the patients and displays a message that the list is successfully sorted.
Use case ends.
Extensions
-
1a. User uses the wrong format to sort patient. (i.e. entering "sort" without any parameters.)
-
1a1. System shows error message that format is wrong and shows correct format of sorting patients.
Use case ends.
-
-
1b. User chooses to sort by a category which the prefix of the category does not exist (i.e. the prefix does not exist or correspond to any category ie “z/”).
-
1b1. System shows error message that prefix is wrong.
Use case ends.
-
-
1c. User inputs an invalid order index (i.e. values that are not 1 or 2).
-
1c1. System shows an error message that the order index does not exist.
Use case ends.
-
-
1d. User chooses to sort by a patients' NRIC by either order but none of the patients have the NRIC field filled.
-
1d1. System shows the original list of patients without sorting anything.
Use case ends.
-
-
1e. User chooses to sort by a patients' NRIC by alphabetical order but only some patients have the NRIC field filled.
-
1e1. System shows a list where patients with empty NRIC fields will be at the top and patients with NRIC filled will be sorted accordingly below the former patients.
Use case ends.
-
Assume that user has launched the application with the default settings (encryption toggled off).
MSS
-
User requests to toggle on encryption.
-
User makes some changes to the patient data.
-
User requests to exit the application.
-
System encrypts patient data.
-
System removes unencrypted patient data.
-
System exits.
Use case ends.
Extensions
-
4a. System unable to encrypt the data.
-
4a1. System logs this anomaly and saves the unencrypted data.
Use case ends.
-
-
Should work on any mainstream OS as long as it has Java
9or higher installed. -
Should work on both 32-bit and 64-bit environments.
-
Should be able to store up to 1000 patients' information without a noticeable sluggishness in performance for typical usage.
-
System data is only stored locally and not on the cloud.
-
The layout of the system will be simple and understandable by even doctors who are not proficient with computer systems.
-
Data encryption can be toggled based on user’s preference.
-
The product is not required to handle the printing of reports/profile pages.
The following survey was conducted on students from NUS Yong Loo Lin School of Medicine who are majoring in either Medicine, Nursing or Pharmacy.
Survey on Digital Patient Data System
-
What are some of the issues that you think health care professionals face in day to day operations?
-
Do you think that an application that is able to digitize patient data would be beneficial to healthcare professionals?
-
We are intending to build an app that allows healthcare professionals to manage their patients more efficiently. What do you think of the following features?
-
Map that indicates patients' home address
-
Medication history
-
Medical history
-
Appointment timetable
-
-
What would be your main concern for using such an application?
-
What are some important patient information that you would want to be included in such an application?
Given below are instructions to test the app manually.
|
ℹ️
|
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
-
Deleting a person while all persons are listed
-
Prerequisites: List all persons using the
listcommand. Multiple persons in the list. -
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. -
Test case:
delete 0
Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete,delete x(where x is larger than the list size) {give more}
Expected: Similar to previous.
-
-
Adding a additional information (NRIC, Date of Birth, Height, Weight, Gender, Blood Type, Occupation and Marital Status) are listed.
-
Prerequisites: List all persons using the
listcommand. Multiple persons in the list. -
Test case:
addinfo 2 i/S9696531A d/01-01-1990 h/154 w/75.6 g/M b/A+ o/Teacher m/M
Expected: Additional information where NRIC is S9696531A, date of birth is 01-01-1990, height of 154 cm, weight of 75.6 kg, gender Male, blood type A+, occupation is Teacher and marital status is married is added to person at index 1. Message of additional info being successfully added is shown. -
Test case:
addinfo 0 i/S9696531A d/01-01-1990 h/154 w/75.6 g/M b/A+ o/Teacher m/M
Expected: No additional information is added. Message of invalid command format is shown. -
Test case:
addinfo 1 nric/S9696531A d/01-01-1996+ Expected: No additional information is added. Message of invalid command format is shown. -
Test case:
addinfo 1 i/A0123456E
Expected: No additional information is added. Message of constraint of NRIC is shown. -
Test case:
addinfo 1 i/S1234567A
Expected: No additional infomation is added. Message of incorrect NRIC is shown. -
Test case:
addinfo 1 d/01/01/2010
Expected: No additional infomation is added. Message of correct date format is shown -
Test case:
addinfo 1 d/DD-01-2010where DD is more than the total number of days for that month and less than 1
Expected: No additional infomation is added. Message of invalid value for day is shown -
Test case:
addinfo 1 d/01-MM-2010where MM is more than 12 and less than 1
Expected: No additional infomation is added. Message of invalid value for month is shown -
Test case:
addinfo 1 d/01-01-YYYYwhere YYYY is less than 1900
Expected: No additional infomation is added. Message of year should be greater than 1900 is shown. -
Test case:
addinfo 1 h/xwhere x is any non floating or integer input
Expected: No additional infomation is added. Message of height should be numeric input only is shown. -
Test case:
addinfo 1 w/xwhere x is any non floating or integer input
Expected: No additional infomation is added. Message of weight should be numeric input only is shown. -
Test case:
addinfo 1 g/xwhere x is any input other than M or F
Expected: No additional infomation is added. Message of correct gender input is shown. -
Test case:
addinfo 1 b/xwhere x is any input other than the correct blood types
Expected: No additional infomation is added. Message of correct blood type is shown. -
Test case:
addinfo 1 o/xwhere x is a String with whitespace, special characters or numerals
Expected: No additional infomation is added. Message of correct blood type is shown. -
Test case:
addinfo 1 m/xwhere x is any input other than S, M or D
Expected: No additional infomation is added. Message of correct marital status input is shown.
-
-
Adding an appointment to a patient while all patients are listed
-
Prerequisites: List all patients using the
listcommand. Multiple patients in the list. Ensure that the first patient does not have any appointments. -
Test case:
addappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
Expected: An appointment from 16-09-2018 15:00 to 16-09-2018 15:30 at Consultation Room 12 for a Diabetes Checkup by Dr Tan is added to the patient at index 1 in the list. A message that the appointment is successfully added is shown. -
Test case:
addappt 0 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
Expected: No appointment is added to any patient. An error message is shown telling the user that he/she has used the invalid command format, along with the correct command format foraddappt. -
Other incorrect
addapptcommands to try:addappt,addappt x(where x is any integer),addappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30
Expected: Similar to previous. -
Test case:
addappt x s/16-09-2018 17:00 e/16-09-2018 17:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan(where x is larger than the list size)
Expected: No appointment is added to any patient. An error message is shown telling the user that the index provided is invalid. -
Test case:
addappt 1 s/16/09/2018 18:00 e/16/09/2018 17:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
Expected: No appointment is added to any patient. An error message is shown telling the user that the date and time must be DD-MM-YYYY HH:MM. -
Test case:
addappt 1 s/16-09-2018 18:00 e/16-09-2018 17:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
Expected: No appointment is added to any patient. An error message is shown telling the user that the end date and time of an appointment must be after the start date and time.
-
-
Adding an appointment to a patient with existing appointments
-
Prerequisites: List all patients using the
listcommand. Multiple patients in the list. Ensure that the first patient does not have any appointments.
Add an appointment to the first patient using the commandaddappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
Test case:
addappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
Expected: No appointment is added to any patient. An error message is shown telling the user that the appointment he/she is adding clashes with the timing of another appointment for the patient. -
Test case:
addappt 1 s/16-09-2018 15:30 e/16-09-2018 16:00 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
Expected: An appointment from 16-09-2018 15:30 to 16-09-2018 16:00 at Consultation Room 12 for a Diabetes Checkup by Dr Tan is added to the patient at index 1 in the list. A message that the appointment is successfully added is shown.
-
-
Editing an appointment for a patient while all patients are listed
-
Prerequisites: List all patients using the
listcommand. Multiple persons in the list. Ensure that the first patient does not have any appointments.
Add 2 appointments to the first person using the following 2 commands:-
addappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tanand -
addappt 1 s/16-09-2018 16:00 e/16-09-2018 16:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
-
-
Test case:
editappt 0 os/16-09-2018 15:00 s/16-09-2018 14:00 e/16-09-2018 14:30 v/Consultation Room 13
Expected: No appointment is edited. An error message is shown telling the user that he/she has used the invalid command format, along with the correct command format foreditappt. -
Other incorrect
editapptcommands to try:editappt,editappt x(where x is any integer),editappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30
Expected: Similar to previous. -
Test case:
editappt 1 os/16-09-2018 15:00
Expected: No appointment is updated. An error message is shown telling the user that at least one field to edit must be provided. -
Test case:
editappt 1 os/16-09-2018 15:00 e/16-09-2018 14:30 v/Consultation Room 13
Expected: No appointment is updated. An error message is shown telling the user that the end date and time of an appointment must be after the start date and time. -
Test case:
editappt 1 os/16-09-2018 15:00 s/16-09-2018 15:30 e/16-09-2018 16:15 v/Consultation Room 13
Expected: No appointment is updated. An error message is shown telling the user that the appointment he/she is editing will clash with the timing of another appointment for the patient. -
Test case:
editappt 1 os/17-09-2018 15:00 s/16-09-2018 14:00 e/16-09-2018 14:30 v/Consultation Room 13
Expected: No appointment is updated. An error message is shown telling the user that the appointment he/she is trying to edit cannot be found for the patient. -
Test case:
editappt 1 os/16-09-2018 15:00 s/16-09-2018 14:00 e/16-09-2018 14:30 v/Consultation Room 13
Expected: The appointment originally starting at 16-09-2018 15:00 is now edited to start at 16-09-2018 14:00, end at 16-09-2018 14:30, and be held at Consultation Room 13 instead. A message that the appointment is successfully edited is shown.
-
-
Deleting an appointment for a patient while all patients are listed
-
Prerequisites: List all patients using the
listcommand. Multiple patients in the list. Ensure that the first patient does not have any appointments.
Add an appointment to the first patient using the commandaddappt 1 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
Test case:
deleteappt 0 s/16-09-2018 15:00
Expected: No appointment is deleted. An error message is shown telling the user that he/she has used the invalid command format, along with the correct command format fordeleteappt. -
Other incorrect
deleteapptcommands to try:deleteappt,deleteappt x(where x is any integer)
Expected: Similar to previous. -
Test case:
deleteappt 1 s/17-09-2018 15:00
Expected: No appointment is deleted. An error message is shown telling the user that the appointment he/she is trying to delete cannot be found for the patient. -
Test case:
deleteappt 1 s/16-09-2018 15:00
Expected: The appointment starting at 16-09-2018 15:00 will be deleted. A message that the appointment is successfully deleted is shown.
-
-
Clearing appointments for all patients while all patients are listed
-
Prerequisites: List all patients using the
listcommand. Multiple patients in the list. Ensure that the first 3 patients do not have any appointments.
Add 2 appointments each to the first 3 patients using the following 6 commands:-
addappt 1 s/15-09-2018 15:00 e/15-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
addappt 1 s/17-09-2018 15:00 e/17-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
addappt 2 s/16-09-2018 15:00 e/16-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
addappt 2 s/17-09-2018 15:00 e/17-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
addappt 3 s/14-09-2018 15:00 e/14-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan -
addappt 3 s/17-09-2018 15:00 e/17-09-2018 15:30 v/Consultation Room 12 i/Diabetes Checkup d/Dr Tan
-
-
Test case:
clearappts
Expected: No appointments are deleted. An error message is shown telling the user that he/she has used the invalid command format, along with the correct command format forclearappts. -
Test case:
clearappts d/16-09-2018
Expected: The appointments on 16-09-2018 and before are deleted. A message that all appointments ending before or on the specified date have been successfully deleted is shown. -
Test case:
clearappts d/16-08-2018
Expected: No appointments are deleted. An error message is shown telling the user that there are no appointments on or before the specified date to be deleted.
-
-
Adding medical history to a non-existent patient
-
Prerequisites: List all patients using the
listcommand. Any number of patients allowed in the list. -
Test case:
addhist 9999999 hsd/10-10-2010
Expected: No medical entry added to non-existent patient in the list. Error details shown in status message.
-
-
Adding medical history to existing patient
-
Prerequisites: List all patients using the list command. Any number of patients allowed in the list.
-
Test case:
addhist
Expected: FAIL
Invalid command format. Error details shown in status message which includes instructions to follow proper format. -
Test case:
addhist 1 hsd/24/08/1993 hsa/Alcohol hsc/Kuwait hsds/d
Expected: FAIL
Medical History not added due to wrong date format. Error details shown in status message. -
Test case:
addhist 1 hsd/24-08-1111 hsa/Alcohol hsc/Kuwait hsds/w
Expected: FAIL
Medical History only supports dates after year 1900. Error details shown in status message. -
Test case:
addhist 1 hsd/24-08-2222 hsa/Alcohol hsc/Kuwait hsds/d
Expected: FAIL
Medical History only supports dates today and before today. This updates with real time. Error details shown in status message. -
Test case:
addhist 1 hsd/24-08-1993 hsa/Alcohol hsc/Kuwait hsds/w
Expected: FAIL
Invalid Discharge Status. Error details specifies valid discharge status for users to use. -
Test case:
addhist 1 hsd/08-11-2018 hsa/Alcohol hsc/Kuwait hsds/d
Expected: PASS
Medical History entered for first patient on the list with date of 08-11-2018, alcohol allergy, Kuwait as last country visited and is currently discharged.
-
-
Editing medical history to a non-existent patient
-
Prerequisites: List all patients using the
listcommand. Any number of patients allowed in the list. -
Test case:
edithist 9999999 hsod/11-11-2011 hsd/10-10-2010
Expected: FAIL
No medical entry added to non-existent patient in the list. Error details shown in status message.
-
-
Editing medical history to existing patient
-
Prerequisites: List all patients using the
listcommand. Any number of patients allowed in the list. -
Test case:
edithist 1 hsod/10-10-2010 hsd/20-05-2011 hsa/grass hsc/Canada hsds/e
Expected: FAIL
If Medical History entry with date 10-10-2010 does not exist, error details will be shown in status message. -
Test case:
edithist 1 hsod/20-05-2011 hsd/08-11-2018 hsa/grass hsc/Canada hsds/e
Expected: FAIL
If new date specified of Medical History to be edited already exists, error details will be shown in status message. -
Test case:
edithist 1 hsod/12-12-2012 hsd/05-05-2015 hsa/grass hsc/Canada hsds/e
Expected: PASS
If previous Medical History entry exists, and new date specified is not used, the entry chosen will be edited with new date 05-05-2015, new allergy of grass and new previous country visited as Canada and the patient has expired. -
Test case:
edithist 1 hsod/12-12-2012 hsd/12-12-2012 hsds/d
Expected: PASS
If previous Medical History entry exists, discharge status will be updated to discharged. However, current implementation does not auto refresh the discharge status for the entry. Users are required to click on the personcard to manually refresh the infopanel.
-
-
Adding a medical report to a person while all persons are listed.
-
Prerequisites: List all persons using the
listcommand. Multiple persons in the list. -
Test case:
addreport 1 t/Asthma d/01-01-2018 i/Prescribed XXX medicine, next appointment on 02-02-2018.
Expected: Medical report titled Asthma and dated 01-01-2018 with report information is added to person at index 1. Message of medical report being successfully added is shown. -
Test case:
addreport 0 t/Asthma d/01-01-2018 i/Prescribed XXX medicine, next appointment on 02-02-2018.
Expected: No medical report is added. Message of invalid command format will be shown. -
Other incorrect addreport commands to try:
addreport,addreport x(where x is smaller than or equal to the list size)
Expected: Similar to previous. -
Test case:
addreport x (where x is larger than the list size) t/Asthma d/01-01-2018 i/Prescribed XXX medicine, next appointment on 02-02-2018.
Expected: No medical report is added. Message of invalid person index will be shown. -
Test case:
addreport 1 t/ d/01-01-2018 i/prescribed XXX medicine, next appointment on 02-02-2018.Expected: No medical report is added. Message of invalid title will be shown. -
Test case:
addreport 1 t/Asthma d/01012018 i/prescribed XXX medicine, next appointment on 02-02-2018.Expected: No medical report is added. Message of invalid date will be shown. -
Test case: `addreport 1 t/Asthma d/01-01-2018 i/ ` Expected: No medical report is added. Message of invalid information will be shown.
-
-
Editing an existing medical report of a person while all persons are listed.
-
Prerequisites: At least one person in the list must have a medical report added. Two medical reports titled Asthma, dated 01-01-2018 and titled Depression, dated 02-02-2018 with report information have been added to person at index 1.
-
Test case:
editreport 1 ot/Asthma od/01-01-2018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment is on 03-03-2018.
Expected: Existing medical report titled Asthma and dated 01-01-2018 is edited for person at index 1. Message of medical report being successfully edited is shown. -
Test case:
editreport 0 ot/Asthma od/01-01-2018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment is on 03-03-2018.
Expected: No medical report is edited. Message of invalid command format will be shown. -
Other incorrect editreport commands to try:
editreport,editreport x(where x is smaller than or equal to the list size)
Expected: Similar to previous. -
Test case:
editreport x (where x is larger than the list size) ot/Asthma od/01-01-2018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment is on 03-03-2018.
Expected: No medical report is edited. Message of invalid person index will be shown. -
Test case:
editreport 1 ot/ od/01-01-2018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment is on 03-03-2018.
Expected: No medical report is edited. Message of invalid title will be shown. -
Test case:
editreport 1 ot/Asthma od/01012018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment is on 03-03-2018.
Expected: No medical report is edited. Message of invalid date will be shown. -
Test case: `editreport 1 ot/Asthma od/01-01-2018 t/Depression d/02-02-2018 i/ `
Expected: No medical report is edited. Message of invalid information will be shown. -
Test case:
editreport 1 ot/Flu od/03-03-2018 t/Cough d/03-03-2018 i/Prescribed AAA medicine, next appointment is on 04-04-2018.
Expected: No medical report is edited. Message of medical report not found will be shown. -
Test case:
editreport 1 ot/Asthma od/01-01-2018 t/Depression d/02-02-2018 i/Prescribed AAA medicine, next appointment is on 03-03-2018.
Expected: No medical report is edited. Message of unable to edit existing report with the same title and date will be shown.
-
-
Finding patients through specific categories while all patients are listed.
-
Test case:
find n/
Expected: The patient list remains the same, message of invalid format will be shown. -
Test case:
find n/ alex
Expected: Patient list will display Alex Yeoh’s profile with success message. -
Test case: `find z/ `
Expected: The patient list remains the same, message of invalid format will be shown. -
Test case:
find z/ peanut
Expected: The patient list remains the same, message of invalid prefix will be shown.
-
-
Sorting patients through specific categories in specific order while all/some patients are listed.
-
Test case:
sort n/
Expected: The patient list remains the same, message of invalid format will be shown. -
Test case:
sort n/ 1
Expected: Patient list will display sorted patients by name in alphabetical order with success message. -
Test case: `sort z/ `
Expected: The patient list remains the same, message of invalid format will be shown. -
Test case:
sort z/ 1
Expected: The patient list remains the same, message of invalid prefix will be shown. -
Test case:
sort n/ 3
Expected: The patient list remains the same, message of invalid order will be shown. -
Test case:
sort z/ 3
Expected: The patient list remains the same, message of invalid order will be shown. -
Test case:
sort ic/ 1
Expected: Patients with empty NRIC field will be at the top of the list while rest will be sorted by alphabetical order. -
Test case:
sort ic/ 2
Expected: Patients with empty NRIC field will be at the bottom of the list while rest will be sorted by reverse order.
-
-
Sorting patients through specific categories in specific order while all/some patients are listed.
|
ℹ️
|
Place the .jar file in a newly created directory before executing the following test case.
|
-
Test case:
encrypt, followed by making some changes to address book, followed byexit
Expected:healthbook_encrypted.xmlandkeyshould be generated in/datafolder. Open uphealthbook_encrypted.xmlfile to check that the file indeed contains cipher text.
|
ℹ️
|
Only execute the following test case after the previous test case |
-
Test case:
encrypt, followed by making some changes to address book, followed byexit
Expected:healthbook_encrypted.xmlandkeyshould have been removed.healthbook.xmlshould be generated. Open up thehealthbook.xmlto check that the file contains patient data in plain text.































