By: AY1920S2-CS2103-W15-4
Since: Feb 2020
Licence: MIT
1. Setting up
1.1. Prerequisites
-
JDK
11
or above -
IntelliJ IDE
IntelliJ by default has Gradle and JavaFx plugins installed.
Do not disable them. If you have disabled them, go toFile
>Settings
>Plugins
to re-enable them.
1.2. Setting up the project in your computer
-
Fork this repo, and clone the fork to your computer
-
Open IntelliJ (if you are not in the welcome screen, click
File
>Close Project
to close the existing project dialog first) -
Set up the correct JDK version for Gradle
-
Click
Configure
>Project Defaults
>Project Structure
-
Click
New…
and find the directory of the JDK
-
-
Click
Import Project
-
Locate the
build.gradle
file and select it. ClickOK
-
Click
Open as Project
-
Click
OK
to accept the default settings.
1.3. Verifying the setup
-
Run the
clzzz.helper.Main
and try a few commands -
Run the tests to ensure they all pass.
1.4. Configurations to do before writing code
1.4.1. Configuring the coding style
This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,
-
Go to
File
>Settings…
(Windows/Linux), orIntelliJ IDEA
>Preferences…
(macOS) -
Select
Editor
>Code Style
>Java
-
Click on the
Imports
tab to set the order-
For
Class count to use import with '*'
andNames count to use static import with '*'
: Set to999
to prevent IntelliJ from contracting the import statements -
For
Import Layout
: The order isimport static all other imports
,import java.*
,import javax.*
,import org.*
,import com.*
,import all other imports
. Add a<blank line>
between eachimport
-
1.4.2. Updating documentation to match your fork
After forking the repo, the documentation will still have the SE-EDU branding and refer to the AY1920S2-CS2103-W15-4/main
repo.
If you plan to develop this fork as a separate product (i.e. instead of contributing to AY1920S2-CS2103-W15-4/main
), you should do the following:
-
Configure the site-wide documentation settings in
build.gradle
, such as thesite-name
, to suit your own project. -
Replace the URL in the attribute
repoURL
inDeveloperGuide.adoc
andUserGuide.adoc
with the URL of your fork.
1.4.3. Setting up CI
Set up Travis to perform Continuous Integration (CI) for your fork.
After setting up Travis, you can optionally set up coverage reporting for your team fork.
Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork. |
Optionally, you can set up AppVeyor as a second CI.
Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based) |
2. Design
2.1. Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
The .puml files used to create diagrams in this document can be found in the diagrams folder at docs/diagrams .
|
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 method where necessary.
Commons
represents a collection of classes used by multiple other components.
The following class plays an important role at the architecture level:
-
LogsCenter
: Used by many classes to write log messages to the App’s log file.
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.
Each of the four components
-
Defines its API in an
interface
with the same name as the Component. -
Exposes its functionality using a
{Component Name}Manager
class.
For example, the Logic
component (see the class diagram given below) defines it’s API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class.
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 deletepet 1
.
deletepet 1
commandThe sections below give more details of each component.
2.2. UI component
Written by Dylan Lim
The UI consists of a MainWindow
class that is made up of parts which can be classified broadly into 2 groups:
-
(Group 1) Parts that are always displayed at all times, which include
CommandBox
,FeedbackDisplay
,StatusBarFooter
, etc. These parts appear aboveMainWindow
in the class diagram for UI. -
(Group 2) Parts that are selectively displayed, depending on the command entered by the user. Only some of these parts will be shown at any one instance. These include the
Calendar
andDisplayList
components, andOverallStatistics
. These parts appear beneathMainWindow
in the class diagram for UI.
All the UI classes, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
.
In addition, each UI part has been styled using CSS. The custom CSS styling rules are defined in multiple CSS stylesheets, which can be found in the src/main/resources/view/stylesheets
folder.
The UI
component does the following:
-
Executes user commands using the
Logic
component. -
Listens for changes to
Model
data to update the UI with the modified data. -
Handles a returned
CommandResult
to perform additional actions, e.g. show the help window, exit the program, display the appropriate part or component from Group 2, etc.
2.3. Logic component
-
Logic
uses thePetTrackerParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a pet). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("deletepet 1")
API call.
deletepet 1
Command
The lifeline for DeletePetCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
Written by Zhu Ruicong
2.4. Model component
The Model
,
-
stores a
UserPref
object that represents the user’s preferences. -
stores the Pet Store Helper data. Note that the Pet Tracker keeps track of a UniquePetList, which in turn maintains the Pet system, Schedule system and Inventory(FoodCollection) system.
-
exposes an
ObservableList<Pet>
, anObservableList<Slot>
, and anObservableList<FoodCollection>
that are unmodifiable and can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -
does not depend on any of the other three components.
2.5. Storage component
Written by Chen Shenghao
The Storage
component,
-
can save
UserPref
objects in json format and read it back. -
can save the Pet Tracker data in json format and read it back.
2.6. Common classes
Classes used by multiple components are in the seedu.address.commons
package.
3. Implementation
This section describes some noteworthy details on how certain features are implemented.
3.1. Display switching feature
Written by Dylan Lim
3.1.1. Implementation
The display mechanism is facilitated by an ObservableList
of DisplayItem
s called filteredDisplayItems
, which is an attribute stored in ModelManager
.
Any class that is to be displayed as an item in a list implements the DisplayItem
interface. This interface has a single method named getDisplaySystemType
which returns the type of system to be displayed. In our program, the Pet
, Slot
, FoodCollection
, and FoodAmountAndPet
classes implement this interface.
Given below is an example usage scenario and how the display mechanism behaves at each step.
Step 1. The user opens the app the the 1st time. A few things happen at start-up:
-
In
Model
(ModelManager
),filteredDisplayItems
is created, and is set to bind tofilteredPets
. This way,filteredDisplayItems
contains all the elements offilteredPets
, and any changes tofilteredPets
will also be automatically propogated tofilteredDisplayItems
. -
In the
MainWindow
, aDisplayListPanel
and aCalendarPanel
are initialized. TheDisplayListPanel
is created withfilteredDisplayItems
as its backing list, while theCalendarPanel
will be initialized with theList
ofSlot
s obtained fromlogic.getPetTracker().getSlotList()
. -
The
resultDisplayPlaceholder
component in theMainWindow
is set to display theDisplayListPanel
. As such, the user sees the list of pets as the initial display.
Step 2. The user executes display c
to have the slots displayed in calendar view. Since filteredDisplayItems
is not used for displaying the calendar, it is not changed when the display
command calls Model#changeDisplaySystem
. Upon receiving back the result of the command in MainWindow
, resultDisplayPlaceholder
is changed to display the CalendarPanel
instead of the DisplayListPanel
.
The following sequence diagrams shows how the display is switched to calendar:
The lifeline for CommandResult , DisplayParser , and DisplayCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
Step 3. The user executes display s
to have the slots displayed in a list. The display
command calls Model#changeDisplaySystem
, which causes filteredDisplayItems
to re-binded to filteredSlots
. Since the program should now display a list of items instead of a calendar, upon receiving back the result of the command in MainWindow
, resultDisplayPlaceholder
is changed to display the DisplayListPanel
from CalendarPanel
.
The following sequence diagrams shows how the display is switched to slots list view:
The lifeline for CommandResult , DisplayParser , and DisplayCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
The following activity diagram summarizes what happens in MainWindow#executeCommand
upon the return of a command result:
3.2. Schedule feature
Written by Zhao Mingjian
3.2.1. Implementation
The schedule feature uses instances of class Slot
to organise bathing schedule for the pets. Each Slot
contains a
starting time of the bath, stored internally as a LocalDateTime
, and the duration of the bath stored internally as a
Duration
. It stores a reference to the Pet
in the ModelManager
as specified by the user.
Given below is an example usage scenario and how the Schedule
mechanism behaves at each step.
Step 1. The user launches the application with some pets stored (Garfield
, for instance). ObservableList<Slot>
in Schedule
is currently empty.
Step 2. The user executes addslot n/Garfield t/1/4/2020 1200 d/120
command to create a Slot
for Garfield
.
The AddSlotCommandParser
calls parsePet()
in SlotParserUtil
, which then takes in the Model
passed in to find a
reference for the specific Pet
with Model.getPet()
. Prior to this stage, if the name string is invalid, a
ParseException(MESSAGE_INVALID_PETNAME)
will be thrown. Or the program cannot find the Pet
in the model, a
ParseException(MESSAGE_PET_DOES_NOT_EXIST)
will be thrown. This ensures that every slot created actually points to an
existing Pet
found in PetTracker
.
If parsePet() fails its execution, no new Slot is created.
|
Step 3. New Slot
is created.
Step 4. The user now decides that this exact slot should be occupied by another pet, and decides to edit it, executing
the editslot
command.
Step 5. SlotParserUtil
is used again to create a reference to a pet in the ModelManager
.
Step 6. The user now decides that they need to see slots occupied by a particular pet on a particular date, executing
the findslots n/Garfield t/1/4/2020
command.
Step 7. The FindSlotCommand
reduces the two predicates* and pass it to ModelManager
to create a filtered list of
slots.
*The FindSlotCommand
uses the following classes which both inherit Predicate<Slot>
to search for the user specified
slots:
-
SlotPetNamePredicate()
— Internally stores theName
to search for, and compares it withgetPet().getName().fullName
. -
SlotDateTimePredicate()
— Internally stores theLocalDateTime
to search for (Timing will be ignored), and compares it withgetDate()
.
The activity diagram below is an illustration of the flow of events that happen in the model component when the steps above occurs.
Given below is an example usage scenario that demonstrates how the Schedule
system integrates with the Pet
system.
Step 1. The user launches the application with a pet stored: Garfield
. A single instance of Slot
occupies
ObservableList<Slot>
in Schedule
, whose parameters are: petName: Garfield
,
dateTime: 11/4/2020 1200
, duration: 40
. Upon launch, a PetListChangeListener
will be attached to internalList
of
UniquePetList
.
Step 2. The user executes deletepet 1
command to delete Garfield
from the UniquePetList
. When user deletes the pet,
function onChanged
in PetListChangeListener
is called. This function calls removeExcessSlot
within the
PetListChangeListener
for each pet removed.
Step 3. removeExcessSlot
calls remove
in Schedule
to remove slots based on the name of the removed pet.
Step 4. The user now have successfully removed Garfield
and all the slots the pet used to occupy.
The sequence diagram below is an illustration of the flow of events that happen in the model component when the steps above occurs.
3.2.2. Design Considerations
Aspect: How schedule stores the pets internally
-
Alternative 1 (current choice): Makes a reference to the the memory address in
ModelManager
.-
Pros: When the pet is edited, it is easier to update the corresponding slot. Also reduces save file size and conserve system memory as there will be no duplicate information.
-
Cons: Harder to implement and test. Testing requires a sample list of pets to be instantiated first.
-
-
Alternative 2: Simply create a new Pet.
-
Pros: Easy to implement and test (A refactor of
Pet
), low coupling withModel
. -
Cons: Harder to synchronize with any changes in
UniquePetList
-
3.3. Calendar feature
Written by Dylan Lim
3.3.1. Implementation
The class diagram for calendar-related components, as shown in Figure 5, “Structure of the Calendar Component in UI” previously, is reproduced in this section for convenience.
The construction of the calendar is accomplished by the construct()
method in CalendarPanel
. Based on the list of all slots in the system, it determines which type of CalendarRegion
is to be placed at which position of the GridPane
in CalendarPanel
.
CalendarRegion
s marked outIn tha above annotated screenshot, rectangles with the following border color correspond to the following CalendarRegion
(from left to right, on 7/4/2020):
-
Purple:
CalendarDate
. It is used to display the day and date of slots in the same row, and it always positioned to the left. -
Green:
CalendarSlot
. It constitutes a single slot. -
Yellow:
CalendarBuffer
. It acts a buffer between other regions, for padding purposes. -
Blue:
CalendarConflict
. It represents a region of more than two or more conflicted slots.
The following activity diagram outlines the rough flow of calendarPanel#construct
:
CalendarRegion
for slot(s) in holding.CalendarRegion
s are created sequentially, from left to right (increasing time of day), then top to bottom (increasing date). Each time a CalendarRegion
is created, it is placed onto a GridPane
based on the row index, and its starting time.
3.3.2. Design Considerations
Aspect: Construction of calendar upon addition / deletion / edition of slot(s)
-
Alternative 1 (current choice): Clear all components in
CalendarPanel
and redraw everything.-
Pros: Relatively simpler to implement.
-
Cons: Might take a long time to draw if system has many slots.
-
-
Alternative 2: Modify only the component that is related the affected slot.
-
Pros: Better performance.
-
Cons: More complex implementation needed to determine and resolve conflicts, if any.
-
3.4. Inventory feature
Written by Zhu Ruicong
3.4.1. Implementation
The Inventory feature gives a summary of all the food items involved in a pet tracker system.
It is supported by FoodCollection
which resembles a collection of food of the same type and FoodCollectionList
which is a list of these collections.
A FoodCollectionList
is stored as an attribute of UniquePetList
for the following reasons:
-
The list of
FoodCollection
items associated with aUniquePetList
can be directly derived from theUniquePetList
itself. -
Changes in FoodCollection occurs only if there is a change in
UniquePetList#internalList
.
Data stored in FoodCollectionList
is exposed to ModelManager
through UniquePetList
and PetTracker
as an unmodifiable ObservableList<FoodCollection>
.
ModelManager
then passes the list of FoodCollection
to UI for display as a list of DisplayItem
when display i
is called.
The following shows a typical usage scenario that involves the Display Inventory feature.
-
Step 1: The user launches the application. A
UniquePetList
is initialized inPetTracker
, upon which aFoodCollectionList
item is created to store the food data of the pets in the list(if it is an empty list,FoodCollectionList
is also stores an empty list ofFoodCollection
) -
Step 2: The user executes 'display i' command. The
display
command calls Model#ChangeDisplaySystem() and thei
display type determines the displayed list is switched toObservableList<FoodCollection>
.Model#getFilteredDisplayList()
then acquires the list and sends it to Ui unit for display. -
Step 3: The user inputs a command that modifies the
UniquePetList
, e.g 'editpet 1 f/catfood:100'.UniquePetList#internalList
is an instance ofObservableList<Pet>
. Thus when it is modified, aListChangeListener<Pet>
is woken up and it callsUniquePetList#updateFoodCollectionList()
to update theFoodCollectionList
according to the modified Pet list.
The sequence diagram below is an illustration of the flow of events that happen in the logical component when Step 2
above occurs.
display i
CommandNote that there is no explicit initialization or update for FoodCollection
in FoodCollectionList
. FoodCollectionList
is synchronized to the list of pet(UniquePetList#internalList
) in the UniquePetList
through ListChangeListener<Pet>
, which is triggered whenever there is a change in the pet list. The sequence diagram below and the steps illustrates this process:
-
Step 1:
UniquePetList
passes itsinternalList
(referred to aspetList
in the sequence diagram below). -
Step 2:
FoodCollectionList
creates a newFoodCollectionList
objecttemp
and extractstemp#internalList
. -
Step 3: Replaces the content in the current
internalList
with the content in the extractedtemp#internalist
.
ListChangeListener<Pet>
is triggered3.4.2. Design Considerations
Aspect: Maintaining the collection of food in a pet tracker
-
Alternative 1(current choice): Maintains the list as an attribute of
UniquePetList
.-
Pros: Easier to initialize and update the list.
-
Cons: Less extendability. Adding additional food items in inventory(independent of pet list) is difficult.
-
-
Alternative 2: Maintains a list of food collections separate from
UniquePetList
.-
Pros: Higher Extendability that supports more independent operations of FoodCollection List.
-
Cons: More difficult to constantly update and maintain the food collection list should food list changes.
-
Aspect: Updating the collection of food when pet list is modified.
-
Alternative 1(current choice): Replace the entire list by a new food collection list created from the updated pet list.
-
Pros: Easy to implement and no adaptation is required for different types of modification of pet list.
-
Cons: Computationally intensive when there is a huge pet list.
-
-
Alternative 2: Modify
FoodCollection
affected by the command.-
Pros: Less computationally intensive and more responsive given a large database.
-
Cons: Adaptations for each pet related commands is required since the food list can be affected in different ways.(e.g addition, modification, deletion)
-
3.5. Conflict feature
Written by Zhao Tianqi
3.5.1. Implementation
The conflict feature shows a list of all slots that has overlapping time period.
-
It makes uses of
SlotConflictPredicate
which implementsSlotPredicate
to filter slots that has a conflicting timing with some other slots. -
If the screen is displaying shortlisted slots,
conflics
only shows slots with conflicts among the shortlisted list. Otherwise, it shows conflicts in the full slot list -
The command automatically switch display to slots.
Below is a scenario of using conflicts
command:
-
Step 1: The user inputs "conflicts" in the command line. The Logic component processes the input and creates a new instance of
ConflictCommand
-
Step 2: The
ConflictCommand
accessfilteredSlots
inModel
, and create a new instance ofSlotConflictPredicate
withfilteredSlots
. -
Step 3:
Model
filters slots that is conflicting among thefilteredSlots
using theSlotConflictPredicate
. -
Step 4:
ConflictCommand
changescurrentDisplaySystemType
inModel
toDisplaySystemType.SCHEDULE
such that the window will display shortlisted conflicting slots.
conflicts
Command3.5.2. Design Considerations
Aspect: Data structure to store slots and method of checking for conflicts:
-
Alternative 1 (current choice): Store slots in a list, with pairwise comparison between elements to find out conflicts
-
Pros: More straightforward in implementation
-
Cons: The performance might not be scalable. Algorithm does not minimize the computation time.
-
-
Alternative 2: Store slots in an interval tree
-
Pros: Searching for conflicting slots takes less time. The algorithm is more efficient.
-
Cons: Implementation of the data structure needs relatively high level of commitment.
-
3.6. Statistics
Written by Zhao Tianqi
3.6.1. Implementation
We are generating the overall statistics of Pet Store Helper and translate the data in a user-friendly manner.
-
OverallStats
under UI component handles the translation of three sets of data: list of pets, schedule, and list of inventory. -
Data in
OverallStats
is obtained fromLogic
. -
The statistics displayed will automatically update if there is a change in any related information.
How we implemented overall statistic on UI:
-
The statistics for pets are shown in a form of pie chart, while the pets are grouped according to their species.
-
The schedule statistics is in the form of a timetable of recent 3 days. Each slot is represented as a shaded rectangle in the timetable.
-
The inventory data are generated from the list of pets, and grouped together by their names, such that users have a better understanding of overall food consumption. The list of inventory is represented as a bar chart.
Here is the process of how the overall statistics is displayed to the user:
-
Step 1: The user key in the command 'stats', then the Logic component processes the input and creates an instance of
StatsCommand
. TheStatsCommand
first callsModel#updateAll()
to make sure that the model will updatefilteredPets
,filteredSlots
, andfilteredFoodCollections
to show the full list ofPet
,Slot
andFoodCollection
in thePetTracker
. After that, theStatsCommand
callsModel#changeDisplaySystem(DisplaySystemType.STATISTICS
) such that the application will later switch the window to showOverallStats
. In the Ui component, there is a new instance ofOverallStats
created, whileModel#getFilteredPets
,Model#getFilteredSlots
, andModel#getFilteredFoodCollections
are passed in the instance for processing.OverallStats
then generates diagrams according to the data passes in. -
Step 2: The user inputs a command that modifies the UniquePetList, e.g 'editpet 1 s/cat'. The
CommandResult
of anyEditPetCommand
hastype
withDisplaySystemType.NO_CHANGE
. The Ui component identifies thetype
in theCommandResult
and then refresh the window if it isNO_CHANGE
. In this case, the window will refresh and create another new instance ofOverallStats
with the updated list of pets. Therefore the window always shows statistics of the most updated list of pets, slots and food collections.
Following is the sequential diagram of the command stats
stats
Commandstats
Command3.6.2. Design Considerations
Aspect: How to update diagrams when there are changes
-
Alternative 1 (current choice): Refresh the screen
-
Pros: Easy to implement and only need to refer to
model
to get data. -
Cons: Takes time to process the whole lists of data even though there is only one small change in one of the item (pets, slots or foo collection). This approach might be time consuming when the data size is too large.
-
-
Alternative 2: Make use of
Listener
to detect change inUniquePetList
and make changes accordingly-
Pros: Avoid unnecessary processing of data. e.g. The diagrams need not be regenerated when there is no change in pet species, pet food, and recent schedule.
-
Cons: More complicated implementation. There might be more coupling between
OverallStats
under Ui component and Listener class under Model component.
-
3.7. Back up and load feature
Written by Chen Shenghao
3.7.1. Implementation
The back up/load mechanism is facilitated by Storage
.
Storage
is extended to implement the following operations:
-
savePetTracker#(ReadOnlyPetTracker, LocalDateTime)
— callssavePetTracker#(ReadOnlyPetTracker, Path)
after converting LocalDateTime to Path -
savePetTracker#(ReadOnlyPetTracker, Path)
— saves pet tracker data to specified path
The back up/load mechanism follows the exact same steps taken when data is saved after each operation and read at initialization. This ensures maximum compatibility and reduces the need for additional code.
backup
should never fail unless the saving of data after every operation also fails. For 'load', there are two additional caveats, the specified file should exist and be in the correct format. This is unlike the reading of data at initialization which simply resorts to an empty file instead if these issues occur.
The following sequence diagram shows how the backup operation works:
The following sequence diagram shows how the load operation works:
3.7.2. Design Considerations
Aspect: How back up & load executes
-
Alternative 1 (current choice): Executed by Command, following general pattern for Command
-
Pros: Easy to implement, able to rely on established pattern for Command.
-
Cons: Storage is exposed to classes in the
parser
package, which should not have access to its methods
-
-
Alternative 2: Executed by LogicManager, which already saves data to hard disk after every operation
-
Pros: Storage does not have to be passed to classes in the
parser
package -
Cons: Requires passing instruction back to LogicManager, actual operation performed after end of Command#execute(), unable to obtain reliable success/error message.
-
3.8. Logging
We are using java.util.logging
package for logging. The LogsCenter
class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevel
setting in the configuration file (See Section 3.9, “Configuration”) -
The
Logger
for a class can be obtained usingLogsCenter.getLogger(Class)
which will log messages according to the specified logging level -
Currently log messages are output through:
Console
and to a.log
file.
Logging Levels
-
SEVERE
: Critical problem detected which may possibly cause the termination of the application -
WARNING
: Can continue, but with caution -
INFO
: Information showing the noteworthy actions by the App -
FINE
: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
3.9. Configuration
Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json
).
4. Documentation
We use Asciidoc for writing documentation.
We chose Asciidoc over Markdown because Asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting. |
4.1. Editing Documentation
We used Gradle to render .adoc
files locally to preview the end results of edits. Also, we downloaded the AsciiDoc plugin for Intellij, which allowed use to preview the changes made to the .adoc
files in real-time.
4.2. Editing Diagrams
We used the PlantUML plugin for Intellij to create and update the UML diagrams.
4.3. Publishing Documentation
We used Travis for deployment of Github Pages for publishing documentation.
4.4. Converting Documentation to PDF format
We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.
4.5. Site-wide Documentation Settings
The build.gradle
file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.
Attributes left unset in the build.gradle file will use their default value, if any.
|
Attribute name | Description | Default value |
---|---|---|
|
The name of the website. If set, the name will be displayed near the top of the page. |
not set |
|
URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar. |
not set |
|
Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items. |
not set |
4.6. Per-file Documentation Settings
Each .adoc
file may also specify some file-specific asciidoc attributes which affects how the file is rendered.
Asciidoctor’s built-in attributes may be specified and used as well.
Attributes left unset in .adoc files will use their default value, if any.
|
Attribute name | Description | Default value |
---|---|---|
|
Site section that the document belongs to.
This will cause the associated item in the navigation bar to be highlighted.
One of: * Official SE-EDU projects only |
not set |
|
Set this attribute to remove the site navigation bar. |
not set |
4.7. Site Template
The files in docs/stylesheets
are the CSS stylesheets of the site.
You can modify them to change some properties of the site’s design.
The files in docs/templates
controls the rendering of .adoc
files into HTML5.
These template files are written in a mixture of Ruby and Slim.
Modifying the template files in |
5. Testing
5.1. Running Tests
There are two ways to run tests.
Method 1: Using IntelliJ JUnit test runner
-
To run all tests, right-click on the
src/test/java
folder and chooseRun 'All Tests'
-
To run a subset of tests, you can right-click on a test package, test class, or a test and choose
Run 'ABC'
Method 2: Using Gradle
-
Open a console and run the command
gradlew clean test
(Mac/Linux:./gradlew clean test
)
5.2. Types of tests
We have three types of tests:
-
Unit tests targeting the lowest level methods/classes.
e.g.clzzz.helper.commons.util.StringUtilTest
-
Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
e.g.clzzz.helper.storage.StorageManagerTest
-
Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
e.g.clzzz.helper.logic.LogicManagerTest
6. Dev Ops
6.1. Build Automation
We use Gradle for build automation.
6.2. Continuous Integration
We use Travis CI and AppVeyor to perform Continuous Integration.
6.3. Coverage Reporting
We use Coveralls to track the code coverage.
6.4. Documentation Previews
When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged.
6.5. Making a Release
Here are the steps to create a new release.
-
Update the version number in
MainApp.java
. -
Generate a JAR file using Gradle.
-
Tag the repo with the version number. e.g.
v0.1
-
Create a new release using GitHub and upload the JAR file you created.
6.6. Managing Dependencies
Project dependencies are managed by Gradle, and are not included in this repository.
List of dependencies:
Appendix A: Product Scope
Written collaboratively, collated by Zhao Mingjian
Target user profile:
-
has a need to manage their pet store with a variety of animals and features
-
has a need to make schedules for pet grooming and ensure no-conflict in the scheduling
-
prefer desktop apps over other types
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: manage pets, pet consumables and schedule faster than a typical mouse/GUI driven app
Appendix B: User Stories
Written collaboratively, collated by Zhao Mingjian
Priorities: High (must have) - * * *
, Low (nice to have) - * *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
|
user |
key in a new pet, enter its breed, age, size and food consumption. |
keep track of the pets I have in my store and their details |
|
user |
delete a pet |
remove pets that I have sold or no longer taking care of |
|
user |
find a pet by name, species or tags |
locate details of the pets without having to go through the entire list |
|
user |
keep track of pet food, cleaning products and other consumables |
not run low on items needed to keep the pets healthy |
|
user |
schedule when to bathe my own (in-store) pets |
avoid clashes in bathing schedule |
|
user |
view the schedule and see which slots are available to bathe the customers' pets |
avoid clashes in bathing schedule |
|
user |
see which free slots are available for grooming |
avoid clashes in grooming |
|
user |
view a statistical summary of the pets, stocks and schedule |
handle logistics of the store more efficiently |
|
user |
add photos for the pets in store to illustrate |
easier to make a mental link between the actual pets in the store and the names |
|
user |
keep track of the cost and revenue generated by each pet |
so to buy the more popular ones in next restock |
Appendix C: Use Cases
Written by Zhao Mingjian
(For all use cases below, the System is the PSH
and the Actor is the user
, unless specified otherwise)
Use case: Delete pet
MSS
-
User requests to list pets
-
PSH shows a list of pets
-
User requests to delete a specific pet in the list
-
PetTracker deletes the pet
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PSH shows an error message.
Use case resumes at step 2.
-
Use case: Removing a bathing slot
MSS
-
User requests to show schedule
-
PSH shows schedule of that day
-
User requests of delete a slot at a specified timing
-
PSH deletes the slot
Use case ends.
Extensions
-
2a. There is currently conflict in the scheduling (i.e. One slot begins before the previous one ends), the latter slot is shown in red.
Use case resumes at step 2
-
3a. The given timing does not exist.
-
3a1. PSH shows an error message.
Use case resumes at step 2.
-
Appendix D: 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 500 pets + items in total 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.
Appendix F: Instructions for Manual Testing
Applied from AB3 by Zhao Mingjian
Given below are instructions to test the app manually.
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
F.1. Launch and Shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample pets and slots. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
F.2. Switching display
-
Change display of the program
-
Prerequisites: Program is pre-populated with the sample data of pets and slots.
-
Test case:
display s
Expected: Program display is changed to show list of slots. -
Test case:
display c
Expected: Program display is changed to show slots in calendar view. -
Test case:
display i
Expected: Program display is changed to show inventory. -
Test case:
display p
Expected: Program display is changed to back show list of pets. -
Test case:
display x
Expected: Program display does not change. Error message shown. -
Other incorrect display commands to try:
display
,display I
,Display i
Expected: Similar to previous.
-
-
F.3. Adding a pet
-
Adding a pet while all pets are displayed
-
Prerequisites: Program is showing list of pets to (run
display p
)-
Test case:
addpet n/Alice g/female b/13/11/2015 s/dog f/Dog Food: 10 t/cute
Expected: A new pet "Alice" is added to the end of the pet list. Details of the newly added pet shown above the list of pets. -
Test case:
addpet n/Alice g/female b/24/12/2015 s/rabbit f/Rabbit Food: 15 t/fluffy
Expected: No pet is added. Error details shown above the list of pets. -
Other incorrect addpet commands to try:
addpet n/Bubbles g/helicopter b/8/10/2015 s/cat f/Cat Food: 15 t/white
,addpet n/Bubbles g/female b/78/10/2015 s/cat f/Cat Food: 15 t/white
Expected: No pet is added, with the relevant and appropriate error details shown above the list of pets.
-
-
F.4. Deleting a pet
-
Deleting a pet while all pets are displayed
-
Prerequisites: Display all pets using the
display p
command. Multiple pets in the display. -
Test case:
deletepet 1
Expected: First pet is deleted from the list. Details of the deleted pet shown above the list of pets. Slots that the pet used to occupy is also deleted. -
Test case:
deletepet 0
Expected: No pet is deleted. Error details shown above the list of pets. Slots remain the same. -
Other incorrect delete commands to try:
deletepet
,deletepet x
(where x is larger than the list size)
Expected: Similar to previous.
-
F.5. Adding a slot
-
Adding a slot while all slots are displayed
-
Prerequisites: Program is showing list of slots to (run
display s
). Program is pre-populated with the sample data of pets and slots.-
Test case:
addslot n/Bob t/6/4/2020 1000 d/60
Expected: A new slot is added to slot list. Details of the newly added slot shown above the list of slots. Because it is the earliest of all slots, it appears at the 1st slot in the list. -
Test case:
addslot n/Cindy t/67/4/2020 1000 d/60
Expected: No slot is added. Error details shown above the list of slots. -
Other incorrect addslot commands to try:
addslot
,addslot n/Duke t/6/4/2020 1130 d/60
,addslot n/Cindy t/6/4/2020 2300 d/120
Expected: No slot is added, with the relevant and appropriate error details shown above the list of slots.
-
-
F.6. Deleting a slot
-
Deleting a slot while all slots are displayed
-
Prerequisites: Program is showing list of slots to (run
display s
). Program is pre-populated with the sample data of pets and slots.-
Test case:
deleteslot 1
Expected: First slot is deleted from the list. Details of the deleted slot shown above the list of slots. -
Test case:
deleteslot 0
Expected: No slot is deleted. Error details shown above the list of slots. -
Other incorrect deleteslot commands to try:
deleteslot
,deleteslot x
(where x is larger than the list size)
Expected: Similar to previous.
-
-
F.7. View conflicted slots
-
Viewing slots with conflicts
-
Prerequisites: Program is pre-populated with the sample data of pets and slots.
Initial view: On Mon 6/4/2020, there is a single slot occupied by "Gru" from 13:00 - 14:40 (as per the sample data). It is not in conflict.-
Test case:
conflicts
Expected: Program successfully shows no slots with message "0 slots listed!", as the sample data has no slots in conflict. -
Test case:
addslot n/Bob t/6/4/2020 1400 d/60
Expected: A new slot is added to slot list. Details of the newly added slot shown above the list of slots. This newly added slot and the slot occupied by Gru are now marked as "[CONFLICT]" -
Test case:
conflicts
Expected: Program successfully shows only the two slots on 6/4/2020 with message "2 slots listed!"
-
-
F.8. Saving data
-
Dealing with missing/corrupted data files
-
Prerequisites: List of pets is well populated.
-
Test case: changing pet name manually to an invalid name in pettracker.json
Expected: Data is not loaded. Start with an empty Pet Tracker. -
Test case: changing pet name of a slot manually to pet that does not exist in pettracker.json
Expected: Data is not loaded. Start with an empty Pet Tracker.
-