Developer Guide
Table of Contents
- Introduction
- Development Environment
- Tips
- Design
- Testing
- Documentation
-
Appendix
- Planned Enhancements
- Project Requirements
- Product Scope
- Use Cases
- Non-Functional Requirements
-
Instructions for Manual Testing
- Launch and shutdown
- Add a new person
- View a person
- Edit a person
- Delete a person
- Add a tag to a person
- Remove a tag from a person
- Filter persons by keywords
- Arrange persons by criteria
- Generate a sample EduMate
- Suggest meet up locations and times
- Organise and confirm meetings
- Cancel scheduled meetings
- Glossary
- More Information on Documentation, Logging, Testing, Configuration and Dev-ops
1. Introduction
Software Overview
EduMate is a desktop app designed for NUS students to manage their academic and social lives. It is optimised for use through a Command Line Interface (CLI) while still providing the benefits of a Graphical User Interface (GUI). If the user can quickly, EduMate can complete contact and module management tasks faster than traditional GUI apps.
Intended Audience
This guide is intended primarily for developers who want to work on the EduMate Software code base at https://github.com/AY2223S2-CS2103T-W14-2/tp.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
Using the Guide
What Do the Emojis Mean
Emoji | GFMD form | What does it mean |
---|---|---|
![]() |
:construction: |
Feature under construction |
![]() |
:question: |
Frequently asked question (FAQ) |
![]() |
:heavy_check_mark: |
What the developer should do |
![]() |
:warning: |
Warning to the developer, number of warning signs show the severity |
![]() |
:bulb: |
Tip for the developer |
![]() |
:information_source: |
Information for the developer |
Content Overview
Here is a brief overview of the guide’s content, so that it is easier for you to understand the software and our development workflow:
- Development Environment - what you need to do before you can start writing code
- Tips - useful tips that make the developmental process easier
- Design - how EduMate is currently implemented
- Testing - expectations and workflow for the testing process
- Documentation - expectations and workflow for the documentation process
- Appendix - additional information you may find useful
About Us
Please refer to the About Us page for information about the developers.
Getting Help
Should you require assistance in any form with regards to EduMate, please head over to our Github page and file an issue with a tag developer-assistance-required. A member of our core team will attend to you as soon as possible.
Core Technologies
Acknowledgements
- This project is based on the AddressBook Level 3 (AB3) project created by the SE-EDU initiative.
- This project utilised GUI tests from the AddressBook Level 4 (AB4) project created by the SE-EDU initiative as well.
- Some icons and graphics used were sourced from upklyak and flaticon.
- Libraries used: JavaFX, Jackson, JUnit5, Joda-Time, TestFX.
Version Control
The master
Branch
The master
branch represents stable released versions of the EduMate software. It is expected that this version always works as expected.
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
![:heavy_check_mark: :heavy_check_mark:](https://github.githubassets.com/images/icons/emoji/unicode/2714.png)
master
branch should always be synced with the upstream master
branch.
How to Make a Pull Request
Once you’ve made changes to your branch, create a Pull Request (PR) on the upstream master
branch and link the PR with any relevant issues and milestones.
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
Issue Tracker
We use GitHub Issues as our issue tracker, and here is how to use the issue labels:
Issue Label Name | Description |
---|---|
deliverables.Individual |
Individual submission requirements (for the module) |
deliverables.Team |
Team submission requirements (for the module) |
documentation.DeveloperGuide |
Improvements or additions to the Developer Guide |
documentation.UserGuide |
Improvements or additions to the User Guide |
modify |
Existing feature needs to be modified |
new |
New feature needs to be implemented |
priority.High |
The task needs to be completed immediately |
priority.Medium |
The task needs to be completed in the near future |
priority.Low |
The task can be postponed |
severity.High |
The bug needs to be fixed immediately |
severity.Medium |
The bug needs to be fixed in the near future |
severity.Low |
The bug can be fixed later |
type.Bug |
Something is not working and needs to be fixed |
type.Discuss |
Something needs to be discussed with the rest of the team |
type.Investigate |
Something needs to be investigated, but is not a bug |
type.Task |
Something needs to be done |
type.Story |
A feature which addresses a user story |
type.Epic |
A big feature which can be broken down into smaller stories e.g. search |
type.Testing |
Test cases need to be written |
2. Development Environment
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
3. Tips
Sample Data
Sample data for EduMate can be found here. It is a set of 100 persons with procedurally-generated fields.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
|
separating the different fields.
In order, they are: name|phone|email|address|telegram|groups|modules
. Note that groups and modules are separated by a space.
For example, Bee Shan|81121128|beeshan@gmail.com|Bishan|@beeshan|NS CCA|CS3242 BT3101 CS1010E CS3219 CE3165
provides information for a person with the following details:
Field | Value |
---|---|
Name | Bee Shan |
Phone | 81121128 |
beeshan@gmail.com | |
Station | Bishan |
Telegram Handle | @beeshan |
Groups | NS, CCA |
Modules | CS3242, BT3101, CS1010E, CS3219, CE3165 |
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
4. Design
Architecture
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: initialising the components in the correct sequence, and connecting them up with each other.
- At shut down: shutting down the components and invoking 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
.
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
, UserProfilePanel
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.
To start making changes to the UI:
- The layout of these UI parts can be found in matching
.fxml
files in thesrc/main/resources/view
folder. - The controller classes of these UI parts can be found in matching
.java
files in thesrc/main/java/seedu/address/ui
folder. - The stylesheets for these UI parts can be found in
Extensions.css
andMainWindow.css
, exceptUserProfilePanel
andHelpWindow
with separate CSS files in matching.css
files in thesrc/main/resources/view
folder. - For example, the layout of
UserProfilePanel
is specified inUserProfilePanel.fxml
, with controller class atUserProfilePanel.java
and stylesheet atUserProfilePanel.css
.
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.
Key Mapping
The UP and DOWN keys have been mapped to return previously typed commands by the user.
The above activity diagram does not include the mapping of the UP and DOWN keys to return previously typed commands by the user in order to avoid excessive complexity and maintain clarity. It is important to note that when the user has pre-existing text in the input field or has made edits to previous commands, the UP and DOWN keys will function as expected to prevent accidental deletion of user input.
Model Component
API : Model.java
The Model
component,
- stores the information of the user’s contacts i.e., all
Person
objects (which are contained in aUniquePersonList
object). - stores the command history i.e., all command strings (which are contained in a
ArrayList<String>
object). - maintains a filtered and sorted list of currently selected persons, which can be accessed as an unmodifiable
ObservableList<Person>
. This list is observable, allowing for easy UI integration with automatic updates when data changes. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
object. - does not depend on any of the other three components. This means that it can function independently and make sense on its own, without relying on other components.
Person
API : Person.java
Name
Represents the name of the user or the contact in EduMate.
Station
Represents the nearest MRT station to the user or contact’s home.
Phone
Represents the contact number of the user or the contact.
Represents the Email Address of the user or contact.
Telegram Handle
Represents the Telegram Handle of the user or contact.
Group Tag Set
Represents a collection of unique groups that the user or contact belong to. This class was created to support easy sorting by the group field.
Module Tag Set
Represents a collection of unique modules that the user or contact is enrolled into. It contains the lessons that the person has, as well as the modules shared with the user. This class was created to support easy sorting by the module field.
Tag
The following tags are used for adding important pieces of information to the person.
Group Tag
A group tag represents the relationship between the user and the person. For example, the person may be tagged with the “CCA” tag to indicate that the user and the person are CCA mates.
Module Tag
A module tag represents a module that the person is currently taking. There are two options for creating a module tag:
- The user can tag a person with just the module code (
CFG1002
). This is typically used for modules that don’t have lessons. In other words, this format simply informs EduMate that the person is taking the module, so that thesort
andfind
commands can use this information. - The user can tag a person with the module code and a lesson information (
CS2103T MON 8 10
). This will create a lesson on Monday from 8AM to 10AM, and informs EduMate that the person is busy during this time period. This is used by themeet
command to recommend meet up timings.
Time
We use org.joda.time.LocalTime
as the very basis of how we construct our time-related
objects which is then used elsewhere in the codebase.
Day
Day
is an enumeration class in Java and it only contains the 5 weekdays: MONDAY
,
TUESDAY
, WEDNESDAY
, THURSDAY
, FRIDAY
.
HourBlock
HourBlock
is an object which represents an hour of time.
TimeBlock
TimeBlock
is an object which can represent any positive hour of time.
TimePeriod
TimePeriod
is the parent class of both HourBlock
and TimeBlock
. Hence, we often use TimePeriod
when passing arguments around.
Tip: Notice that
TimePeriod
is an abstract class and hence cannot be instantiated. Instead, we create a new TimeBlock
, since it achieves the same functionality as the TimePeriod
.
Info: The time period is prefixed using
T/
(rather than t/
which is used by the telegram handle). It follows the format T/START_TIME END_TIME
, and along with the day, it creates a new time period.
Location
A Location
represents a point in Singapore. We use them to recommend places for the user to meet up with friends. It consists of a latitude (how far north it is), and a longitude (how far east it is).
Restrictions on location attributes:
- Latitude: must be between 1.23776 and 1.47066
- Longitude: must be between 103.61751 and 104.04360
This is to ensure that the location falls within the bounds of Singapore.
The location can be named or unnamed:
- Named locations are meant for actual locations in Singapore. For example, we may have “Bishan”, “NUS”, and “Suntec City”.
- Unnamed locations are reserved for computational purposes. For example, a location in between “Bishan” and “Ang Mo Kio” may be used to recommend suitable meet up locations.
There are also two other classes within the location
package that help to process this data.
Distance Util
The DistanceUtil
class deals with computing the distances between locations. It is used by the following classes:
- It is used by the Recommenders to suggest ideal and central locations for people to meet.
- It is used by the LocationTrackers to give us approximate locations for a person.
Location Data Util
The LocationDataUtil
class deals with reading and parsing location data from files. For example, the set of destinations to eat and study are stored in the resources/data folder and are saved within this class. We also store the locations of MRT stations, which allow us to convert user-inputted strings into named locations.
Tips for using Locations: Notice that locations are immutable. This allows us to pass around locations as references, thereby reducing the amount of data we need to store.
Commitment
A Commitment
is something that a person needs to do at a certain time and place. Notice that we can only create Lesson
s at the moment. Having this as a separate class can allow us to easily extend this application to fit more kinds of commitments.
What are commitments used for:
- They tell us when the person is unavailable, so that we do not recommend inappropriate timings.
- They tell us where the person is expected to be at a particular time, so that we can recommend better locations to meet up.
Lesson
Lesson
is inherited from Commitment
, and represents a time and location that a person is attending a class. In addition, Lesson
stores the module code for the lesson. For example, a person takes CS2040S on Monday at 9AM for 2 hours.
![:construction: :construction:](https://github.githubassets.com/images/icons/emoji/unicode/1f6a7.png)
Currently, all
Lessons
are in NUS, but this can be improved upon in the future, by adding additional arguments to the tag
command.
Timetable
The Timetable
represents the daily schedule of the user or contact.
For each Day
in the Timetable
, there are 15 HourBlock
objects each representing an hour starting from 8 AM - 9 AM and ending at 10 PM - 11 PM.
Utils
Sample Data Util
The SampleDataUtil
class deals with reading and parsing persons data from a file. In particular, these are the people that will appear upon first load of EduMate, as well as during the execution of SampleCommand
. The sample data is stored within this file.
Tips for reading the sample data:
- Each row of data corresponds to a single person, and their fields are separated by the
|
, also known as the “pipe” character. - The attributes are:
NAME|PHONE|EMAIL|ADDRESS|TELEGRAM_HANDLE|GROUP_TAGS|MODULE_TAGS
. - Notice that the
MODULE_TAGS
are separated by a comma,
instead, as its parser uses spaces to separate out the arguments.
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 theEduMateParser
class to parse the user command. - If needed, a command-specific parser (like
AddCommandParser
) will be called to parse the arguments of the user input. - 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
.
Commands
Add Command
The add
command allows users to create a new person and insert them into the application.
Parsing the inputs - When the user types an input, the parser will extract out the relevant arguments and check whether they are valid.
Command Format:
-
add n/NAME [p/PHONE] [s/STATION] [e/EMAIL] [t/TELEGRAM] [g/GROUP]... [m/MODULE]...
: Adds a contact to EduMate.
![:bulb: :bulb:](https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png)
AddCommand
are unordered, so the user can type them in any order. They are all handled in Argument Multimap.
Computing the common modules - One of our sort keys is to use the number of common modules that the person has with the user. As such, we cache these modules to optimise performance.
Assigning a Contact Index - After the inputs have been parsed and extracted, EduMate will look to fill the first gap in contact index. i.e. it will find the lowest positive integer that isn’t already the contact index of a person. Refer to the example given below:
Current state of EduMate | New Contact Index | Explanation |
---|---|---|
1. Gwon Se Rang 2. Lao Ming Da |
3 | 3 is the next number in the sequence. |
1. Gwon Se Rang 3. Lao Ming Da |
2 | 2 is the lowest number that is not already a contact index. |
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
ContactIndex
of 0.
In summary, the activity diagram is as such:
add
command
Edit Command
The edit
command allows the user to edit an existing contact in EduMate.
Parsing the inputs - When the user types an input, the parser will extract out the relevant arguments and check whether they are valid.
Command Formats:
-
edit z/FIELD
: Edits the user details. -
edit INDEX z/FIELD
: Edits the details of the contact at the specifiedINDEX
.
Distinguishing between contact and user - As specified in the command formats, if the user wants to edit their own details, they can just leave out the index. On our end, the ArgumentMultimap
has been modified to accept null as a valid index, which will handle such a use case.
Computing the common modules - One of our sort keys is to use the number of common modules that the person has with the user. As such, we cache these modules to optimise performance.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
Creating a person descriptor - When we are editing a person, we need two things:
- The edited details: These are specified by the user as arguments in the
edit
command. - The person’s original details: If the user does not specify to edit a particular field, we take the current data stored in the field.
From these two sources of information, we can create a descriptor
that keeps track of what the new person should be, which gives us lines such as:
-
editPersonDescriptor.getName().orElse(userToEdit.getName())
.
In summary, the activity diagram is as such:
edit
command
Delete Command
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("delete 1")
API call.
delete
command
![: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.
Tag Command
The tag
command allows user to add ModuleTag
s or GroupTag
s to an existing contact in EduMate.
Parsing the inputs - When the user types in an input, the parser will extract out the relevant arguments.
Command Formats:
-
tag m/MODULE...
: Tags modules to the user. -
tag INDEX m/MODULE...
: Tags modules to the contact at the specified index. -
tag m/MODULE DAY START END...
: Tags lessons to the user with the specified parameters, and tags the module if not already done so. -
tag g/GROUP...
: Tags groups to the user. -
tag INDEX g/GROUP...
: Tags groups to the contact at the specified index.
Distinguishing between contact and user - As specified in the command formats, if the user wants to edit their own details, they can just leave out the index. On our end, the ArgumentMultimap
has been modified to accept null as a valid index, which will handle such a use case.
TagCommand
execution
Untag Command
Similar to the tag
command, the untag
command allows user to remove ModuleTag
s and GroupTag
s from an existing contact in EduMate.
Parsing the inputs - When the user types in an input, the parser will extract out the relevant arguments.
Command Formats:
-
untag m/MODULE...
: Untags modules from the user. -
untag INDEX m/MODULE...
: Untags modules from the contact at the specified index. -
untag m/MODULE DAY START END...
: Untags lessons from the user with the specified parameters, and untags the module if it is empty. -
untag g/GROUP...
: Untags groups from the user. -
untag INDEX g/GROUP...
: Untags groups from the contact at the specified index.
UntagCommand
execution
View Command
The view
command allows users to view their information or their contact’s information on the Profile Panel on the lower right side of the application, above the Command Box. A single view
command defaults to displaying the profile of the user. On the other hand, we can display
a contact’s information appending their assigned ContactIndex
or by adding n/FULL_NAME
behind the view
command.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
Command Formats:
-
view
: Displays user’s profile on the Profile Panel. -
view n/XYZ
: Display XYZ’s profile on the Profile Panel. -
view INDEX
: Display the contact’s whoseContactIndex
isINDEX
on the Profile Panel.
Parsing the inputs - When the user enters the input, the ViewCommandParser
will first check if the arguments are empty.
- If it is not empty, then
ViewCommandParser
will try to extract tokens that were prefixedn/
(for the name). -
If a name is not present in the arguments, it will search for an index (of
int
type) instead in the preamble.The parser, using the arguments (if they exist), creates the
ViewCommand
to be executed.
Below is a Sequence Diagram which summarises the behaviour of ViewCommandParser
.
ViewCommandParser
Below is an Activity Diagram for the execution of the ViewCommand
.
ViewCommand
execution
Find Command
The find
command allows users to search for their contacts with partial information.
For example, if the user wants to search for a person but does not know the full name, they can simply search the name and get a list of people matching the name. This applies to all information a Person contains. Additionally, it can accept multiple keywords for the search but is limited to the same type of information.
Parsing the inputs - When the user types an input, the parser will extract out the relevant arguments and check if there is only one type of information.
Command Formats:
-
find [z/FIELD MORE_FIELD]
: Finds the contacts matching the field found in the ‘z’ field.
Tip:
-
This command can be used before the other commands to return a list of contacts the user wants to work with.
-
The
find
command returns a filtered list, so command operations only work on persons present in the filtered list.
e.g. If the filtered list does not contain any person with contact index 2, any operation relating to contact index 2 will throw error.
Describing the find - ContainsKeywordPredicate
class which extends from Predicate
handles storing the Prefix
and keywords
to pass into the ModelManager
class. It then uses the Java FilteredList
Library to handle the Predicate
to return a list of people the user requested.
In summary, the activity diagram is as such:
find
command
Sort Command
The sort
command allows users to arrange their contacts in the order they desire. To be more robust in their arrangement, users are allowed to chain comparators together to break ties.
For example, if the user wants to sort by groups, and break ties with name, they can simply type sort g/ n/
.
Parsing the inputs - When the user types an input, the parser will scan through the arguments. Then, it checks whether the field needs to be sorted in ascending or descending order. Finally, it combines all the comparators together so that we get a single comparator.
Command Formats:
-
sort
: Sorts the contacts by theirContactIndex
. -
sort [z/a]...
: Sorts the contacts by thez
field in ascending order. -
sort [z/d]...
: Sorts the contacts by thez
field in descending order. -
sort [z/]...
: Sorts the contacts by thez
field in their default order.
![:bulb: :bulb:](https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png)
sort g/d n/a
is different from sort n/a g/d
.
Describing the sort - The Comparator
class in Java does not have a toString()
method. As such, we have to pass a descriptor when we are creating our SortCommand
. Additionally, we needed a mapping from the prefixes (n/
) to their descriptors (Name
). As such, we transformed the Prefix
class to an Enum
to easily get the descriptors.
![:bulb: :bulb:](https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png)
ObservableList
to populate the UI components. However, we can wrap this ObservableList
inside a SortedList
which accepts a Comparator
as an argument. In this way, we only need to set this argument if we want to sort something in the UI.
List Command
Links: Command
The list
command will allow users to view all the contacts saved in EduMate.
Command Format:
-
list
: lists all contacts in the EduMate Application.
Exit Command
Links: Command
The exit
command allows users to exit the EduMate Application via the command line.
Command Format:
-
exit
: Exits the EduMate Application.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
isExit
boolean in the ExitCommandResult
class to true
which is passed through multiple classes to the MainWindow
class to handle the exit.
Save Command
The save
command allows users to save a copy of EduMate. This information is stored within the data
folder, the same place as where edumate.json
is kept.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
We cannot save the json file directly from the command, because the command only has access to the model. Instead, we pass the file path through a
SaveCommandResult
, which will inform the LogicManager
to save the information in a particular file.
save
command
Load Command
The save
command allows users to load a previously saved copy of EduMate. This information is retrieved from the data
folder, the same place as where edumate.json
is kept.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
Similar to the Save Command, we pass the file path through a
LoadCommandResult
, which will inform the LogicManager
to load the information from a particular file.
load
command
Meet Command
The meet
command allows users to get recommendations of optimal meeting timings and locations with their contacts.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
The
meet
command has 2 different sub-commands : eat
, study
.
However, we will be referring to all 3 commands generally as meet
.
All 3 commands (meet
, study
and eat
) only differ in the location
recommendations as certain locations are only appropriate for certain activities.
Running meet
will recommend studying, eating locations and other general locations together with their recommended timings.
This feature is utilises the Recommender
.
Command Formats:
-
meet CONTACT_INDEX...
: Recommends a meeting time and location for all the participants with the given contact indices (including the user). -
eat CONTACT_INDEX...
: Recommends a time and eating place where all participants with the given contact indices (including the user) can have a meal together. -
study CONTACT_INDEX...
: Recommends a time and study spot where all participants with the given contact indices (including the user) can study together.
Organise Command
The organise
command will set a meet up with the time and place for all participants and the user himself/herself. Note that the user’s information is automatically added to the list of participants as it is assumed that they will be taking part in the meet up.
Command Formats:
-
organise RECOMMENDATION_INDEX
: Takes the recommendation at the specified index and saves it. -
organise CONTACT_INDEX... d/DAY T/START_TIME END_TIME l/LOCATION
: Creates a new meet up for participants with the given contact indices. Note that this list of contact indices should not include that of the user (0).
On the other hand, the unorganise
command will remove the meet up at the specified index.
Command Format:
-
unorganise MEET_UP_INDEX
: Removes the scheduled meet up with the specified index.
The TimingRecommender
will check if the timing is a suitable for every participant to meet.
Sample Command
The sample
command repopulates the EduMate with a fresh set of contacts. Note that this calls the same function as that called in Sample Data Util.
Command Format:
-
sample NUMBER
: Replaces the EduMate with the specifiedNUMBER
of sample persons.
Parsers
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
EduMateParser
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 theEduMateParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.AddCommandParser
,DeleteCommandParser
etc.) inherit from theParser
interface so that they can be treated similarly where possible (e.g. during testing).
Argument Multimap
The ArgumentMultimap
utilises a HashMap
to store an ArrayList<String>
of arguments from the user, mapped to the Prefix
that precedes the arguments.
Prefix
The Prefix
is an enum
consisting of n/
,s/
, p/
, t/
, e/
, g/
, m/
, d/
, T/
, l/
and a blank Prefix
which is an empty String. The Prefixes listed previously correspond to Name, Station, Phone, Telegram Handle, Email, Group Tags, Module Tags, Day, Time Period and Location.
Recommenders
API : Recommender.java
The Recommender
component,
- consists of 2 sub-components (modules) :
LocationRecommender
andTimingRecommender
- recommends timing and location of meet ups for relevant participants and the user.
How the Recommender
Component works:
- User enters a
meet/eat/study
command. - The
TimingRecommender
is initialised with a set of participants. - The
LocationRecommender
is initialised with a set of destinations. - New
LocationTracker
s are created to give approximate locations of each person. - The
TimingRecommender
recommends common available timings amongst users and participants. - Based on the timings provided, the
LocationTracker
s return each person’s approximate locations. - The
LocationRecommender
recommends optimal meeting points based on the locations provided by theLocationTracker
s. - Feedbacks to user the recommended meet up locations and timings.
Timing Recommender
The TimingRecommender
’s role is to recommend timings in which the user and all participants are available.
The TimingRecommender
uses the participants’ schedule to find common time periods that everyone
will be free so that a meet up could be scheduled.
TimingRecommender
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
TimingRecommender
will always recommend timeslots and ranks them in descending time duration that
the participants could meet up.
Location Recommender
The LocationRecommender
’s role is to recommend a central location where persons can meet. It accepts two sets of locations:
- A set of
destinations
to be suggested. They could be places to study, eat or both. - A set of
sources
representing the participants’ locations given a particular time.
The midpoint of these sources
is calculated, and then we compare the destinations
based on how close they are to this midpoint. In this way, we recommend the locations that are the closest for everybody.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
DistanceUtil
class, which calculates distances and finds the nearest destinations.
Location Tracker
The LocationTracker
’s role is to give an approximate location of a person given a certain timing. These approximations are then fed into the LocationRecommender
to give more accurate recommendations.
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
The process of getting a recommendation is as follows:
- From the person’s timetable, we gather their set of known locations. For example, if the person has a lesson at NUS on Monday 8AM to 9AM, we know their location at that time period.
- Next, between any two consecutive known locations, we calculate the number of unknown locations between them.
- Based on this calculation, the
DistanceUtil
will return a list of approximations that achieve what was mentioned earlier. - Finally, these locations are put in their respective places in the
LocationTracker
.
Storage Component
API : Storage.java
The Storage
component,
- can save both address book data and user preference data in json format, command history in text format, and read them back into corresponding objects.
- inherits from both
EduMateStorage
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.address.commons
package.
MathUtil
The MathUtil
class contains generic functions for mathematical operations such as Cartesian Product and indexing.
5. Testing
Testing Types
Types of tests used:
- Developer Testing
- Regression Testing
- Unit Tests
- Stubs
- Integration testing
- Dogfooding
Our organisation made use of different testing types in order to cover multiple grounds. Types of testings also changed with the progress of the product.
Developer Testing
Our organisation opted to use developer testing right from the start with every increment of the product, instead of waiting for the whole product to be ready before conducting more tests.
This type of testing involved the developers trying out the product with the various commands implemented, to discover possible bugs early, and avoid major reworks in future increments and iterations.
Regression Testing
Our organisation continued with regression testing as increments came in, to ensure that previous features were not broken with changes and modifications. This is due to the interconnectedness of certain features implemented, such as commands and the model. Our project followed a breadth-first iterative model, and hence it was crucial for us to carry out regression testing as the project evolved and morphed.
Our organisation did this both with automated unit tests and manual testing. We put a greater emphasis on unit tests due to the expensive cost of manual testing, especially at stages of the product where it is not complete in its entirety.
Unit Tests
Our organisation primarily utilised JUnit5
for conducting unit tests. JUnit5
is a popular testing framework in the Java programming language that enables developers to write and run unit tests for their code.
Each individual unit of the program is tested to ensure each piece works correctly and stubs are commonly used to test the units in isolation.
Unit tests were implemented as features were added in, to ensure that as the product evolves, these features will have tests to ensure that they are still working as intended. Unit tests were also changed and added on as the product progressed, to ensure that the features were tested more thoroughly as the team learned new testing types and techniques.
Stubs
Stubs were used to test features and classes in isolation, so that any bugs in dependencies will not affect the tests that are in place. Use of stubs is common in our testing for models, as they have a lot of dependencies that make it difficult to test the entire logic in total. The model stubs are in use when testing other classes like commands. Stubs help to isolate dependencies so that each component’s logic are tested without being affected by other components.
Integration Testing
Integration testing was used extensively in the testing of the GUI, as part of CI. Integration testing were also included in unit tests to ensure that our features work well with each other. It was also covered manually via developer testing and dogfooding.
Dogfooding
Towards the completion of our product, our developers used the product on a regular basis in an attempt to simulate how a normal user might use the product. This helped ensure that our product would be relatively bug-free for a regular use case.
Model
Our organisation created dummy values for a model of a simulated list of persons that our product might, and used that to carry out testing on. When changes were made to the model in the product, any changes required were reflected in this testing model as well, to ensure that unit tests are testing on a correct simulation of the program.
Testing Commands
Our organisation tested commands by creating commands with the correct parameters, bypassing the parser, and executed them. Assertions were used to ensure that commands created, when executed, performed the correct operations on the model created specifically for tests, as well as to ensure that correct exceptions are thrown as and when needed, especially for invalid inputs.
Our organisation made use of equivalence partitions to tests for the types of commands that can be executed. The rationale is that since we have a relatively large number of variants for each command, we needed to test all possible inputs and partitions.
Testing Parsers
Our organisation opted to use stubs in order to test the parsers, to isolate that the parser is firstly parsing the correct text, and returning the correct corresponding command.
Negative and positive test cases were used to ensure that invalid inputs throws the correct exceptions, and that valid inputs creates and returns the correct command with correct parameters. This testing ensures that our definitions for equivalent commands were well-defined.
GUI Tests
Our organisation utilised TestFX
for conducting GUI tests. TestFX
is a popular testing framework for JavaFX
applications as it provides a set of tools and utilities for writing tests that interact with JavaFX
UI components, simulate user interactions, and perform assertions on the state of the UI.
We referenced from Addressbook Level 4 (AB4) on automated GUI testing.
- What’s different from AB4:
- We used the Github Actions Workflow located in
.github/workflows/gradle.yml
rather than setting upTravis CI
as perTestFX
documentation. -
build.gradle
runs both unit tests and GUI tests in the same task, which is also used byGithub Actions workflow
. -
TestFX
version is upgraded to4.0.16-alpha
whileopenjfx-monocle
version is upgraded tojdk-12.0.1+2
.
- We used the Github Actions Workflow located in
Setting up automated GUI Tests in Github Actions
Due to the Github Actions environment, there is a need to test in a headless environment. To test in a headless environment, you must add Monocle
as a test dependency as per TestFX documentation.
The current build.gradle sets the GUI tests to run in a headless environment by default. To remove that or set it to run with visual output on your local computer, find the code block below and set the jvmArgs
and systemProperties
according to your needs.
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
jvmArgs "-Dheadless=${project.hasProperty('headless')
? project.headless
: false}"
systemProperties = [
'testfx.robot': 'glass',
'testfx.headless': 'true',
'prism.order': 'sw',
'prism.text': 't2k',
]
}
Understanding GUI Tests
We utilised GUI tests from AB4 and here is a summary of it.
Note that AllUITests
above refers to all UI Tests in seedu.address.ui
except for TestFxmlObject
. The handles used in the corresponding test cases can be easily seen from their names. For example, CommandBoxTest
contains CommandBoxHandle
.
All UI tests using TestFX
extend from GuiUnitTest
and handles are created for the corresponding UI test, which extends from either StageHandle
or NodeHandle
depending on the type used for UiPart
in the actual class to be tested.
Measuring Coverage of Integration Tests
We have used Jacoco
and Codecov
to monitor the code coverage of integration tests.
Create Code Coverage Report
Refer to the documentation on setting up Codecov
for setting up on CI/CD.
Read Code Coverage Report
For more information, check this. The above link also contains information on this.
6. Documentation
We take documentation very seriously as it not only helps users, but new developers in the team to quickly get up to speed with the project so that they can start contributing as soon as possible.
Useful Text Boxes
![:bulb: :bulb:](https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png)
alert-primary
to show tips for the developer
![:heavy_check_mark: :heavy_check_mark:](https://github.githubassets.com/images/icons/emoji/unicode/2714.png)
alert-success
to tell the developer what should be done
![:information_source: :information_source:](https://github.githubassets.com/images/icons/emoji/unicode/2139.png)
alert-info
to show information for the developer
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
alert-warning
to warn the user about performing a certain action
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
![:warning: :warning:](https://github.githubassets.com/images/icons/emoji/unicode/26a0.png)
alert-danger
to strongly warn the user about performing a certain action
![:construction: :construction:](https://github.githubassets.com/images/icons/emoji/unicode/1f6a7.png)
alert-dark
to indicate a feature under development
Using PlantUML
![: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.
For more information, you may view our special documentation page here.
7. Appendix
Planned Enhancements
-
To handle cases where the module code provided is not a valid NUS module, we propose the use of the NUSMods API to check whether the module exists. In this way, we can also tag the lessons with a more specific venue to improve recommendation of locations within NUS. This is currently not implemented as EduMate is an offline application, and existing modules will change overtime.
-
Apart from lessons, people may have commitments outside of NUS. To handle these cases, we propose to modify the
tag
command to take in a time and location to indicate that a person will be at the location at that time. This is currently not implemented as it is considered a new feature. -
To better create automated fields, we propose the use of
Optional
in our person fields. They would show “Unknown” if the field is not there, making it clearer that the fields have not been populated yet. This is currently not implemented as it would require major changes to the commands, as well as storage. -
The profile panel currently overspills when there are too many modules and groups. This can be solved in the future by converting the profile panel into a scroll pane, thereby allowing longer panels to be shown. This, however, requires us to refactor our UI components, which is not allowed at this phase.
-
Despite us not allowing it, the application still can enter full screen mode due to the settings on certain devices. This is unintended behaviour, as we intended EduMate to remain at a fixed size. One possible solution would be to re-enable the resizing of the application. However, this would require major changes to the UI, making it more responsive to such resizing events.
-
More explicit feedback messages for
tag
anduntag
commands for users.
Project Requirements
Product Scope
Target user profile
- has a need to manage a significant number of contacts
- frustrated in the struggle to find suitable meet up venues and timings
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
- is an NUS student
Value proposition
Help NUS students maintain both their social and academic life by lowering the barriers to meet up and make new friends within modules.
User Stories
As a … | I want to … | So that I can… |
---|---|---|
student | store my friends’ contact information | easily keep track of their availability for study sessions. |
student | store my tutors’ contact information | easily ask them for consultation sessions when they are available. |
student | update my profile | keep my information up to date. |
student | update the profile of a contact | keep their information up to date. |
student | keep track of what modules I share with my contacts | quickly find study partners. |
student | keep track of what groups I share with my contacts | quickly find contacts within the same friend group. |
student | assign lessons to my contacts | see when they are available for study sessions. |
student | see the availability of my contacts | plan my study sessions accordingly. |
student | view the profiles of my contacts | see their availability and contact information. |
student | remove a contact | free up space for adding other contacts. |
student | find contacts who share the most number of modules with me | easily form study groups. |
student | search for contacts based on specific criteria | find contacts with shared modules or tags. |
student | search for contacts who live near me | meet up with them at a place closer to home. |
student | find the contacts who share the most modules with me this semester | know who are likely to be my close friends this semester. |
student | sort my contacts by name | quickly find a specific person in my contact list. |
student | get suggestions for where to meet my friends | narrow down the search window for meet up locations. |
student | get suggestions for when to meet my friends | narrow down the search window for meet up timings. |
student | get suggestions for where to eat with my friends | easily find a place to grab a meal. |
student | get suggestions for when to eat with my friends | easily find a time to grab a meal. |
student | get suggestions for where to study with my friends | work on assignments with my friends. |
student | get suggestions for when to study with my friends | work on assignments with my friends. |
student | see a list view of suggested meet up locations and timings | compare them easily. |
student | schedule meetings with my contacts | meet up with my contacts without having to manually coordinate with each person. |
student | backup and restore my data | save my contact information and avoid losing them. |
student | keep track of my meet ups | remember who I am supposed to meet. |
student | view the contact details of my tutors and lecturers | get in touch with them when needed. |
student | run the application on my own operating system | safely transfer my data over when using a new device. |
student | use a simple interface | use the application without much hassle. |
Use Cases
(For all use cases below, the System is EduMate and the Actor is the User
, unless specified otherwise)
Use case: UC01 - View the list of all contacts
MSS
- User requests to list contacts.
-
EduMate shows a list of all contacts.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
2b. The list has already been filtered or sorted.
- 2b1. EduMate resets the filters and sorts.
Use case resumes from step 2.
Use case: UC02 - Display a help window using a command
MSS
- User requests for help.
-
EduMate shows a help window containing usages for commands.
Use case ends.
Use case: UC03 - Display a help window using a button
MSS
- User clicks the help button.
-
EduMate shows a help window containing usages for commands.
Use case ends.
Use case: UC04 - Clear the list of contacts
MSS
- User requests to clear the list of contacts.
-
EduMate shows an empty state.
Use case ends.
Use case: UC05 - Create a sample EduMate
- User requests to create a sample EduMate.
- EduMate resets the person list.
-
EduMate selects random contacts and adds them to the person list.
Use case ends.
Extensions
- 1a. The given number of samples is invalid.
- 1a1. EduMate shows an error message.
Use case: UC06 - Add a contact
MSS
- User requests to add a person to the contact list with their details.
- EduMate creates a new person and assigns an index to them.
- EduMate shows the list of contacts with the newly added person.
-
EduMate shows the added person’s information in the profile panel.
Use case ends.
Extensions
- 1a. The given name is invalid.
- 1a1. EduMate shows an error message.
- 1b. The person with the given name already exists in the contact list.
- 1b1. EduMate shows an error message.
- 1c. The given station name does not match our data.
- 1c1. EduMate shows an error message.
- 1d. The given phone number does not match our specifications.
- 1d1. EduMate shows an error message.
- 1e. The given telegram handle does not match our specifications.
- 1e1. EduMate shows an error message.
- 1f. The given email address does not match our specification.
- 1f1. EduMate shows an error message.
-
1g. No group tags are given.
Use case resumes from step 1.
-
1h. No module tags are given.
Use case resumes from step 1.
Use case: UC07 - Add a contact with missing fields
MSS
- User requests to add a person to the contact list with missing fields.
- EduMate creates a new person with default values and assigns an index to them.
- EduMate shows the list of contacts with the newly added person.
-
EduMate shows the added person’s information in the profile panel.
Use case ends.
Extensions
- 1a. The name is invalid or missing.
- 1a1. EduMate shows an error message.
- 1b. The person with the given name already exists in the contact list.
- 1b1. EduMate shows an error message.
- 2a. The email field is missing.
- 2a1. EduMate assigns an email based on the name.
Use case resumes from step 2.
- 2b. The telegram handle field is missing.
- 2b1. EduMate assigns a telegram handle based on the name.
Use case resumes from step 2.
- 2c. The station field is missing.
- 2c1. EduMate assigns a default station “Kent Ridge” to the person.
Use case resumes from step 2.
- 2d. The phone field is missing.
- 2d1. EduMate assigns a default phone number “00000000” to the person.
Use case resumes from step 2.
Use case: UC08 - View user information
MSS
- User requests to view a profile without an index.
-
EduMate shows the user’s profile in the profile panel.
Use case ends.
Use case: UC09 - View a contact’s information by name
MSS
- User requests to view a profile using the contact’s full name.
-
EduMate shows the contact’s profile in the profile panel.
Use case ends.
Extensions
- 1a. The given full name is not found.
- 1a1. EduMate shows an error message.
Use case: UC10 - View a contact’s information by index
MSS
- User requests to view a profile using the contact’s index.
-
EduMate shows the contact’s profile in the profile panel.
Use case ends.
Extensions
- 1a. The given index is invalid.
- 1a1. EduMate shows an error message.
Use case: UC11 - Edit a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to edit a person’s details with new information.
- EduMate edits the person’s information.
-
EduMate shows the edited person’s information in the profile panel.
Use case ends.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
- 2b. The given details are invalid.
- 2b1. EduMate shows an error message.
- 2c. The edited name is already found in the EduMate.
- 2c1. EduMate shows an error message.
Use case: UC12 - Delete a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to delete a person from the contact list.
- EduMate deletes the person from the contact list.
-
EduMate shows the user’s information in the profile panel.
Use case ends.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
Use case: UC13 - Tag a basic module to a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to add a basic module tag to a contact.
- EduMate tags the module to the contact.
- EduMate displays a list of successfully added modules.
-
EduMate displays the tagged person’s information in the profile panel.
Use case ends.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
- 2b. The given module code is invalid.
- 2b1. EduMate shows an error message.
- 3a. The module code exists in the person’s contact.
- 3a1. EduMate does not add any tags.
- 3a2. EduMate does not show the module in the feedback message.
Use case resumes at step 5.
Use case: UC14 - Tag a non-basic module to a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to add a non-basic module tag to a contact.
- EduMate assigns lessons to the contact.
- EduMate tags the module to the contact.
- EduMate displays a list of successfully added modules.
- EduMate displays the tagged person’s information in the profile panel.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
- 2b. The given module information is invalid.
- 2b1. EduMate shows an error message.
- 3a. The lesson clashes with the contact’s timetable.
- 3a1. EduMate shows an error message with details of clashes.
- 3b. The added lessons clash with each other.
- 3b1. EduMate shows an error message.
- 4a. The module does not exist in the contact’s module set.
- 4a1. EduMate adds the module and lesson to the contact’s module set.
- 4a2. EduMate displays the added lesson in the feedback message.
Use case resumes at step 6.
- 4b. The module exists in the contact’s module set but the lesson does not.
- 4b1. EduMate adds the module and lesson to the contact’s module set.
- 4b2. EduMate displays the added lesson in the feedback message.
Use case resumes at step 6.
- 4c. The module and lesson exist in the contact’s module set.
- 4c1. EduMate shows an error message.
Use case: UC15 - Untag a module from a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to remove a module tag from a contact.
- EduMate untags the module from the contact.
- EduMate removes the associated lessons from the contact.
- EduMate displays a list of successfully removed module tags.
-
EduMate displays the untagged person’s information in the profile panel.
Use case ends.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
- 2b. The given details are invalid.
- 2b1. EduMate shows an error message.
- 3a. The module does not exist in the contact’s module set.
- 3a1. EduMate does not remove any module.
Use case resumes at step 6.
- 3b. The module and lesson exists in EduMate.
- 3b1. EduMate removes that lesson.
- 3b2. EduMate removes the module from the module set if there are no more lessons.
Use case resumes at step 5.
- 3c. The module exists in EduMate, but the lesson does not.
- 3c1. EduMate does not remove the module.
- 3c2. EduMate does not display the module and lesson in the feedback message.
Use case resumes at step 6.
- 3d. The module does not come with a lesson.
- 3d1. EduMate removes the entire module from that person’s module set.
Use case resumes at step 6.
Use case: UC16 - Tag a group to a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to add a group tag to a contact.
- EduMate tags the group to the contact.
- EduMate displays a list of successfully added groups.
-
EduMate displays the tagged person’s information in the profile panel.
Use case ends.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
- 2b. The given details are invalid.
- 2b1. EduMate shows an error message.
- 3a. The group already exists in the group set.
- 3a1. EduMate does not display the group in the feedback message.
Use case resumes at step 5.
Use case: UC17 - Untag a group from a contact
MSS
- User requests to view a contact's information by name (UC09).
- User requests to remove a group tag from a contact.
- EduMate untags the group from the contact.
- EduMate displays a list of successfully removed groups.
-
EduMate displays the untagged person’s information in the profile panel.
Use case ends.
Extensions
- 2a. The given index is invalid.
- 2a1. EduMate shows an error message.
- 2b. The given details are invalid.
- 2b1. EduMate shows an error message.
- 3a. The group does not exist in the group set.
- 3a1. EduMate does not display the group in the feedback message.
Use case resumes at step 5.
Use case: UC18 - Find contacts based on search criteria
MSS
- User requests to view the list of contacts (UC01).
- User requests to find contacts based on search criteria.
-
EduMate shows a list of contacts satisfying the search criteria.
Use case ends.
Extensions
- 2a. The given details are invalid.
- 2a1. EduMate shows an error message.
- 3a. No contacts satisfy the criteria.
- 3a1. EduMate shows no contacts.
Use case ends.
Use case: UC19 - Sort contacts based on index
MSS
- User requests to view the list of contacts (UC01).
- User requests to sort contacts without using any prefix.
-
EduMate shows a list of contacts sorted by their index.
Use case ends.
Extensions
- 2a. The given details are invalid.
- 2a1. EduMate shows an error message.
-
3a. The sorted list is empty.
Use case ends.
Use case: UC20 - Sort contacts based on matching modules
MSS
- User requests to view the list of contacts (UC01).
- User requests to sort contacts based on number of common modules.
-
EduMate shows a list of contacts sorted by their number of shared modules, followed by their index.
Use case ends.
Extensions
- 2a. The given details are invalid.
- 2a1. EduMate shows an error message.
-
3a. The sorted list is empty.
Use case ends.
Use case: UC21 - Sort contacts based on multiple search criteria
MSS
- User requests to view the list of contacts (UC01).
- User requests to sort contacts based on multiple search criteria.
-
EduMate shows a list of contacts sorted by the criteria, followed by their index.
Use case ends.
Extensions
- 2a. The given details are invalid.
- 2a1. EduMate shows an error message.
-
3a. The sorted list is empty.
Use case ends.
Use case: UC22 - Recommend meet up locations and timings
MSS
- User requests to view the list of contacts (UC01).
- User requests to meet with a set of contacts.
-
EduMate shows a list of recommendations of where and when to meet.
Use case ends.
Extensions
- 2a. The set of contacts is empty.
- 2a1. EduMate shows an error message.
- 2b. Some indices are invalid.
- 2b1. EduMate shows an error message.
- 3a. There are no available timings to meet up.
- 3a1. EduMate shows an empty list.
Use case ends.
Use case: UC23 - Recommend places and times to eat
MSS
- User requests to view the list of contacts (UC01).
- User requests to eat with a set of contacts.
-
EduMate shows a list of recommendations of where and when to eat with contacts.
Use case ends.
Extensions
- 2a. The set of contacts is empty.
- 2a1. EduMate shows an error message.
- 2b. Some indices are invalid.
- 2b1. EduMate shows an error message.
- 3a. There are no available timings to eat.
- 3a1. EduMate shows an empty list.
Use case ends.
Use case: UC24 - Recommend study locations and timings
MSS
- User requests to view the list of contacts (UC01).
- User requests to study with a set of contacts.
-
EduMate shows a list of recommendations of where and when to study.
Use case ends.
Extensions
- 2a. The set of contacts is empty.
- 2a1. EduMate shows an error message.
- 2b. Some indices are invalid.
- 2b1. EduMate shows an error message.
- 3a. There are no available timings to study.
- 3a1. EduMate shows an empty list.
Use case ends.
Use case: UC25 - Organise a meet up using recommendation
MSS
- User requests to view the list of contacts (UC01).
- User requests to organise a meet up with contacts using a recommendation index.
-
EduMate creates a meet up and displays it in the meet up panel.
Use case ends.
Extensions
- 2a. The recommendation index is invalid.
- 2a1. EduMate shows an error message.
- 2b. Some contact indices are invalid.
- 2b1. EduMate shows an error message.
Use case: UC26 - Organise a meet up manually
MSS
- User requests to view the list of contacts (UC01).
- User requests to organise a meet up with contacts by typing the day, time and location.
-
EduMate creates a meet up and displays it in the meet up panel.
Use case ends.
Extensions
- 2a. Recommendation index is invalid.
- 2a1. EduMate shows an error message.
- 2b. Some contact indices are invalid.
- 2b1. EduMate shows an error message.
- 2c. The details provided are invalid.
- 2c1. EduMate shows an error message.
Use case: UC27 - Unorganise a meet up
MSS
- User requests to unorganise a meet up by index.
-
EduMate removes the organised meet up from the meet up panel.
Use case ends.
Extensions
- 1a. The given index is invalid.
- 1a1. EduMate shows an error message.
- 2a. The given index does not exist.
- 2a1. EduMate shows an error message.
Use case: UC28 - Save to a backup file
MSS
- User requests to save EduMate into a backup file.
-
EduMate saves the file in the “data” folder.
Use case ends.
Extensions
- 1a. The given file name is invalid.
- 1a1. EduMate shows an error message.
- 2a. A file with the name already exists within the folder.
- 2a1. EduMate replaces the file in the folder.
Use case ends.
Use case: UC29 - Load from a backup file
MSS
- User requests to load EduMate from a backup file.
-
EduMate loads the file in the “data” folder.
Use case ends.
Extensions
- 1a. The given file name is invalid.
- 1a1. EduMate shows an error message.
- 2a. The given file name does not exist.
- 2a1. EduMate shows an error message.
Use case: UC30 - Exit the application using a command
MSS
- User requests to exit the application.
- EduMate saves its current state.
-
EduMate closes.
Use case ends.
Use case: UC31 - Exit the application using a button
MSS
- User clicks the exit button.
- EduMate saves its current state.
-
EduMate closes.
Use case ends.
Use case: UC32 - View a previous command
MSS
- User presses the UP button.
-
EduMate shows the previous command in the command box.
Use case ends.
Extensions
- 2a. The user has already typed in the command box.
- 2a1. EduMate does not show the previous command.
Use case ends.
- 2b. There are no more previous commands.
- 2b1. EduMate does not show the previous command.
Use case ends.
Use case: UC33 - View the next command
MSS
- User presses the DOWN button.
-
EduMate shows the next command in the command box.
Use case ends.
Extensions
- 2a. The user has already typed in the command box.
- 2a1. EduMate does not show the next command.
Use case ends.
- 2b. There are no more next commands.
- 2b1. EduMate does not show the next command.
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.
- Any user action should be parsed and executed within 1 second.
- Each person should be able to hold up to 10 group and module tags without a noticeable sluggishness in performance for typical usage.
- The product does not require internet connection to function.
- The code should be open source.
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
-
1a. Download the jar file and copy into an empty folder
-
1b. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimal.
-
Add a new person
Scenario 1
Context: There is no contact named “Thomas” in EduMate.
Command executed: add n/Thomas s/Bedok p/12345678 e/thomas@gmail.com t/@thomas
Expected Output in the Person List: New person added to EduMate.
Scenario 2
Context: There is a contact named “Edward” in EduMate
Command executed: add n/Edward
Expected Output in the Command Response Box: This person already exists in the address book
.
View a person
Scenario 1
Context: None needed.
Command executed: view
Expected Output in the Profile Panel: The user’s profile is shown.
Scenario 2
Context: There exists a Person
with ContactIndex 5
in EduMate.
Command executed: view 5
Expected Output in the Profile Panel: The Person
with ContactIndex 5
is shown.
Scenario 3
Context: Thomas’ profile is present in EduMate.
Command executed: view n/Thomas
Expected Output in the Profile Panel: Thomas’ profile is shown.
Edit a person
Scenario 1
Context: There exists a Person
with ContactIndex 3
in EduMate.
Command executed: edit 3 n/Henry
Expected Output in the Person List: The Person Card with ContactIndex 3
contains the name “Henry”.
Scenario 2
Context: None needed.
Command executed: edit n/Gordon
Expected Output in Profile Panel: The user’s name is changed to Gordon.
Delete a person
Scenario 1
Context: There exists a Person
with ContactIndex 4
in EduMate.
Command executed: delete 4
Expected Output in the Person List: Person Card containing profile of Person
with ContactIndex 4
is removed.
Scenario 2
Context: There exists a Person
with ContactIndex 1, 2, 3
and 4
in EduMate and there is no other contact with the name “James”.
Command executed: delete 4
, add n/James e/james@gmail.com t/@james s/Bishan p/87654321
Expected Output in the Person List: Person Card containing Person
with ContactIndex 4
is removed. A new Person
named James is created and assigned ContactIndex 4
and appears on Person List.
Scenario 3
Context: None needed.
Command executed: delete
Expected Output in the Command Response Box: Invalid command format!
delete
: Deletes the person identified by the index number used in the displayed person list.
Scenario 4
Context: None needed.
Command executed: delete 0
Expected Output in the Command Response Box: Cannot delete your own profile!
Add a tag to a person
The following commands work under the assumption that there are no clashes in the timetable. In the scenario where a
tag
command results in any ModuleTag
having a clash, the entire command will be aborted.
Scenario 1
Context: Person
with ContactIndex 1
exists and does not have CS1234 ModuleTag
. User
has CS1234 as ModuleTag
.
Command executed: tag 1 m/CS1234
Expected Output in the Person List: CS1234 ModuleTag
will appear for Person
with ContactIndex 1
.
Scenario 2
Context: Person
with ContactIndex 1
exists and does not have CS1234 ModuleTag
. User
does not have CS1234 as ModuleTag
.
Command executed: tag 1 m/CS1234
Expected Output in the Person List: ‘Person’ with ContactIndex 1
will still be tagged, but will not appear in Profile Panel.
Scenario 3
Context: Person
with ContactIndex 2
exists and does not have CS2345 ModuleTag
. User
has CS2345 as ModuleTag
.
Command executed: tag 2 m/CS2345 mon 12 13
Expected Output in the Person List: Person
with ContactIndex 2
will have CS2345 ModuleTag
shown and Lesson
will be added.
Scenario 4
Context: Person
with ContactIndex 2
exists and has CS2345 ModuleTag
. User
has CS2345 as ModuleTag
.
Context executed: tag 2 m/CS2345 mon 12 13
Expected Output in the Person List: Lesson added.
Scenario 5
Context: Person
with ContactIndex 3
exists and does not have Friend
as a GroupTag
.
Command executed: tag 3 g/Friend
Expected Output in the Person List: Friend GroupTag
will appear on the Person Card containing profile of Person
with ContactIndex 3
.
Remove a tag from a person
Scenario 1
Context: Person
with ContactIndex 1
exists and has CS1234
as ModuleTag
. User
has CS1234 as ModuleTag
as well.
Command executed: untag 1 m/CS1234
Expected Output in the Person List: CS1234 ModuleTag
disappears from Person Card of Person
with ContactIndex 1
.
Scenario 2
Context: Person
with ContactIndex 2
exists and has CS2345 as ModuleTag
with a Monday class from 12PM to 1PM and it is his only Lesson
of CS2345. User
has CS2345 as ModuleTag
as well.
Command executed: untag 2 m/CS2345 mon 12 13
Expected Output in the Person List: CS2345 12PM - 1PM Lesson
on Monday is dropped. Moreover, the CS2345 ModuleTag
is also removed from the Person Card of Person
with ContactIndex 2
.
Scenario 3
Context: Person
with ContactIndex 3
exists and has Enemy as GroupTag
.
Command executed: untag 3 g/Enemy
Expected Output in the Person List: Person
with ContactIndex 3
will have Enemy GroupTag
removed from its Person Card.
Filter persons by keywords
Scenario 1
Context: None needed.
Command executed: find n/Albert
Expected Output in Person List: All contacts that have the word ‘Albert’ in their name.
Scenario 2
Context: None needed.
Command executed: find m/CS2103T
Expected Output in Person List: All contacts with CS2103T tag under Module
.
Scenario 3
Context: None needed.
Command executed: find n/Albert m/CS2103T
Expected Output in Person List: All contacts that have the word ‘Albert’ in their name and CS2103T tag under Module
.
Arrange persons by criteria
Scenario 1
Context: None needed.
Command executed: sort
Expected Output in Person List: Contacts are sorted by ContactIndex
in ascending order.
Scenario 2
Context: None needed.
Command executed: sort n/a
Expected Output in Person List: Contacts are sorted by name in ascending order.
Scenario 3
Context: None needed.
Command executed: sort g/d n/
Expected Output in Person List: Contacts are sorted by number of groups in descending order, with names as tiebreaks.
Generate a sample EduMate
Scenario 1
Context: None needed.
Command executed: sample 50
Expected Output in Person List: A random sample of 50 contacts is generated. Running it multiple times should result in different EduMates.
Scenario 2
Context: None needed.
Command executed: sample 101
Expected Output in Command Response Box: Error message for Invalid Size.
Suggest meet up locations and times
Scenario 1
Context: Person
with ContactIndex 1, 4
and 5
exists in EduMate.
Command executed: meet 1 4 5
Expected Output in Command Response Box: Suggestions on where and when to meet.
Scenario 2
Context: Person
with ContactIndex 1, 4
and 5
exists in EduMate.
Command executed: eat 1 4 5
Expected Output in Command Response Box: Suggestions on where and when to eat.
Scenario 3
Context: Person
with ContactIndex 1, 4
and 5
exists in EduMate.
Command executed: study 1 4 5
Expected Output in Command Response Box: Suggestions on where and when to study.
Organise and confirm meetings
Scenario 1
Context: Recommendation
with index 1 exists in Meet Up Recommendation Panel. Scheduled Meet Up Panel has no clashing meet ups with the Recommendation
with index 1.
Command executed: organise 1
Expected Output in Scheduled Meet Up Panel: Location
, TimePeriod
and names of contacts with ContactIndex 1, 4
and 5
will show.
Scenario 2
Context: Person
with ContactIndex 1, 4
and 5
exists in EduMate and they do not have any Commitment
from 4PM - 6PM on Thursday.
Command executed: organise 1 4 5 d/THURSDAY T/16 18 l/Starbucks
Expected Output in Scheduled Meet Up Panel: Location
of Starbucks, TimePeriod
of 4PM - 6PM and names of contacts with ContactIndex 1, 4
and 5
will show.
Cancel scheduled meetings
Scenario 1
Context: There is a scheduled MeetUp
in the Scheduled Meet Up Panel of index 1, 2 and 3.
Command executed: unorganise 2
Expected Output in Scheduled Meet Up Panel: MeetUp
of index 2 disappears, only left with MeetUps
of index 1 and 3.
Glossary
- Command Line Interface (CLI): A text-based user interface (UI) used to run programs, manage computer files and interact with the computer
- Graphical User Interface (GUI): A form of user interface that allows users to interact with electronic devices through graphical icons
- Mainstream OS: Windows, Linux, Unix, OS-X
- NUS: National University of Singapore
- MRT: Also known as the Mass Rapid Transit, Singapore high-speed railway system
- Pull Request (PR): An event that takes place in software development when a contributor/developer is ready to begin the process of merging new code changes with the main project repository
- Repo (Repository): A storage location for software packages, mainly residing on GitHub