Developer Guide
Table of Contents
- Table of Contents
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
Acknowledgements
This project is created based on the AddressBook-Level3 project by the SE-EDU initiative.
Libraries used: JavaFX, Jackson, JUnit5
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.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 delete 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
object 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 fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("delete 1")
API call.
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 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).
Tag
-related classes is detailed in the class diagram in the implementation section of tagging feature.
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
)
In the event that data saved in the json file is corrupted, the Storage
component will make a copy of the
existing json file.
After the MainApp
calls JsonAddressBookStorage#readAddressBook()
, if the data is corrupted, JsonAddressBookStorage
will call the backup()
method and make a copy of the addressbook.json
. The copied file will be saved in the data
directory in a file called backup.json
.
Users will still be able to use all features available, but the existing addressbook.json
will be overwritten.
After closing the application, users are able to go into the data
directory and rectify the problem in backup.json
before copying the information into addressbook.json
.
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.
Tagging feature
Implementation
Each Person
object contains its own set of Tag
objects, and the Tag
objects are not referenced and stored by other
Person
objects, even if the same Tag
is used by multiple Person
objects. However, there is a data structure in
AddressBook
, UniqueTagList
to keep track of every unique Tag
objects used in the application, in order to
implement the command to list all existing tags. The class diagram below shows how the tagging feature is implemented
in the Model component.
Tag
Tag
objects have the following characteristics:
- A
Tag
object only has one public data member (final),tagName
ofString
object, representing the name of theTag
, which can be used to distinguish itself from otherTag
object. - The name of the
Tag
,tagName
needs to be alphanumeric (only letters and numerals are allowed). - Any two
Tag
objects are not unique if and only if theirtagName
are equal, ignoring case differences. -
Tag
objects can be sorted, and the sorted order is the natural ordering of theirtagName
, ignoring case differences.
ReadOnlyUniqueTagList
ReadOnlyUniqueTagList
is an interface that specifies the behaviour of a read-only UniqueTagList
. It is designed to
protect the data integrity of UniqueTagList
, as UniqueTagList
should only be modifiable by the AddressBook
object
and not by other objects at runtime. Therefore, UniqueTagList
only exists in AddressBook
and returns a copy of
UniqueTagList
as ReadOnlyUniqueTagList
type, in AddressBook#getUniqueTagList()
, when requested, so that the
original copy of UniqueTagList
is unmodifiable by other classes.
UniqueTagList
Due to the nature of the tagging feature implementation, UniqueTagList
is implemented such that all unique tags used
are stored and maintained in a HashMap<Tag, Integer>
, where the key set is the set of unique tags, and the value is
the occurrence frequency of each unique tag. For example, if a Tag
with a tagName
of “friends” is used twice in the
AddressBook
, then the value of the Tag
will be 2. This implementation requires the value of all the keys in the
HashMap
to be more than 0, otherwise the key should be removed. UniqueTagList
implements the following operations.
-
addTags(Set<Tag> tagsToAdd)
Adds theTag
objects inSet<Tag>
to theHashMap
. For eachTag
object, if it is not in theHashMap
, then it will be added to theHashMap
with an initial value of 1. Otherwise, the value of theTag
object will be incremented by one. The sequence diagram of this operation is shown below.
-
removeTags(Set<Tag> tagsToRemove)
Removes theTag
objects inSet<Tag>
from theHashMap
. For eachTag
object, if it is in theHashMap
with a value of 1, then it will be removed from theHashMap
. Otherwise, if it is in theHashMap
with a value of more than 1, the value of theTag
object will be decremented by one. The sequence diagram of this operation is shown below.
-
removeAndAddTags(Set<Tag> tagsToRemove, Set<Tag> tagsToAdd)
PerformsremoveTags(Set<Tag> tagsToRemove)
andaddTags(Set<Tag> tagsToAdd)
sequentially. -
clearTags()
Clears all the mappings in theHashMap
. -
getUniqueTagList()
Returns a sorted list of unique tags that exists in theUniqueTagList
. -
getUniqueTagListSize()
Returns the number of unique tags in theUniqueTagList
.
The correctness of UniqueTagList
in AddressBook
is guaranteed by the immutability of the Person
model that
contains Tag
. Any changes to the UniquePersonList
in AddressBook
or any changes to any Person
in AddressBook
can only be done through AddressBook
. Therefore, in an event that the Person
model becomes mutable, this
implementation of UniqueTagList
may fail and needs to be revised.
For example, during every command that modifies the existing data in AddressBook
, the method AddressBook#setPerson(p, q)
will be called. Apart from making changes to the UniquePersonList
, this method call will also update the UniqueTagList
,
as shown in the sequence diagram below.
UniqueTagList#addTags(Set<Tag> tagsToAdd)
or UniqueTagList#removeTags(Set<Tag> tagsToRemove)
will be called directly
by AddressBook
in situations where new data is being added to the AddressBook
or existing data is being removed
from the AddressBook
respectively.
Design Consideration
Aspect: How tags are assigned to Person
- Alternative 1 (current implementation): A new tag is instantiated everytime even though there already exists a tag with
the same tag name in
UniqueTagList
.
- Pros: Easy to implement, less coupling.
- Cons: May have performance issues in terms of memory usage.
- Alternative 2: Unique tags are only instantiated once. Adding an existing tag to a person creates a reference to the
existing tag. The implementation is briefly shown below.
- Pros: Better performance in terms of memory usage.
- Cons: More difficult to implement, more coupling (between
UniqueTagList
and the instantiation ofPerson
etc) required.
Aspect: How unique tags are stored in UniqueTagList
(in the current implementation of tagging system)
- Alternative 1 (current implementation): Unique tags are stored in a
HashMap
as keys, with its frequency of occurrence as values.
- Pros: Updating
UniqueTagList
takes constant time; the number of occurrence for each unique tag is recorded and can be used. - Cons: Reading the
UniqueTagList
in alphabetical order takes O(n log(n)) time, incurred by sorting of the tags.
- Pros: Updating
- Alternative 2: Unique tags are stored in a
PriorityQueue
.
- Pros: Reading the
UniqueTagList
in alphabetical order just takes O(n) time. - Cons: Updating
UniqueTagList
takes O(log(n)) time every time; requires additional data structure to maintainUniqueTagList
accurately.
- Pros: Reading the
Date Features
Implementation
As seen in the Model
component, each Person
object contains its own BirthDate
object,
a list of ContactedInfo
and a ReminderList
. The list of ContactedInfo
stores ContactedInfo
objects,
while the ReminderList
stores Reminder
objects. A ContactedInfo
object has a RecentDate
object,
and a Reminder
object has a ReminderDate
object. As BirthDate
objects, RecentDate
objects and ReminderDate
objects need to be displayed in the same format for consistency, we have a DocumentedDate
parent class to ensure that
the three “date” type objects will use the same toString
method in DocumentedDate
to allow users to display the
dates in the same format, as seen in the class diagram below.
Documented Date
DocumentedDate
objects have the following characteristics:
- A
DocumentedDate
object has a privateLocalDate
member to allow the application to easily store and display a formatted date. - A
DateTimeFormatter
constant is included as a member so that developers can tweak how the formatted date is shown to the users.
Documented Date Child Classes
Despite inheriting from the DocumentedDate
parent class, these 3 “date” type objects have different behaviours.
A BirthDate
object needs to be recurring, to check if the person’s birthday is occurring on the same day despite
being saved in a past year. A RecentDate
needs to be a date that occurs in the past, and a ReminderDate
needs to be
a date that has not yet occurred. To model this more concretely, we implement some checks using the ParserUtil
class.
The three “date” type objects, are primarily created using static methods in the ParserUtil
class.
However, there are public constructors to create each BirthDate
, RecentDate
and ReminderDate
object. This is to
enable better testability.
As seen in the sequence diagram above, which shows the process of creating a BirthDate
object,
ParserUtil#parseBirthDate(validDate)
is called, with the user supplying a validDate
in the form of a String
.
The method will trim the validDate
into a String
called trimmedDate
and call
DocumentedDate#isValidDate(trimmedDate)
to check if it is in a valid date format. If the trimmedDate
is indeed a valid date,
it will then be used to create a new BirthDate
object. After that, a final check is done using the getDaysPassed()
method, before ParserUtil
returns the newly created BirthDate
object. For BirthDate
objects, the check using the
getDaysPassed()
method has to ensure that BirthDate
objects are not created using dates in the future,
i.e. either past dates or the current date.
As both RecentDate
and ReminderDate
objects have similar requirements to the BirthDate
objects, the process of
creating these objects are the same as the BirthDate
objects. For better comparison, let us examine one more sequence
diagram for the creation of a ReminderDate
object.
As seen above, the process exactly mirrors that of the BirthDate
object. However, the biggest difference is that the
check using getDaysPassed()
must make sure that ReminderDate
objects cannot be created with a date that has passed.
This is because the purpose of the reminder is to ensure that users can keep track of tasks that have not yet been done
or important events that are upcoming.
The RecentDate
objects are much more similar to the BirthDate
objects when compared to ReminderDate
objects,
as they have the same requirement of not being able to be created using a date in the future. This is because
RecentDate
objects keep track of the user’s interactions with clients and contacts, and the user must have had an
interaction with the contact before they save the interaction record in the application.
Having two levels of checks ensures that the working “date” type objects are less bug prone, when using the specific
“date” type object for their designated usages. This makes features such as after
or within
return valid entries
when used, instead of an invalid or unexpected entry.
Design Consideration
Aspect: How date type objects are created
- Alternative 1 (current implementation): “Date” type objects extend
DocumentedDate
.
- Pros: We can modify certain behaviour of each specific child class (i.e. allowing
BirthDate
objects to be read as recurring dates when necessary.)- Less duplicated bugs as each child class is independent of each other.
- Less duplicated code as the parent class can hold common methods.
- Cons: More overhead as more classes are required.
- Pros: We can modify certain behaviour of each specific child class (i.e. allowing
- Alternative 2: Use
DocumentedDate
for all dates and differentiate usingenum
types- Pros: We can standardise all formatting and behaviour strictly, and only use type specific methods
when necessary. (i.e. Since
BirthDate
andRecentDate
objects check for past and current dates only, we do not need to have duplicated code) - Cons: More checks are required within each method, may potentially violate Single Responsibility Principle and code quality due to the different types of checks required.
- Pros: We can standardise all formatting and behaviour strictly, and only use type specific methods
when necessary. (i.e. Since
Aspect: How to store dates
- Alternative 1 (current implementation):
DocumentedDate
objects use aLocalDate
object to store dates.
- Pros: We can encapsulate the processes of date manipulation and comparison.
- We can leverage on Java being a strongly typed language to ensure that inputs and outputs are less prone to errors.
- Cons: Users are restricted in the way they input dates.
- Pros: We can encapsulate the processes of date manipulation and comparison.
- Alternative 2: Use a
String
to store dates- Pros: More flexibility in terms of user input and input manipulation by the system.
- Cons: More processes are required to parse and check for invalid inputs.
- Users might be able to abuse the system by parsing a
String
with a long length, which might slow down the system when the system is running other process concurrently. - Handling of behaviour for specific date types in terms of comparing dates may require more work.
- Users might be able to abuse the system by parsing a
Interaction record feature
Implementation
Each Person
object contains its own List
of ContactedInfo
objects. The class diagram below shows how
the recently contacted information feature is implemented in the Model component.
ContactedInfo
A ContactedInfo
object contains the information regarding recent interactions for a specific client.
The sequence diagram below shows how the add recently contacted information feature is parsed.
The class diagram below shows how ContactedInfo is implemented.
ContactedInfo
objects have the following characteristics:
- A
ContactedInfo
object has two private data members (final),recentDate
ofRecentDate
object representing that date of interaction, anddescription
ofDescription
object, representing the description of the interaction. Both objects would distinguish one ContactedInfo object from another. - Any two
ContactedInfo
objects are not unique if bothdescription
andrecentDate
is equal. -
ContactedInfo
objects can be sorted, and the sorted order is the reverse ordering of theRecentDate
.
RecentDate
RecentDate
is an object that stores information regarding the interaction date for ContactedInfo
. RecentDate
object inherits from DocumentedDate
object.
RecentDate
objects have the following characteristics:
- A
RecentDate
object has two private data members (final),date
representing the date of interaction as aLocalDate
object, andvalue
ofString
format representing the date inYYYY-MM-DD
form. - input to create a
RecentDate
object needs to be the correct format (YYYY-MM-DD
). - Any two
RecentDate
objects are not unique if bothRecentDate
represents the same date. -
RecentDate
objects can be sorted, and the sorted order is the reverse ordering of theirLocalDate
.
RecentDate
implements the following operations.
-
parse(String parsedDate)
Creates a newRecentDate
using aString
.String
has to have the formatYYYY-MM-DD
. -
defaultRecentDate()
Returns today’s date as aRecentDate
object.
Description
Description
object represents the description of the recent interaction. Description gets invoked in the ParserUtil parseContactedInfo method.
The sequence diagram below shows what happens when a Description object is instantiated.
Description
objects have the following characteristics:
-
Description
can take on any values, but should not be blank nor should it exceed 280 characters. - Contains one public data member (final)
value
ofString
object, representing the description of theDescription
object, which can be used to distinguish itself from otherDescription
object.
Description
implements the following operations.
-
parse(String parsedDate)
Creates a newRecentDate
using aString
.String
has to have the formatYYYY-MM-DD
. -
defaultDesc()
Returns aDescription
object containing theString
with the description being “First Interaction”. -
isValidDescription(String test)
Checks if the givenString
is a valid input. Returns true if the inputString
is not blank and does not exceed 280 characters, otherwise false.
Design Consideration
Aspect: How Recent Interaction feature data is handled
- Alternative 1 (current Implementation):
ContactedInfo
is an object that holds bothDescription
andRecentDate
.- Pros: Easy to handle, more cohesion. This method introduces more SLAP, thus making it easier to update and maintain code.
- Cons: More checks are needed to ensure that inputs by user is valid.
- Alternative 2:
Description
andRecentDate
objects are seperated.- Pros: Easy to implement.
- Cons: More coupling. This method would make it harder to maintain and update code. This method does not take SLAP into account, making it harder to implement commands related to this feature.
Reminder Feature
Implementation
As seen from the Model
, a Person
contains a ReminderList
, which stores Reminder
objects. The class diagram below
shows how the reminder features are implemented in the Model
component.
Reminder
Each Reminder
object contains information regarding reminders specific to a saved client, and has the following
characteristics:
- A
Reminder
object stores a privateReminderDescription
object, and a privateReminderDate
object.- A
ReminderDescription
object stores a privateString
which describes the reminder event. - A
ReminderDate
object extends fromDocumentedDate
stores a privateLocalDate
field to capture the date of the reminder. - Any two
Reminder
objects are not if bothReminderDescription
andReminderDate
are equal.
- A
Reminder
implements the following method:
-
isSameDateAs(ReminderDate reminderDate)
Checks if theReminder
object happens on the same date as the givenReminderDate
.
The class diagram below shows how a Reminder
object is implemented
The sequence diagram below shows how a user input to add a reminder is parsed into a AddReminderCommand
.
ReminderDescription
Each ReminderDescription
object stores information pertaining to the description of reminders.
ReminderDescription
objects have the following characteristics:
- A
ReminderDescription
object stores a privateString
which describes the reminder event.- The private
String
must be alphanumeric, should not be blank, and should not exceed 280 characters. - This field is also being used to compare with other
ReminderDescription
objects to check if they are identical. For instance, any twoReminderDescription
objects are equal if they have the same descriptionString
.
- The private
ReminderDescription
implements the following method:
-
isValidDescription(String description)
Checks if the givenString
is a validReminderDescription
.
ReminderDate
Each ReminderDate
object stores information pertaining to the date of reminders. A ReminderDate
object cannot have
a date which happens in the past, as reminders are supposed to remind users of upcoming events.
ReminderDate
objects have the following characteristics:
- A
ReminderDate
object has a privateDateTimeFormatter
that provides the format in which a date is to be printed. Developers are able to conveniently alter this field to change the output format of the date. - A
ReminderDate
object has a privateString
which stores the displayed value of a date provided by theDateTimeFormatter
.
ReminderDate
implements the following method:
-
parse(String parsedDate)
Creates a newReminderDate
using aString
. TheString
provided has to be in the formatyyyy-MM-dd
.
ReminderList
ReminderList
is an object that stores Reminder
objects. ReminderList
makes use of a PriorityQueue
to store
Reminder
objects, and makes use of the ReminderDate
to arrange the Reminder
objects in chronological order.
ReminderList
has been designed to be immutable. Every addition or deletion of a Reminder
in the ReminderList
would
return a copy of the updated list. The new instance returned would then be used to replace the existing ReminderList
in a Person
object. Another advantage of the immutability characteristic is that the internal state will be
consistent, even when there are exceptions.
The sequence diagram below shows how ReminderList
handles a deletion of a Reminder
object.
Design Consideration
Aspect: How to store information in Reminder
- Alternative 1 (current implementation):
Reminder
stores the description and date of reminders as two objects, i.e.ReminderDescription
andReminderDate
.- Pros: This method applies SLAP, which increases the readability of the code, and makes the updating and debugging process simpler.
- Cons: Requires more checks on user input to make sure that legal arguments are being passed to the methods.
- Alternative 2:
Reminder
stores the description and date of reminders as two primitives, i.e.String
andLocalDate
.- Pros: Implementation of
Reminder
is easier - Cons: Harder to debug and update the code.
- Pros: Implementation of
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- has a need to manage a significant number of contacts
- has a need to distinct between groups of contacts
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
- prefers getting reminders on actionable items
Value proposition: manage and consolidate information on contacts with automated reminders, faster than a typical mouse/GUI driven application
User stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * |
new user | see usage instructions | refer to instructions easily when I forget how to use the App |
* * * |
user | add a new person | |
* * * |
financial advisor | add birthdays for my contacts | show my clients that I take note of their important dates personally |
* * * |
user | edit an existing person | make sure that the information stored is up to date |
* * * |
user | delete a person | remove entries that I no longer need |
* * * |
user | find a person by name | locate details of persons without having to go through the entire list |
* * |
busy user | keep track of important tasks daily | make sure I do not miss out tasks for my clients |
* * |
user with many persons in the address book | assign tags to my contacts | categorise my contacts in a meaningful manner |
* * |
financial advisor | track my last interaction with a contact | have a snapshot of the relationship |
Use cases
(For all use cases below, the System is the Address Book
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Add a new contact
MSS
- User requests to add a new contact to the Address Book.
-
Address Book adds contact to the contact list.
Use case ends.
Extensions
-
1a. The given input is invalid.
-
1a1. Address Book shows an error message.
Use case ends.
-
Use case: UC02 - Update a contact
MSS
- User requests to update details for a person in the Address Book.
-
Address Book updates the details of the contact.
Use case ends.
Extensions
-
1a. The given input is invalid.
-
1a1. Address Book shows an error message.
Use case ends.
-
-
1b. The given index is invalid.
-
1b1. Address Book shows an error message.
Use case ends.
-
Use case: UC03 - List all contacts
MSS
- User requests to list all contacts.
-
Address Book shows a list of contacts if any.
Use case ends.
Extensions
-
1a. The list is empty.
-
1a1. AddressBook shows an error message.
Use case ends.
-
Use case: UC04 - Delete a contact
MSS
- User lists all contacts (UC03).
- User requests to delete a specific contact in the list.
-
Address Book deletes the contact.
Use case ends.
Extensions
-
2a. The given contact is invalid.
-
2a1. AddressBook shows an error message.
Use case ends.
-
Use case: UC05 - Find contact by keyword
MSS
- User requests to find a person.
-
Address Book shows a list of persons with names containing the keyword.
Use case ends.
Extensions
-
1a. No keyword is given.
-
1a1. Address Book shows an error message.
Use case ends.
-
-
1b. The given keyword does not match any contacts.
-
1b1. Address Book shows a message that no contacts matches the keyword.
Use case ends.
-
Use case: UC06 - Set previously contacted date
MSS
- User requests to set previously contacted date for a specified contact.
-
Address Book sets the previously contacted date for the specified contact.
Use case ends.
Extensions
-
1a. No date is given.
-
1a1. Address Book sets the previously contacted date as today for the specified contact.
Use case ends.
-
-
1b. The given date is invalid.
-
1b1. Address Book shows an error message.
Use case ends.
-
-
1c. The given index is invalid.
-
1c1. Address Book shows an error message.
Use case ends.
-
-
1d. No description provided.
-
1d1. Address Book shows an error message.
Use case ends.
-
-
1e. Description provided is more than 280 characters.
-
1e1. Address Book shows an error message.
Use case ends.
-
Use case: UC07 - Show all contacted information for a specified contact
MSS
- User request to list all contacted information for a specified contact.
-
Address Book shows all contacted information for the specified contact.
Use case ends.
Extensions
-
1a. No index specifying a specific contact is given.
-
1a1. Address Book shows an error message.
Use case ends.
-
-
1b. The given index specifying a specific contact is invalid.
-
1b1. Address Book shows an error message.
Use case ends.
-
Use case: UC08 - List all contacts in Address Book within a designated time frame
MSS
- User requests to see all contacts last contacted within/outside a designated number of days.
-
Address Book shows contacts last contacted within/outside the designated time frame (i.e. less than 30 days).
Use case ends.
Extensions
-
1a. No client was contacted within/outside the designated number of days.
-
1a1. Address Book does not show any clients.
Use case ends.
-
-
1b. Invalid index provided.
-
1b1. Address Book shows an error message.
Use case ends.
-
Use case: UC09 - Set reminder
MSS
- User requests to set a reminder for a designated contact at a specified date.
-
Address Book sets a reminder for the contact tagged to the specified date.
Use case ends.
Extensions
-
1a. The given reminder message is invalid.
-
1a1. Address Book shows an error message.
Use case ends.
-
-
1b. The given reminder date is invalid.
-
1b1. Address Book shows an error message.
Use case ends.
-
Use case: UC10 - View reminders of a contact
MSS
- User requests to view reminders of a specific contact.
-
Address Book shows reminders of the specified contact.
Use case ends.
Extensions
-
1a. The given contact is invalid.
-
1a1. Address Book shows an error message.
Use case ends.
-
-
1b. No reminder is found in the given contact.
-
1b1. Address Book shows an error message.
Use case ends.
-
Use Case: UC11 - View reminders on a date
MSS
- User requests to view reminders on a specific date.
-
Address Book shows reminders associated with the specified date.
Use case ends.
Extensions
-
1a. The date given is invalid.
-
1a1. Address Book shows an error message.
Use case ends.
-
Use case: UC12 - Delete a reminder
MSS
- User views reminders of a specific contact (UC09).
- User requests to delete a reminder for a specified contact.
-
Address Book deletes a reminder for the specified contact.
Use case ends.
Extensions
-
2a. The given reminder is invalid.
-
2a1. Address Book shows an error message.
Use case ends.
-
-
2b. The given contact is invalid.
-
2b1. Address Book shows an error message.
Use case ends.
-
Use case: UC13 - Show all tags
MSS
- User requests to view all tags.
-
Address Book shows all existing tags.
Use case ends.
Extensions
-
1a. There is no tags in Address Book.
-
1a1. Address Book shows a message, stating that there is no tags.
Use case ends.
-
Use case: UC14 - Show all contacts that are tagged to a tag
MSS
- User views all tags (UC13).
- User requests to view all contacts that are tagged to the specified tag.
- Address Book shows all contacts that are tagged to the specified tag, if any.
Extensions
-
2a. The given tag is invalid.
-
2a1. Address Book shows an error message.
Use case ends.
-
Use case: UC15 - Add a tag to a contact
MSS
- User requests to add a tag to a contact.
-
Address Book appends the designated tag to the contact.
Use case ends.
Extensions
-
1a. The given contact is invalid.
-
1a1 Address Book shows an error message.
Use case ends.
-
-
1b. The given tag is invalid.
-
1b1 Address Book shows an error message.
Use case ends.
-
-
1c. The given tag already exists.
-
1c1 Address Book shows an error message.
Use case ends.
-
Use case: UC16 - Delete a tag from a contact
MSS
- User requests to delete a tag from a contact.
-
Address Book removes the specified tag from the contact.
Use case ends.
Extensions
-
1a. The given contact is invalid.
-
1a1. Address Book shows an error message.
Use case ends.
-
-
1b. The given tag is not associated with the contact.
-
1b1. Address Book shows an error message.
Use case ends.
-
-
1c. The given tag is invalid.
-
1c1. Address Book shows an error message.
Use case ends.
-
Use case: UC17 - Show all birthdays today
MSS
- User requests to view all birthdays occurring today.
-
Address Book shows all persons with birthdays today.
Use case ends.
Extensions
-
1a. No birthdays occur today.
- 1a1. Address Book shows message stating that there are 0 persons with birthdays today. Use case ends.
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.
- Should not be bigger than 100MB.
- A user should not be required to use an installer to run the application.
- A new user should know how to use or where to look for function guides within one day.
- An advanced user should be able to edit and replace the dataset manually.
- The application GUI should work well for standard screen resolutions 1920x1080 and higher, and for screen scales of 100% and 125%.
- The application should respond to user input within 2 seconds.
- The application is not required to support printing or use with other 3rd party software.
- The application is not required to implement undo, redo and data recovery functions on error.
Glossary
- Address Book: Address book used to store contacts in the application
- Application: The Automated Insurance Assistant Application
- Command Box: Box for user input, for a graphical representation, click here.
- ContactedInfo: The type of object that interaction records are saved as.
- Mainstream OS: Windows, Linux, Unix, OS-X
- MSS: Main Success Scenario that describes the most straightforward interaction for a given use case, which assumes that nothing goes wrong
- RecentDate: The type of date object used to save dates for a given interaction record.
- Result Display Message: Message shown in the Result Display.
- SLAP: Single level of abstraction principle. Refers to every method dealing with only one level of abstraction.
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Run the jar file in a shell application using the command
java -jar AIA.jar
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 running the jar file with the same command.
Expected: The most recent window size and location is retained.
-
Person Related Tests
Adding a contact
- Add a new contact into the contact list
-
Prerequisites: none
-
Test case:
add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 b/1970-01-01
Expected: Contact is added to contact list. -
Test case: Duplicate persons
Command: Run the command fromii
twice.
Expected: Duplicate person message. Error details shown in the result display message. Command box remains the same. -
Other incorrect add commands to try:
- Missing required fields
- Prefixes with no fields (e.g.
n/
except tag)
Expected: Invalid command message. Error details shown in the result display message. Command box remains the same.
-
Deleting a contact
-
Deleting a contact while all contacts are being shown
-
Prerequisites: List all contacts using the
list
command. Multiple contacts in the contact list. -
Test case:
delete 1
Expected: First contact is deleted from the contact list. Details of the deleted contact shown in the result display message. -
Test case:
delete 0
Expected: No contact is deleted. Error details shown in the result display message. Command box remains the same. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the contact list size)
Expected: Similar to previous.
-
Editing a contact
-
Editing a contact in contact list
-
Prerequisites: A contact with tags in the contact list.
-
Test case:
edit 1 n/name
Expected: Name of first contact is changed toname
. Details of the edited contact shown in the result display message. - Other valid edit commands to try:
edit 1 p/88888888
edit 1 e/email@mail.com
edit 1 a/500 Dover Road
edit 1 b/2000-01-01
Expected: Similar to previous.
-
Test case:
edit 1 t/
Expected: Tags of the contact is removed. -
Test case:
edit 0 n/name
Expected: No contact is edited. Error details shown in the result display message. Command box remains the same. - Other incorrect edit commands to try:
edit
,edit x n/name
,...
(where x is larger than the contact list size)
Expected: Similar to previous.
-
Showing all birthdays today
-
Showing all contacts with birthdays today in the contact list
-
Prerequisites: At least one contact with a birthday today in the contact list.
-
Test case:
birthdays
Expected: Contacts with birthdays today are shown in contact list. Number of contacts listed is shown in the result display message. -
Test case: no birthdays shown
Prerequisite: No contacts with birthdays today in the contact list.
Command:birthdays
Expected: No contacts are shown in contact list.0 persons listed
is shown in the result display message.
-
Tag Related Tests
Adding a tag
-
Adding a tag to a contact in the contact list
-
Prerequisites: At least one contact in the contact list.
-
Test case:
tag 1 t/someTag
Expected: First contact is tagged tosomeTag
. Details of the tagged contact shown in the result display message. -
Test case: Duplicate tags
Command: run the command inii
twice.
Expected: Contact is not re-tagged. Error details shown in the result display message. Command box remains the same. -
Test case:
tag 1 t/some tag
Expected: Contact is not tagged. Error details shown in the result display message. Command box remains the same. -
Other incorrect add tag commands to try:
tag
,tag 1
,tag x t/sometag
,...
(where x is larger than the contact list size)
Expected: Similar to previous.
-
Deleting a tag
-
Deleting a tag from a contact in the contact list
-
Prerequisites: At least one contact with the tag
someTag
in the contact list. -
Test case:
untag 1 t/someTag
Expected: First contact is no longer tagged tosomeTag
. Details of the contact shown in the result display message. -
Test case:
untag 1 t/some tag
Expected: Contact is not changed. Error details shown in the result display message. Command box remains the same. -
Other incorrect delete tag commands to try:
untag
,untag 1
,untag 1 t/x
,...
(where x isstring
that is not a tag)
Expected: Similar to previous.
-
Viewing all tags
-
Viewing all tags in the list
-
Prerequisites: At least one tag in the contact list.
-
Test case:
tags
Expected: Tag(s) is shown in the result display message. -
Test case: no tags shown
Prerequisite: No tags in the contact list.
Command:tags
Expected: No tags message shown in the result display message.
-
Finding contacts using a tag
-
Viewing all contacts associated with a tag
-
Prerequisites: At least one contact with a the
someTag
tag in the contact list. -
Test case:
#someTag
Expected: Contact list shows contacts associated with the tag. Number of contacts listed is shown in the result display message. -
Test case: no contacts shown
Prerequisite: No contact with thehello
tag in the contact list.
Command:#hello
Expected: No contact shown in contact list.0 persons listed
shown in the result display message.
-
Interaction records related tests
Adding an interaction record
-
Adding an interaction record to a contact in the contact list
-
Prerequisites: At least one contact in the contact list.
-
Test case:
log 1 d/2022-04-09 des/Coffee
Expected: Interaction is saved for the first contact with the given date and description. Details are shown in the result display message. -
Test case:
log
Expected: Error details shown in the result display message. Command box remains the same. -
Test case:
log 1 d/3000-01-01 des/post-apocalyptic coffee
Expected: Interaction record is not saved. Error details shown in the result display message. Command box remains the same. -
Other incorrect add interaction record commands to try:
log 1 d/x des/x
,log 1 d/ des/x
,log 1 d/2022-01-01 des/
,...
(where x is astring
)
Expected: Similar to previous.
-
Viewing interaction records of a contact
-
Viewing interaction records of a specific contact in the contact list
-
Prerequisites: One contact with an interaction record in the contact list.
-
Test case:
logs 1
Expected: Show the interaction records of the first contact in the result display message. -
Test case: no interaction records
Prerequisite: First contact with no interaction records.
Command:logs 1
Expected: Show no records of interaction in the result display message. -
Test case:
logs x
(where x is larger than the contact list size)
Expected: Error details shown in the result display message. Command box remains the same.
-
Deleting an interaction record
-
Deleting an interaction from a contact in the contact list
-
Prerequisites: At least one contact with an interaction record in the contact list.
-
Test case:
unlog 1 del/1
Expected: First contact no longer has the first interaction record. Details of the deleted interaction record shown in the result display message. -
Test case:
unlog 1 del/x
(where x is larger than the interaction record list size)
Expected: Contact’s interaction records are not changed. Error details shown in the result display message. Command box remains the same. -
Other incorrect delete interaction record commands to try:
unlog
,unlog 1
,unlog x del/1
,...
(where x is larger than contact list size)
Expected: Similar to previous.
-
Viewing contacts contacted within days
-
Viewing contacts contacted within a specified number of days
-
Prerequisites: At least one contact with an interaction record at most 5 days before the current date.
-
Test case:
within 5
Expected: Contacts with interaction records within 5 days from the current date are shown in the contact list. Number of contacts listed is shown in the result display message. -
Test case: No interaction records within 3 days prerequisite: No contacts must have interaction records within 3 days (including 3 days before current date).
Expected: No contacts shown in contact list. No contacts listed in result display message. -
Test case:
within
Expected: Error details shown in the result display message. Command box remains the same.
-
Viewing contacts contacted after days
-
Viewing contacts contacted more than a specified number of days
-
Prerequisites: At least one contact with an interaction record at least 5 days before the current date.
-
Test case:
after 5
Expected: Contacts with interaction records more than 5 days ago from the current date are shown in the contact list. Number of contacts listed is shown in the result display message. -
Test case: No interaction records more than 3 days old prerequisite: No contacts must have interaction records more than 3 days old (including 3 days before current date).
Expected: No contacts shown in contact list. No contacts listed in result display message. -
Test case:
after
Expected: Error details shown in the result display message. Command box remains the same.
-
Reminders related tests
Adding a reminder
-
Adding an reminder to a contact in the contact list
-
Prerequisites: At least one contact in the contact list.
-
Test case:
remind 1 r/Some task rd/x
(Where x is a date in the future)
Expected: Reminder is saved for the first contact with the given date and description. Details are shown in the result display message. -
Test case:
remind
Expected: Error details shown in the result display message. Command box remains the same. -
Test case:
remind 1 r/Some task rd/2000-01-01
Expected: Reminder is not saved. Error details shown in the result display message. Command box remains the same. -
Other incorrect add reminder commands to try:
remind 1
,remind 1 r/ rd/y
,remind 1 r/x rd/
,...
(where x is astring
and y is a valid reminder date)
Expected: Similar to previous.
-
Viewing reminders of a contact
-
Viewing reminders of a specific contact in the contact list
-
Prerequisites: One contact with a reminder in the contact list.
-
Test case:
reminder 1
Expected: Show the reminders of the first contact in the result display message. -
Test case: no reminders
Prerequisite: First contact with no reminders.
Command:reminder 1
Expected: Show no reminders in the result display message. -
Test case:
reminder x
(where x is larger than the contact list size)
Expected: Error details shown in the result display message. Command box remains the same.
-
Viewing reminders by date
-
Viewing reminders in the contact list on a specific date
-
Prerequisites: At least one contact with a reminder on 01 Jan 2023 in the contact list.
-
Test case:
reminders rd/2023-01-01
Expected: Show the reminders tagged to 01 Jan 2023 in the result display message. -
Test case:
reminders rd/
Expected: Show the reminders tagged to the current date in the result display message. -
Test case: no reminders
Prerequisite: No reminders occurring on a specified datex
.
Command:reminders rd/x
Expected: Show no reminders in the result display message. -
Test case:
reminders
Expected: Error details shown in the result display message. Command box remains the same.
-
Deleting a reminder
-
Deleting a reminder from a contact in the contact list
-
Prerequisites: At least one contact with a reminder in the contact list.
-
Test case:
forget 1 del/1
Expected: First contact no longer has the first reminder. Details of the deleted reminder shown in the result display message. -
Test case:
forget 1 del/x
(where x is larger than the reminder list size)
Expected: Contact’s reminder list is not changed. Error details shown in the result display message. Command box remains the same. -
Other incorrect delete reminder record commands to try:
forget
,forget 1
,forget x del/1
,...
(where x is larger than contact list size)
Expected: Similar to previous.
-
Saving data
- Dealing with missing data files
- Remove addressbook.json and the data directory
-
Run the jar file
Expected: The application will automatically generate a data directory and populate addressbook.json with sample data.
- Dealing with corrupted data files
- Remove some lines from addressbook.json
-
Run the jar file
Expected: The application will make a copy of the current addressbook.json in backup.json and continue running with an empty addressbook.json. If changes are made, addressbook.json will be overwritten.