Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
Acknowledgements
- {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries – include links to the original source as well}
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
![:bulb: :bulb:](https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png)
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
has two classes called Main
and 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 methods where necessary.
Commons
represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command rm 1
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point).
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
andTask
objects residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses theAddressBookParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add a person). - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("rm 1")
API call.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
AddressBookParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddCommand
) which theAddressBookParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the address book data i.e., all
Person
objects (which are contained in aUniquePersonList
object). - stores the currently ‘selected’
Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<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. - stores the previous user input into the
UserCommandCache
- stores a
TaskListManager
object which is responsible for managing task display operations. It maintains aName
object of the person whose tasks are currently displayed. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
Tag
list in the AddressBook
, which Person
references. This allows AddressBook
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.![](images/BetterModelClassDiagram.png)
Storage component
API : Storage.java
The Storage
component,
- can save both address book data and user preference data in json format, and read them back into corresponding objects.
- inherits from both
AddressBookStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.addressbook.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
View Task list feature
Displays the task list associated to the specified person onto the taskListPanel
of the GUI.
The view task list feature is facilitated by :
TaskListManager
:
- It serves as a archive to track the task lists reference of every
Person
. -
It maintains an
ObservableList
which encapsulates aPerson
’s task list, and is referenced by theUI
for display on the GUI. - It implements the following operation that support the view task list feature:
-
TaskListManager#setToDisplayTaskList
— set the currently displayed task list to the task list of the specified person.
-
This operation is exposed in the Model
interface as Model#displayPersonTaskList
.
Given below is the example usage scenario:
Step 1. The user launches the ContactSh application. Data will be loaded from the storage to the application memory. The TaskListManager
will populate itself with the references of every Person
’s task list.
Step 2. The user executes cat 2
command to view the task list of the 2nd Person
that is shown on the currently displayed person list.
step 3. If the parameters entered by the user is valid, the application will retrieve the task list reference of the specified Person
from the archive. The task list reference currently encapsulated by the ObservableList
is cleared and is then replaced by the specified Person
’s task list reference. Else, ContactSh will display an error message indicating that the user did not type in the parameters correctly.
The following sequence diagram show how the view task list operation works:
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
cat
command:
![ViewTaskListActivityDiagram](/tp/images/ViewTaskListActivityDiagram.png)
Design consideration:
Aspect: How to display the task list on the GUI
-
Alternative 1 (current choice): Have two side-by-side panels, left for person list and right for task list.
- Pros:
- User is able to concurrently view more information.
- Cons:
- More work to create and optimize the split panel.
- Content wrapping can was tricky since there is a slider in the middle to resize either panels.
- Pros:
-
Alternative 2: Have only one panel. The person list gets replaced by task list when cat is executed.
- Pros:
- More convenient to implement.
- Cons:
-
list
has to be executed again if user wants to redirect back to the person list (extra overhead which reduces efficiency). - Lesser view of information.
-
- Pros:
Command Cache
The command Cache is the aspect of the program which stores the previous user input. This allows the user to browse through the previous input using the up and down arrow key which simulates the Linux experience.
This function is facilitated by 3 aspects of the program:
- CommandBox in GUI
- InternalCommand in Logic
- UserCommandCache in Model
Caching the command
The following sequence diagram demonstrates how the caching mechanism in the Model and Logic unit:
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
The following activity diagram illustrates how the storage in the cache is handled:
With the current iteration, the cache may hold up to 50 most recent command. However, only the newest 25 command is guaranteed to be saved at all times. The user is not blocked from accessing older commands as it provides additional functionality without too much loss.
Accessing the Cache
As mentioned before, the caching feature utilises a different kind of command as with other features. The reason will be explored in the design consideration section. Nonetheless, both command type are handled by the Logic unit almost exactly the same way.
The diagram below shows the generation of the internal command in the GUI:
The cache, stored in the Model, is implemented using the Singleton design pattern as there should, at all times, be only one cache existing. A reset function is made for testing purposes. For this reason, cache is placed in it’s own package to ensure that only the test class are able to reset it.
Design Consideration
Aspect: Accessing cache
-
Alternative 1 : Have cache stored in model and piggyback on existing command code.
- Pros:
- A relatively simple design with less possibility of bug
- Less effort needed
- Still maintain cohesion and separation of responsibility
- Cons:
- Could not differentiate between internal and external input command. This leads to either the possibility for user to input the internal commands accidentally, causing bug, or some commands being blocked from running
- Pros:
-
Alternative 2 (current choice): Have cache stored in model and create new internal command.
- Pros:
- No need for command blocking and no possibility for user to accidentally type in the command
- Still maintain cohesion and separation of responsibility
- Cons:
- Increased avenue for bugs
- More coding to be done
- Relatively worse in terms of “repeating yourself”
- Pros:
-
Alternative 3: Have cache stored in UI.
- Pros:
- No need for extraction using commands
- Simple implementation
- Cons:
- Breaks the MVC pattern as UI now saves things
- Decreased cohesion
- Pros:
Find people feature
Displays the people associated with the specified search keywords onto the PersonListPanel
of the GUI.
Given below is the example usage scenario:
Step 1. The user launches the ContactSh application. Data will be loaded from the storage to the application memory. The PersonListPanel
will be populated with a PersonCard
for every person from memory.
Step 2. The user executes find -n Alex
command to find anyone whose name could be abbreviated to be Alex
on the currently displayed person list.
Step 3. If the parameters entered by the user is valid, the application will retrieve any Person
that matches the keywords given. The person list reference currently encapsulated by the FilteredList
will then be filtered based on whether a person has an attribute that matches the keywords. The updated FilteredList
is then shown to the user with all matching persons via the PersonListPanel
. Else, ContactSh will display an error message indicating that the user did not type in the parameters correctly.
The following sequence diagram show how the find operation works:
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
The following activity diagram summarises what happens when a user executes a find -n Alex
command:
Design consideration:
Aspect: How to find based on the keywords
-
Alternative 1 (current choice): Check that the order of the keywords matches the order they appear in for any person’s attribute (e.g. name) and whether each separate word of a person’s attribute starts with the keywords, ignoring case.
- Pros: The user is able to use abbreviations for certain attributes to find people and not have to worry about exact matching
- Cons:
- The user can no longer find multiple people (using different keywords) and even if at least one of the keywords matches a person’s attribute, it will not display the person if the keywords are out of order and do not all appear in the person’s attribute.
-
Alternative 2: Use exact matching and check if any of the keywords matches a person’s attribute
-
Pros: Easier to implement.
-
Cons:
- Keywords provided must be exact, so even if the user is missing one letter, it will not display the expected person
-
Mark Tasks as done/not done feature
Marks the task specified by the user as done or not done. Tasks that are marked as done are coloured green in the tasklistpanel
. Tasks marked as done will not show up as overdue or soon to be due.
Given below is an example usage scenario:
Step 1: The user launches the ContactSH application. Data will be loaded from the storage to the application memory. The PersonListPanel
will be populated with a PersonCard
for every person from memory.
Step 2: The user executes donetask 2 -ti3
to mark the 3rd task of the second person in the list as done.
Step 3: If the specified person and their corresponding tasks exists, the tasks will be marked as done. Else, an error message will be displayed indicating that the parameters are wrong. If the tasks are already marked as done, it will not be marked again. A message will then be displayed showing how many tasks are marked as done, and how many are already marked as done.
The following sequence diagram shows how the mark task as done operation works:
The following activity diagram summarizes what happens when a user executes donetask 2 -ti3
:
The undotask
command does the opposite - it marks the specified tasks as not done. Tasks that were previously marked as done have their colour in the tasklistpanel
changed from green to orange, red or gray, depending if they are soon to be due, overdue, or neither, respectively.
Design consideration:
Aspect: How to mark tasks as done or not done
-
Alternative 1 (current choice): Have separate commands for marking a task as done or not done.
- Pros: Easy to implement, commands have singular purpose.
- Cons: Users need to be use another command to mark task as done.
-
Alternative 2: Add another flag to
edit
command to edit if a task is done or not done.- Pros: Tasks can be marked as done and edited at the same time.
- Cons: Harder to implement, more flags to take note of in the edit command.
Add new task with the same command word as add new person feature
Adds a new task to an existing person using the add
command word, similar to adding a new person.
Given below is an example usage scenario:
Step 1: The user launches the ContactSH application. Data will be loaded from the storage to the application memory. The PersonListPanel
will be populated with a PersonCard
for every person from memory.
Step 2: The user executes add 1 -tn Task
to add a new task named “Task” to the first person in the list.
Step 3: If the specified person exists, a new task named “Task” will be added to the person’s task list. Else, an error message will be displayed indicating that either the person index is invalid or the parameters given are wrong.
The following sequence diagram shows how the add task operation works:
The rm
command follows a similar operation sequence. Users are able to delete either a person or a task using the same rm
command word.
The following activity diagram summarizes what happens when a user executes add 1 -tn Task
:
Design consideration:
Aspect: How to either add a new person or task using the same add
command word
-
Alternative 1 (current choice): If the command is to add a new task, invoke
AddTaskCommandParser
fromAddCommandParser
, returning aAddTaskCommand
. Else if the command is to add a new person, return aAddCommand
directly fromAddCommandParser
.- Pros:
- Commands encapsulate the exact command to execute.
- Easier to debug if either command demonstrates erroneous behaviour.
- Cons:
- More testing needed to ensure correct integration.
- More coding to be done.
- Pros:
-
Alternative 2: Handle all commands to add either a new person or task in the same
AddCommandParser
andAddCommand
.- Pros:
- Simple implementation.
- Less effort needed.
- Cons:
- Increased avenue for bugs.
- Pros:
[Proposed] Undo/redo feature
Proposed Implementation
The proposed undo/redo mechanism is facilitated by VersionedAddressBook
. It extends AddressBook
with an undo/redo history, stored internally as an addressBookStateList
and currentStatePointer
. Additionally, it implements the following operations:
-
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 rm 5
command to delete the 5th person in the address book. The rm
command calls Model#commitAddressBook()
, causing the modified state of the address book after the rm 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
.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
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.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
currentStatePointer
is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The undo
command uses Model#canUndoAddressBook()
to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
The following sequence diagram shows how the undo operation works:
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
UndoCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The redo
command does the opposite — it calls Model#redoAddressBook()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the address book to that state.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
currentStatePointer
is at index addressBookStateList.size() - 1
, pointing to the latest address book state, then there are no undone AddressBook states to restore. The redo
command uses Model#canRedoAddressBook()
to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
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. Reason: 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:
Design considerations:
Aspect: How undo & redo executes:
-
Alternative 1 (current choice): Saves the entire address book.
- Pros: Easy to implement.
- Cons: May have performance issues in terms of memory usage.
-
Alternative 2: Individual command knows how to undo/redo by
itself.
- Pros: Will use less memory (e.g. for
rm
, just save the person being deleted). - Cons: We must ensure that the implementation of each individual command are correct.
- Pros: Will use less memory (e.g. for
{more aspects and alternatives to be added}
[Proposed] Data archiving
{Explain here how the data archiving feature will be implemented}
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- NUS Student Entrepreneurs
- Proficient in Linux style CLIs
- Has many meetings and is in contact with different people (students, mentors, stakeholders, clients, partners)
- Carries Laptop around (prefers Laptop)
Value proposition:
- Users familiar with Unix commands can quickly master using the app efficiently.
- Allow users to keep track of tasks/meetings associated with contacts.
- Enhanced contact searchability and organisation.
- Eliminates the need to remember and recall interpersonal details of contacts.
User stories
* * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
![:memo: :memo:](https://github.githubassets.com/images/icons/emoji/unicode/1f4dd.png)
epics
.
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
general user | have essential functionalities | ||
*** |
general user | update contact details | keep track of up to date details |
*** |
general user | delete contacts | get rid of contacts who are no longer relevant |
*** |
general user | save contacts | keep track of them |
*** |
general user | look through the list of contacts | see the contacts I have added |
new user | start using the app normally as soon as possible | ||
*** |
new user | purge all example contacts | start adding my own contacts |
Linux CLI user | have a CLI similar to Linux CLI | ||
*** |
Linux CLI user | use similar commands to Linux CLI | reduce the need to learn new commands |
*** |
Linux CLI user | backtrack commands i have entered before | save time on retyping them |
student entrepreneur | categorize my business contacts | organize them better | |
** |
student entrepreneur | differentiate between business and student contacts | differentiate easily |
* |
student entrepreneur | organise my contacts according to specific groups | find the ones i want easily |
** |
student entrepreneur | mark my contacts as important | know which contacts i prioritize |
student entrepreneur | have statistics and indicators for my tasks | improve my tasks management | |
** |
student entrepreneur | view the overall statistics of all my tasks | have an idea of my tasks progression |
** |
student entrepreneur | be reminded when tasks are due or due soon | be aware and take necessary actions to deal with them |
beginner user | learn how to use the app fast | spend less time on learning | |
*** |
beginner user | view the user guide easily | learn the commands as and when I need |
*** |
beginner user | view the list of instructions | know what instructions are available |
*** |
beginner user | see examples of contacts | have an idea of how contacts will be presented |
intermediate user | sort and filter my contacts | sieve out irrelevant contacts | |
*** |
intermediate user | search for contacts with the attribute of my choice | find my contacts faster and more accurately |
** |
intermediate user | sort contacts by tasks | identify connections between contacts |
* |
intermediate user | choose what information about my contacts to view | read the information easier |
** |
intermediate user | search for contacts using abbreviations | improve my work efficiency |
intermediate user | keep track of tasks related to my contacts | ||
*** |
intermediate user | assign tasks to contacts | know what I should contact them for |
*** |
intermediate user | delete tasks from contacts | remove task which are done |
** |
intermediate user | mark a task as complete | still keep the task but know that it has been done |
*** |
intermediate user | view tasks of a specific contact | see what tasks are connected to said contact |
*** |
intermediate user | view every contact’s tasks in a form of a list | an overview of all my tasks |
** |
intermediate user | filter what tasks i view using keywords | narrow down tasks that i am looking for |
experienced user | manipulate multiple contacts with one command | improve my work efficiency | |
** |
experienced user | delete multiple contacts using only one command | improve my work efficiency |
* |
experienced user | move multiple contacts using only one command | improve my work efficiency |
** |
experienced user | add multiple contacts using only one command | improve my work efficiency |
experienced user | update large number of contacts at once | exclude manually adding them myself | |
** |
experienced user | import a list of contacts | add a large number of contacts at once |
** |
experienced user | export a list of contacts | send them to other people |
expert Linux CLI user | use high-level CLI instructions | directly use the app at a high-level | |
* |
expert Linux CLI user | make command combinations | execute multiple instructions in one line |
* |
expert Linux CLI user | redirect input/output | input/output from/to files instead of stdin |
* |
expert Linux CLI user | create scripts | automate specific tasks |
Use cases
(For all use cases below, the System is the ContactSH
and the Actor is the user
, unless specified otherwise)
Use case: Add a contact
MSS
- User requests to add a contact.
-
ContactSH adds the contact
Use case ends.
Extensions
-
1a. The given contact is invalid.
-
1a1. ContactSH shows an error message.
Use case resumes at step 1.
-
Use case: Edit a contact
MSS
- User requests a list of contacts.
- ContactSH shows a list of contacts.
- User requests to edit a specific contact in the list.
-
ContactSH edits the contact.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. ContactSH shows an error message.
Use case resumes at step 2.
-
-
3b. The given edit information is invalid.
-
3b1. ContactSH shows an error message.
Use case resumes at step 2.
-
Use case: Delete a contact
MSS
- User requests to list contacts
- ContactSH shows a list of contacts
- User requests to delete contacts in the list
-
ContactSH deletes the contact
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. ContactSH shows an error message.
Use case resumes at step 2.
-
-
3b. User requests to delete all contacts in the list.
-
3b1. ContactSH deletes all contacts in the list.
Use case ends.
-
Use case: Find contact(s) by a criterion
MSS
- User requests for contacts satisfying a criterion.
- ContactSH searches for contacts that satisfy the criterion.
-
ContactSH displays the list of contacts that satisfy the criterion.
Use case ends.
Extensions
-
1a. The given criterion is invalid.
-
1a1. ContactSH shows an error message.
Use case ends.
-
-
2a. No result matches the criterion.
-
2a1. ContactSH returns message stating no contact found.
Use case ends.
-
Use case: Find command and its usage
MSS
- User requests for a list of commands.
- ContactSH returns a list of commands.
- User requests for details of a specific command in the list.
-
ContactSH returns the details of the command.
Use case ends.
Extensions
-
3a. The given command is invalid.
- 3a1. ContactSH shows an error message.
Use case resumes at step 2.
Use case: Sort contacts by name
MSS
- User requests to sort contacts by name.
-
ContactSH returns a sorted list of contacts.
Use case ends.
Extensions
-
1a. The reverse flag is given.
- 1a1. ContactSH returns a reverse sorted list of contacts.
Use case ends.
Use case: Edit a task
MSS
- User requests for a list of contacts.
- ContactSh returns a list a contacts.
- User requests for a list of tasks of a contact.
- ContactSH returns a list of tasks of that contact.
- User provides parameters to edit tasks.
-
ContactSH edits tasks.
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
-
3a. User requests for list of tasks of all users.
-
3a1. ContactSH returns list of tasks of all users.
Use case resumes at step 5.
-
-
3b. The list is empty.
Use case ends.
-
5a. The given edit information is invalid.
-
5a1. ContactSH shows an error message.
Use case resumes at step 5.
-
{More to be added}
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- Any changes to the data should be saved permanently and automatically.
- Should be easy to learn and use at all times regardless of the user’s skill with the user interface.
- The project is expected to push deliverables according to the module schedule.
- Should be compliant with the coding standards of the module.
- Documentation for the project, such as the user and developer guides, should be effective and concise.
- Should be logging useful information and tracking sources of errors as they are identified.
- Should be easily testable from different testing approaches (e.g. Integration testing, System testing, automated functional tests, manual tests etc.)
{More to be added}
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Private contact detail: A contact detail that is not meant to be shared with others
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
Launch and shutdown
-
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.
-
-
Exiting the program
- Use
exit
or close the window to end the program.
- Use
Adding a person
-
Adding a person with description more than 500 characters long.
- Enter the following command:
add -nJohn Doe -p98765432 -ejohnd@example.com -aJohn street, block 123 -dThis is a description that is more than 500 characters long. The rest of this message is randomly padded to make up 500 characters.0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
Expected: Error message stating that description is too long.
- Enter the following command:
Deleting a person
-
Deleting a person while all persons are being shown
-
Prerequisites: List all persons using the
ls
command. Multiple persons in the list. -
Test case:
rm 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:
rm 0
Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
rm
,rm x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
-
{ more test cases … }
Deleting tasks
-
Deleting tasks of a person while the task list of that person is currently shown.
- Prerequisites:
- List all persons using the
ls
command. Multiple persons in the list. - Show the task list of the target person using the
cat
command. - Index of target person must be shown on the person list.
- Index of target task must be shown on the person List.
- Arguments are valid and compulsory parameters are provided.
- List all persons using the
- Test case:
rm 1 -ti2
Expected: 2nd task will be deleted from the list. Details of the deleted task shown in the status message.
- Prerequisites:
-
Deleting tasks of a person while the task list of another person is currently shown.
- Prerequisites:
- List all persons using the
ls
command. Multiple persons in the list. - The index of the target person must be shown on the person list.
- The task list shown must be different from the target person.
- Arguments are valid and compulsory parameters are provided.
- List all persons using the
- Test case:
rm 1 -ti2
Expected: No task will be deleted. Error details shown in the status message.
- Prerequisites:
-
Deleting a non-existent task of a person while the task list of that person is currently shown.
- Prerequisites:
- List all persons using the
ls
command. Multiple persons in the list. - The index of the target person must be shown on the person list.
- The target task index must not be within the task list shown.
- Arguments are valid and compulsory parameters are provided.
- List all persons using the
-
Test case:
rm 1 -ti100
Expected: No task will be deleted. Error details shown in the status message. - Test case:
rm 2 -ti0
Expected: No task will be deleted. Error details shown in the status message.
- Prerequisites:
Saving data
-
Dealing with missing data files
- Delete the data file located at
[JAR file location]/data/contactsh.json
. - Run the program.
Expected: A new data file with some example contacts will be created.
- Delete the data file located at
-
Dealing with corrupted data files
- Modify the data file located at
[JAR file location]/data/contactsh.json
with incorrect modifications such as replacing phone numbers with a string of alphabets. - Run the program.
Expected: The data file is replaced with an empty file, program starts with no contacts.
- Modify the data file located at