By: Team T09-2      Since: Sep 2018      Licence: MIT

1. Setting up

1.1. Prerequisites

  1. JDK 9 or later

    JDK 10 on Windows will fail to run tests in headless mode due to a JavaFX bug. Windows developers are highly recommended to use JDK 9.
  2. IntelliJ IDE

    IntelliJ by default has Gradle and JavaFx plugins installed.
    Do not disable them. If you have disabled them, go to File > Settings > Plugins to re-enable them.

1.2. Setting up the project in your computer

  1. Fork this repo, and clone the fork to your computer

  2. Open IntelliJ (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first)

  3. Set up the correct JDK version for Gradle

    1. Click Configure > Project Defaults > Project Structure

    2. Click New…​ and find the directory of the JDK

  4. Click Import Project

  5. Locate the build.gradle file and select it. Click OK

  6. Click Open as Project

  7. Click OK to accept the default settings

  8. Open a console and run the command gradlew processResources (Mac/Linux: ./gradlew processResources). It should finish with the BUILD SUCCESSFUL message.
    This will generate all resources required by the application and tests.

1.3. Verifying the setup

  1. Run the seedu.address.MainApp and try a few commands

  2. 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,

  1. Go to File > Settings…​ (Windows/Linux), or IntelliJ IDEA > Preferences…​ (macOS)

  2. Select Editor > Code Style > Java

  3. Click on the Imports tab to set the order

    • For Class count to use import with '*' and Names count to use static import with '*': Set to 999 to prevent IntelliJ from contracting the import statements

    • For Import Layout: The order is import static all other imports, import java.*, import javax.*, import org.*, import com.*, import all other imports. Add a <blank line> between each import

Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.

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 se-edu/addressbook-level4 repo.

If you plan to develop this fork as a separate product (i.e. instead of contributing to se-edu/addressbook-level4), you should do the following:

  1. Configure the site-wide documentation settings in build.gradle, such as the site-name, to suit your own project.

  2. Replace the URL in the attribute repoURL in DeveloperGuide.adoc and UserGuide.adoc with the URL of your fork.

1.4.3. Setting up CI

Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.

After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).

Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork.

Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).

Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based)

1.4.4. Getting started with coding

When you are ready to start coding,

  1. Get some sense of the overall design by reading Section 2.1, “Architecture”.

  2. Take a look at Appendix A, Suggested Programming Tasks to Get Started.

2. Design

2.1. Architecture

Architecture
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .pptx files used to create diagrams in this document can be found in the diagrams folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture.

Main has only one class called MainApp. It is responsible for,

  • At app launch: Initializes the components in the correct sequence, and connects them up with each other.

  • At shut down: Shuts down the components and invokes cleanup method where necessary.

Commons represents a collection of classes used by multiple other components. Two of those classes play important roles at the architecture level.

  • EventsCenter : This class (written using Google’s Event Bus library) is used by components to communicate with other components using events (i.e. a form of Event Driven design)

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

The rest of the App consists of four components.

  • 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.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

Events-Driven nature of the design

The Sequence Diagram below shows how the components interact for the scenario where the user issues the command TDL_delete 1.

SDforDeleteTask
Figure 3. Component interactions for TDL_delete 1 command (part 1)
Note how the Model simply raises a TodoListChangedEvent when the To-do List data are changed, instead of asking the Storage to save the updates to the hard disk.

The diagram below shows how the EventsCenter reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.

SDforDeleteTaskEventHandling
Figure 4. Component interactions for TDL_delete 1 command (part 2)
Note how the event is propagated through the EventsCenter to the Storage and UI without Model having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components.

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 5. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, TaskListPanel, ExpenditureListPanel, StatusBarFooter, CalendarPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The UI component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml

The UI component,

  • Executes user commands using the Logic component.

  • Binds itself to some data in the Model so that the UI can auto-update when data in the Model change.

  • Responds to events raised from various parts of the App and updates the UI accordingly.

2.3. Logic component

LogicClassDiagram
Figure 6. Structure of the Logic Component

API : Logic.java

  1. Logic uses the AddressBookParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a person) and/or raise events.

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("TDL_delete 1") API call.

DeleteTaskSdForLogic
Figure 7. Interactions Inside the Logic Component for the TDL_delete 1 Command

2.4. Model component

ModelClassDiagram
Figure 8. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the To-do List and Expenditure Tracker data.

  • exposes an unmodifiable ObservableList<Task> and ObservableList<Expenditure> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.

  • does not depend on any of the other three components.

2.5. Storage component

StorageClassDiagram
Figure 9. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the To-do List and Expenditure Tracker data in xml format and read it back.

2.6. Common classes

Classes used by multiple components are in the seedu.addressbook.commons package.

3. Implementation

This section describes some noteworthy details on how certain features are implemented.

3.1. Undo/Redo feature

3.1.1. Proposed Implementation

The undo/redo mechanism is facilitated by VersionedAddressBook. It extends AddressBook with an undo/redo history, stored internally as an addressBookStateList and currentStatePointer. Additionally, it implements the following operations:

  • VersionedAddressBook#commit() — Saves the current address book state in its history.

  • VersionedAddressBook#undo() — Restores the previous address book state from its history.

  • VersionedAddressBook#redo() — Restores a previously undone address book state from its history.

These operations are exposed in the Model interface as Model#commitAddressBook(), Model#undoAddressBook() and Model#redoAddressBook() respectively.

Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.

Step 1. The user launches the application for the first time. The VersionedAddressBook will be initialized with the initial address book state, and the currentStatePointer pointing to that single address book state.

UndoRedoStartingStateListDiagram

Step 2. The user executes delete 5 command to delete the 5th person in the address book. The delete command calls Model#commitAddressBook(), causing the modified state of the address book after the delete 5 command executes to be saved in the addressBookStateList, and the currentStatePointer is shifted to the newly inserted address book state.

UndoRedoNewCommand1StateListDiagram

Step 3. The user executes add n/David …​ to add a new person. The add command also calls Model#commitAddressBook(), causing another modified address book state to be saved into the addressBookStateList.

UndoRedoNewCommand2StateListDiagram
If a command fails its execution, it will not call Model#commitAddressBook(), so the address book state will not be saved into the addressBookStateList.

Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoAddressBook(), which will shift the currentStatePointer once to the left, pointing it to the previous address book state, and restores the address book to that state.

UndoRedoExecuteUndoStateListDiagram
If the currentStatePointer is at index 0, pointing to the initial address book state, then there are no previous address book states to restore. The undo command uses Model#canUndoAddressBook() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how the undo operation works:

UndoRedoSequenceDiagram

The redo command does the opposite — it calls Model#redoAddressBook(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores the address book to that state.

If the currentStatePointer is at index addressBookStateList.size() - 1, pointing to the latest address book state, then there are no undone address book states to restore. The redo command uses Model#canRedoAddressBook() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

Step 5. The user then decides to execute the command list. Commands that do not modify the address book, such as list, will usually not call Model#commitAddressBook(), Model#undoAddressBook() or Model#redoAddressBook(). Thus, the addressBookStateList remains unchanged.

UndoRedoNewCommand3StateListDiagram

Step 6. The user executes clear, which calls Model#commitAddressBook(). Since the currentStatePointer is not pointing at the end of the addressBookStateList, all address book states after the currentStatePointer will be purged. We designed it this way because it no longer makes sense to redo the add n/David …​ command. This is the behavior that most modern desktop applications follow.

UndoRedoNewCommand4StateListDiagram

The following activity diagram summarizes what happens when a user executes a new command:

UndoRedoActivityDiagram

3.1.2. Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (proposed choice): Saves the entire address book.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

    • Pros: Will use less memory (e.g. for delete, just save the person being deleted).

    • Cons: We must ensure that the implementation of each individual command are correct.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (proposed choice): Use a list to store the history of address book states.

    • Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.

    • Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both HistoryManager and VersionedAddressBook.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.

    • Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to do two different things.

3.2. Completing/Uncompleting a task feature

3.2.1. Current Implementation

Marking of a task as completed or uncompleted uses both Logic and Model components. Both TDL_complete and TDL_uncomplete commands are similar in most areas as they are implemented based on the edit task command. This feature also reuses the methods in the Model component used by the edit task command.

  • The parameter of the commands is the index of the to-do list.

The following sequence diagram shows how the TDL_complete operation works:

CompleteUncompleteTaskSequenceDiagram

Step 1. Upon user’s input, AddressBookParser determines if the command entered by the user is valid and then calls the appropriate CommandParser class. The arguments are also passed to the CommandParser class.

Step 2. CompleteTaskCommandParser or UncompleteTaskCommandParser will use the arguments given to retrieve and check if the index is valid. CompleteTaskCommand or UncompleteTaskCommand will then be called respectively by the parser class.

Step 3. The Command class will check for the validity of the index based on the currently shown to-do list and also the completion status of the specific task to be modified.

Completion status of the task needs to be checked as we want to prevent cases where the command does not change the completion status, ie. performing TDL_complete on a task already marked as completed.

Step 4. Similar to the edit task command, the task to be modified is updated using Model#updateTask() with a new task. The new task object is a copy of the task to be modified with the completion status changed.

3.2.2. Design Considerations

Aspect: Methods to support the completed/uncompleted commands
  • Alternative 1 (current choice): Reuses the same methods available in Model

    • Pros: Easy to implement with little to no modifications to the Model component.

    • Cons: May cause confusion since the same methods in the Model component are used by different commands with similar implementations.

  • Alternative 2: Create additional methods in Model

    • Pros: Should create less confusion as these methods are only used by a unique command.

    • Cons: We must ensure that the implementation of each individual method is correct.

3.3. Viewing filtered tasks feature

3.3.1. Current Implementation

Viewing a filtered task list uses both Logic and Model components. This feature reuses the existing Model#updateFilteredTaskList() method to update the filter to be used. We create two new predicates to either retrieve all completed tasks or all uncompleted tasks.

  • Each predicate evaluates to true based on the completion status of the tasks.

  • The parameter of this command is either 'all', 'completed' or 'uncompleted'.

The following sequence diagram shows how the TDL_view uncompleted operation works:

ViewTaskSequenceDiagram

Step 1. Upon user’s input, AddressBookParser determines if the command entered by the user is valid and then calls the ViewTaskCommandParser class. The arguments are also passed to this class.

Step 2. Since the parameter for this command is a string, the argument is trimmed and checked in the ViewTaskCommandParser class. The string is then passed to the ViewTaskCommand class to be executed.

Step 3. Depending on the filter, ViewTaskCommand class will use the Model#updateFilteredTaskList() method with the appropriate predicate and update the list of task to be shown.

3.3.2. Design Considerations

Aspect: Methods to support the feature
  • Alternative 1 (current choice): Reuses the same method available in Model with new predicates

    • Pros: Easy to implement with little modifications to the Model component.

    • Cons: Need to iterate through the to-do list to check for all tasks' completion status which might be slow given a large number of tasks.

  • Alternative 2: Saves and stores all variation of the filtered task list

    • Pros: Each filtered task list is readily available and easily obtainable.

    • Cons: Whenever there is a change to the task list, we need to ensure that all lists are updated accordingly.

3.4. Sort To-do list

3.4.1. Current Implementation

Sorting tasks in the to-do list uses both Logic and Model components. Generally, the implementation of TDL_sort date, TDL_sort priority and TDL_sort module are quite similar, and they use different comparators which are stored in SortComparator.

Firstly, after getting the input from user, SortCommandParser split command to get the parameter and choose the corresponding sorting method. Then, we use Collection.sort() in UniqueTaskList to sort ObservableList<Task> versionedTodoList

TDL_sort reverse use the method Collection.reverse() to reverse the sequence of tasks in to-do list.

To avoid the sequential order of upper case and lower case, we use TaskName a → a.toString().toLowerCase() transfer all upper case into lower case.

The following sequence diagram shows how the TDL_complete operation works:

SortTaskSequenceDiagram

3.4.2. Design Considerations

Aspect: Methods to support the sort commands
  • Alternative 1 (current choice): write methods for each sort parameter separately

    • Pros: easily to implement and have already gathered all comparators in SortComparator

    • Cons: hard to read and debug

  • Alternative 2: In Model part, write only one methods and use if sentence to execute corresponding one.

    • Pros: Easy to read and debug

3.5. Deadline Notification

3.5.1. Current Implementation

Deadline Notification in the to-do list uses both Model and UI components.

  • In Model part: We convert all deadline of task from TaskDate into Date type which can easily be processed with Java library. Besides that, we set all deadline to 0am and assume all tasks listed in the to-do list are in the same year as the date in system. We new a Date variable which initialized with the system date and compare it with the deadline of tasks.

  • In UI part: We use setStyle method of Label class to change the font color of id, task name, module code and deadline for distinguishing uncompleted tasks with different deadline.

  • In commons part: We store all Date type related methods in the TimeUtil class.

The following sequence diagram shows how the DeadlineNotification operation works:

DeadlineNotification

3.5.3. Aspect: Methods to support the deadline notification feature

  • Alternative 1 (current choice): Add related methods to Task class and Model class directly

    • Pros: Easy to implement

    • Cons: Hard to read and debug

  • Alternative 2: build a new class for Deadline notification

    • Pros: Easy to debug and increase new features like notify deadline with CLI output

    • Cons: Hard to implement

3.6. Calendar

3.6.1. Current Implementation

Calendar uses both Model and UI components.

  • In Model part: The CalendarInfo class initializes a calendar for the current month and generates the index of the first day of the whole week.

  • In UI part: We create a gridpane as the template of the calendar and use setCalendar method of CalendarInfo class to set and fill components of the calendar user interface.

3.6.2. Aspect: Methods to support the calendar feature

  • Alternative 1 (current choice): Use the Calendar class in Java library to implement a calendar panel.

    • Pros: It is easy to create, no external library or API is needed and pulling data from to-do list and expenditure tracker will be feasible as well.

    • Cons: The appearance of calendar may not be that good.

  • Alternative 2: Use calendar API (Google Calendar)

    • Pros: The appearance will be better and the calendar will provide more dynamic features.

    • Cons: It needs more effort to integrate with our application and pull task and expenditure data from storage.

Here is an image of Google Calendar with other dynamic features provided. For example, user could click on a date and add an event, which is not supported by Java Calendar class by default.

GoogleCalendarImage

More dynamic features with mouse clicking for the calendar in Something Daily will be implemented in Version 2.0.

3.7. Viewing filtered expenditures feature

3.7.1. Current Implementation

Viewing expenditures in the Expenditure Tracker uses both Logic and Model components.

  • In Logic part: We use getPredicateShowExpendituresOnDate method of ViewExpenditureCommand class to get the predicate for a particular date, afterwards it is passed to updateFilteredExpenditureList method which will update the expenditure list shown to user. We use predicateShowExpendituresOfCategory method to get the predicate for a specific category, afterwards it is passed to updateFilteredExpenditureList method which will update the expenditure list shown to user.

  • In Model part: We use setPredicate method of FilteredList in ModelManager class to change the content of current expenditure list.

3.7.2. Aspect: Methods to support the viewing filtered expenditures feature

  • Alternative 1 (current choice): We iterate through the entire expenditure list and select the expenditures based on filter.

    • Pros: It is easy to implement, there is no need for sorting functions.

    • Cons: It needs to check all the expenditures in the list with time complexity O(n) which is relatively slow.

  • Alternative 2: We keep two expenditure lists sorted by date or category respectively.

    • Pros: It is faster to get the expenditures. We only need to find the first and last appearance of the date or category, all expenditures between start and end will be selected.

    • Cons: It is harder to implement and more storage are needed to maintain the two sorted lists.

3.8. Get advice

3.8.1. Current Implementation

Get advice uses both Logic and Model components.

  • In Logic part: The CommandResult method of ExpenditureGetAdviceCommand class calls getExpenditureRecords method of ModelManager class and stores the returned map. Afterwards, we use a string builder to create an advice to be shown to the user.

  • In Model part: We use getExpenditureRecords method of ExpenditureList class to create a map, where the key contains category and value contains total money spent on this category.

The following sequence diagram shows how the ET_advice operation works:

ExpenditureGetAdviceSequenceDiagram

3.8.2. Aspect: Methods to show the advice message

  • Alternative 1 (current choice): We generate the advice message using string builder and afterwards the message will be shown to user in a pop-up window.

    • Pros: It is user friendly. The content of advice will be shown clearly, which is easy for user to see.

    • Cons: It needs effort to implement a PopUpString class (in our cases, a self-implemented pop-up window will be easy to implement since only a string needs to be shown) and corresponding methods for UI activating in the ExpenditureGetAdviceCommand class.

  • Alternative 2: We show the advice message in the command result box.

    • Pros: It is easy to be implemented.

    • Cons: It is not user friendly and harder for user to view in the command result box which is relatively small.

3.9. Pop-up window

3.9.1. Current Implementation

A PopUpString class was implemented to trigger the pop-up process.

  • In PopUpString class: The popup method creates a new stage with a scene containing one label to hold the advice string. Afterwards, by using stage.show() method, a new window will appear.

3.9.2. Aspect: Styles of the pop-up window to be shown

  • Alternative 1 (current choice): A new normal window is shown

    • Pros: The style of window is normal which provides user with necessary information.

    • Cons: It needs effort to implement a PopUpString class.

  • Alternative 2: A dialog window is shown

    • Pros: It is easy to be implemented using JOptionPane class in Java library.

    • Cons: The style of window is dialog which might be a bit awkward and might mislead user to consider the content of this window as error message.

3.10. Check Expenditure

3.10.1. Current Implementation

Check the total money spent in a specific period uses both Logic and Model components. It also generate a chart to show each expenditure in this period on each date.

The following sequence diagram shows how the ET_advice operation works:

CheckSequenceDiagram

3.10.2. Design Consideration

Aspect: Methods to support the check commands
  • Alternative 1 (current choice): Use list to get each money in expenditures.

    • Pros: Easy to implement using the exist list for expenditures.

    • Cons: Can not get the expenditures which are not shown in the list.

  • Alternative 2: Create additional structure for expenditures.

    • Pros: May use less memory.

    • Cons: Another data structure may cause some errors.

Aspect: Methods to generate the graph
  • Alternative 1 (current choice): Use a pie chart.

    • Pros: Can show users the percentage of each expenditure directly.

    • Cons: Do not show the change of their expense during this period.

  • Alternative 2: Use a line chart.

    • Pros: Can show users the trend of their expenditures according to the date.

    • Cons: Can not let users know how much each expenditure occupies total expenditures.

3.11. Data Encryption

3.11.1. Proposed Implementation

{Implementation of the data encryption feature will be introduced and explained in the near future.}

3.12. 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.13, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.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.13. Configuration

Certain properties of the application can be controlled (e.g App name, 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

See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits. Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.

4.2. Publishing Documentation

See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.

4.3. 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.

Here are the steps to convert the project documentation files to PDF format.

  1. Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the docs/ directory to HTML format.

  2. Go to your generated HTML files in the build/docs folder, right click on them and select Open withGoogle Chrome.

  3. Within Chrome, click on the Print option in Chrome’s menu.

  4. Set the destination to Save as PDF, then click Save to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.

chrome save as pdf
Figure 10. Saving documentation as PDF files in Chrome

4.4. 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.
Table 1. List of site-wide attributes
Attribute name Description Default value

site-name

The name of the website. If set, the name will be displayed near the top of the page.

not set

site-githuburl

URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar.

not set

site-seedu

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.5. 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.
Table 2. List of per-file attributes, excluding Asciidoctor’s built-in attributes
Attribute name Description Default value

site-section

Site section that the document belongs to. This will cause the associated item in the navigation bar to be highlighted. One of: UserGuide, DeveloperGuide, LearningOutcomes*, AboutUs, ContactUs

* Official SE-EDU projects only

not set

no-site-header

Set this attribute to remove the site navigation bar.

not set

4.6. 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 docs/templates requires some knowledge and experience with Ruby and Asciidoctor’s API. You should only modify them if you need greater control over the site’s layout than what stylesheets can provide. The SE-EDU team does not provide support for modified template files.

5. Testing

5.1. Running Tests

There are three ways to run tests.

The most reliable way to run tests is the 3rd one. The first two methods might fail some GUI tests due to platform/resolution-specific idiosyncrasies.

Method 1: Using IntelliJ JUnit test runner

  • To run all tests, right-click on the src/test/java folder and choose Run 'All Tests'

  • To run a subset of tests, you can right-click on a test package, test class, or a test and choose Run 'ABC'

Method 2: Using Gradle

  • Open a console and run the command gradlew clean allTests (Mac/Linux: ./gradlew clean allTests)

See UsingGradle.adoc for more info on how to run tests using Gradle.

Method 3: Using Gradle (headless)

Thanks to the TestFX library we use, our GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.

To run tests in headless mode, open a console and run the command gradlew clean headless allTests (Mac/Linux: ./gradlew clean headless allTests)

5.2. Types of tests

We have two types of tests:

  1. GUI Tests - These are tests involving the GUI. They include,

    1. System Tests that test the entire App by simulating user actions on the GUI. These are in the systemtests package.

    2. Unit tests that test the individual components. These are in seedu.address.ui package.

  2. Non-GUI Tests - These are tests not involving the GUI. They include,

    1. Unit tests targeting the lowest level methods/classes.
      e.g. seedu.address.commons.StringUtilTest

    2. Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
      e.g. seedu.address.storage.StorageManagerTest

    3. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
      e.g. seedu.address.logic.LogicManagerTest

5.3. Troubleshooting Testing

Problem: HelpWindowTest fails with a NullPointerException.

  • Reason: One of its dependencies, HelpWindow.html in src/main/resources/docs is missing.

  • Solution: Execute Gradle task processResources.

6. Dev Ops

6.1. Build Automation

See UsingGradle.adoc to learn how to use Gradle for build automation.

6.2. Continuous Integration

We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.

6.3. Coverage Reporting

We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.

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. See UsingNetlify.adoc for more details.

6.5. Making a Release

Here are the steps to create a new release.

  1. Update the version number in MainApp.java.

  2. Generate a JAR file using Gradle.

  3. Tag the repo with the version number. e.g. v0.1

  4. Create a new release using GitHub and upload the JAR file you created.

6.6. Managing Dependencies

A project often depends on third-party libraries. For example, Address Book depends on the Jackson library for XML parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
a. Include those libraries in the repo (this bloats the repo size)
b. Require developers to download those libraries manually (this creates extra work for developers)

Appendix A: Suggested Programming Tasks to Get Started

Suggested path for new programmers:

  1. First, add small local-impact (i.e. the impact of the change does not go beyond the component) enhancements to one component at a time. Some suggestions are given in Section A.1, “Improving each component”.

  2. Next, add a feature that touches multiple components to learn how to implement an end-to-end feature across all components. Section A.2, “Creating a new command: remark explains how to go about adding such a feature.

A.1. Improving each component

Each individual exercise in this section is component-based (i.e. you would not need to modify the other components to get it to work).

Logic component

Scenario: You are in charge of logic. During dog-fooding, your team realize that it is troublesome for the user to type the whole command in order to execute a command. Your team devise some strategies to help cut down the amount of typing necessary, and one of the suggestions was to implement aliases for the command words. Your job is to implement such aliases.

Do take a look at Section 2.3, “Logic component” before attempting to modify the Logic component.
  1. Add a shorthand equivalent alias for each of the individual commands. For example, besides typing clear, the user can also type c to remove all persons in the list.

    • Hints

    • Solution

      • Modify the switch statement in AddressBookParser#parseCommand(String) such that both the proper command word and alias can be used to execute the same intended command.

      • Add new tests for each of the aliases that you have added.

      • Update the user guide to document the new aliases.

      • See this PR for the full solution.

Model component

Scenario: You are in charge of model. One day, the logic-in-charge approaches you for help. He wants to implement a command such that the user is able to remove a particular tag from everyone in the address book, but the model API does not support such a functionality at the moment. Your job is to implement an API method, so that your teammate can use your API to implement his command.

Do take a look at Section 2.4, “Model component” before attempting to modify the Model component.
  1. Add a removeTag(Tag) method. The specified tag will be removed from everyone in the address book.

    • Hints

      • The Model and the AddressBook API need to be updated.

      • Think about how you can use SLAP to design the method. Where should we place the main logic of deleting tags?

      • Find out which of the existing API methods in AddressBook and Person classes can be used to implement the tag removal logic. AddressBook allows you to update a person, and Person allows you to update the tags.

    • Solution

      • Implement a removeTag(Tag) method in AddressBook. Loop through each person, and remove the tag from each person.

      • Add a new API method deleteTag(Tag) in ModelManager. Your ModelManager should call AddressBook#removeTag(Tag).

      • Add new tests for each of the new public methods that you have added.

      • See this PR for the full solution.

Ui component

Scenario: You are in charge of ui. During a beta testing session, your team is observing how the users use your address book application. You realize that one of the users occasionally tries to delete non-existent tags from a contact, because the tags all look the same visually, and the user got confused. Another user made a typing mistake in his command, but did not realize he had done so because the error message wasn’t prominent enough. A third user keeps scrolling down the list, because he keeps forgetting the index of the last person in the list. Your job is to implement improvements to the UI to solve all these problems.

Do take a look at Section 2.2, “UI component” before attempting to modify the UI component.
  1. Use different colors for different tags inside person cards. For example, friends tags can be all in brown, and colleagues tags can be all in yellow.

    Before

    getting started ui tag before

    After

    getting started ui tag after
    • Hints

      • The tag labels are created inside the PersonCard constructor (new Label(tag.tagName)). JavaFX’s Label class allows you to modify the style of each Label, such as changing its color.

      • Use the .css attribute -fx-background-color to add a color.

      • You may wish to modify DarkTheme.css to include some pre-defined colors using css, especially if you have experience with web-based css.

    • Solution

      • You can modify the existing test methods for PersonCard 's to include testing the tag’s color as well.

      • See this PR for the full solution.

        • The PR uses the hash code of the tag names to generate a color. This is deliberately designed to ensure consistent colors each time the application runs. You may wish to expand on this design to include additional features, such as allowing users to set their own tag colors, and directly saving the colors to storage, so that tags retain their colors even if the hash code algorithm changes.

  2. Modify NewResultAvailableEvent such that ResultDisplay can show a different style on error (currently it shows the same regardless of errors).

    Before

    getting started ui result before

    After

    getting started ui result after
  3. Modify the StatusBarFooter to show the total number of people in the address book.

    Before

    getting started ui status before

    After

    getting started ui status after
    • Hints

      • StatusBarFooter.fxml will need a new StatusBar. Be sure to set the GridPane.columnIndex properly for each StatusBar to avoid misalignment!

      • StatusBarFooter needs to initialize the status bar on application start, and to update it accordingly whenever the address book is updated.

    • Solution

Storage component

Scenario: You are in charge of storage. For your next project milestone, your team plans to implement a new feature of saving the address book to the cloud. However, the current implementation of the application constantly saves the address book after the execution of each command, which is not ideal if the user is working on limited internet connection. Your team decided that the application should instead save the changes to a temporary local backup file first, and only upload to the cloud after the user closes the application. Your job is to implement a backup API for the address book storage.

Do take a look at Section 2.5, “Storage component” before attempting to modify the Storage component.
  1. Add a new method backupAddressBook(ReadOnlyAddressBook), so that the address book can be saved in a fixed temporary location.

A.2. Creating a new command: remark

By creating this command, you will get a chance to learn how to implement a feature end-to-end, touching all major components of the app.

Scenario: You are a software maintainer for addressbook, as the former developer team has moved on to new projects. The current users of your application have a list of new feature requests that they hope the software will eventually have. The most popular request is to allow adding additional comments/notes about a particular contact, by providing a flexible remark field for each contact, rather than relying on tags alone. After designing the specification for the remark command, you are convinced that this feature is worth implementing. Your job is to implement the remark command.

A.2.1. Description

Edits the remark for a person specified in the INDEX.
Format: remark INDEX r/[REMARK]

Examples:

  • remark 1 r/Likes to drink coffee.
    Edits the remark for the first person to Likes to drink coffee.

  • remark 1 r/
    Removes the remark for the first person.

A.2.2. Step-by-step Instructions

[Step 1] Logic: Teach the app to accept 'remark' which does nothing

Let’s start by teaching the application how to parse a remark command. We will add the logic of remark later.

Main:

  1. Add a RemarkCommand that extends Command. Upon execution, it should just throw an Exception.

  2. Modify AddressBookParser to accept a RemarkCommand.

Tests:

  1. Add RemarkCommandTest that tests that execute() throws an Exception.

  2. Add new test method to AddressBookParserTest, which tests that typing "remark" returns an instance of RemarkCommand.

[Step 2] Logic: Teach the app to accept 'remark' arguments

Let’s teach the application to parse arguments that our remark command will accept. E.g. 1 r/Likes to drink coffee.

Main:

  1. Modify RemarkCommand to take in an Index and String and print those two parameters as the error message.

  2. Add RemarkCommandParser that knows how to parse two arguments, one index and one with prefix 'r/'.

  3. Modify AddressBookParser to use the newly implemented RemarkCommandParser.

Tests:

  1. Modify RemarkCommandTest to test the RemarkCommand#equals() method.

  2. Add RemarkCommandParserTest that tests different boundary values for RemarkCommandParser.

  3. Modify AddressBookParserTest to test that the correct command is generated according to the user input.

[Step 3] Ui: Add a placeholder for remark in PersonCard

Let’s add a placeholder on all our PersonCard s to display a remark for each person later.

Main:

  1. Add a Label with any random text inside PersonListCard.fxml.

  2. Add FXML annotation in PersonCard to tie the variable to the actual label.

Tests:

  1. Modify PersonCardHandle so that future tests can read the contents of the remark label.

[Step 4] Model: Add Remark class

We have to properly encapsulate the remark in our Person class. Instead of just using a String, let’s follow the conventional class structure that the codebase already uses by adding a Remark class.

Main:

  1. Add Remark to model component (you can copy from Address, remove the regex and change the names accordingly).

  2. Modify RemarkCommand to now take in a Remark instead of a String.

Tests:

  1. Add test for Remark, to test the Remark#equals() method.

[Step 5] Model: Modify Person to support a Remark field

Now we have the Remark class, we need to actually use it inside Person.

Main:

  1. Add getRemark() in Person.

  2. You may assume that the user will not be able to use the add and edit commands to modify the remarks field (i.e. the person will be created without a remark).

  3. Modify SampleDataUtil to add remarks for the sample data (delete your addressBook.xml so that the application will load the sample data when you launch it.)

[Step 6] Storage: Add Remark field to XmlAdaptedPerson class

We now have Remark s for Person s, but they will be gone when we exit the application. Let’s modify XmlAdaptedPerson to include a Remark field so that it will be saved.

Main:

  1. Add a new Xml field for Remark.

Tests:

  1. Fix invalidAndValidPersonAddressBook.xml, typicalPersonsAddressBook.xml, validAddressBook.xml etc., such that the XML tests will not fail due to a missing <remark> element.

[Step 6b] Test: Add withRemark() for PersonBuilder

Since Person can now have a Remark, we should add a helper method to PersonBuilder, so that users are able to create remarks when building a Person.

Tests:

  1. Add a new method withRemark() for PersonBuilder. This method will create a new Remark for the person that it is currently building.

  2. Try and use the method on any sample Person in TypicalPersons.

[Step 7] Ui: Connect Remark field to PersonCard

Our remark label in PersonCard is still a placeholder. Let’s bring it to life by binding it with the actual remark field.

Main:

  1. Modify PersonCard's constructor to bind the Remark field to the Person 's remark.

Tests:

  1. Modify GuiTestAssert#assertCardDisplaysPerson(…​) so that it will compare the now-functioning remark label.

[Step 8] Logic: Implement RemarkCommand#execute() logic

We now have everything set up…​ but we still can’t modify the remarks. Let’s finish it up by adding in actual logic for our remark command.

Main:

  1. Replace the logic in RemarkCommand#execute() (that currently just throws an Exception), with the actual logic to modify the remarks of a person.

Tests:

  1. Update RemarkCommandTest to test that the execute() logic works.

A.2.3. Full Solution

See this PR for the step-by-step solution.

Appendix B: Product Scope

Target user profile:

  • NUS SoC students

  • Is busy and has a need to better manage his/her student life

  • Has a need to manage a significant number of academic tasks

  • Has a need to keep track on expenditures

  • Prefer desktop applications over mobile platforms

  • Prefers typing over mouse input

  • Is reasonably comfortable using CLI applications

Value proposition: To assist students in managing all of their academic work and spendings which will improve their student life

Appendix C: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use the application

* * *

student

add a new task to the to-do list

* * *

student

edit a task on the to-do list

keep my tasks updated and correct

* * *

student

delete a task on the to-do list

remove any entries that I no longer need

* * *

student

archive completed tasks

have a history of all tasks completed earlier throughout the school semester

* * *

student with multiple modules

tag each task with a module code

identify all tasks specific to a particular module

* * *

student with multiple tasks

tag each task with a deadline

identify all tasks that are time sensitive

* * *

student with multiple tasks

tag each task with different levels of importance/priority

identify all tasks that requires more attention

* * *

student with multiple tasks

filter the todo list by completion status

obtain a list of tasks based on their completion status

* * *

student

add a new expenditure to the expenditure tracker

* * *

student

edit an expenditure in the expenditure tracker

keep my expenditures updated and correct

* * *

student

delete an expenditure in the expenditure tracker

remove any entries that I typed wrongly

* * *

student who is not capable of managing expenditure

see and check where did I spend my money and how much did I spend for each expenditure with the corresponding date

better understand my spending habits

* * *

student who wants to know how much money did I spend and how much income did I get for a certain period

see the amount of spendings and income respectively by keying in the starting date and end date of a particular period

* *

student with multiple tasks

sort the todo list by module

view all tasks specific to a particular module

* *

student with multiple tasks

sort the todo list by deadline

view which task is due the earliest

* *

student with multiple tasks

sort the todo list by importance/priority

view which tasks are more important than the other

* *

student with tasks that may last for a long time

easily record and view my progress with progress bar

* *

student

delete all archived completed tasks after the semester is done

get ready for the next semester

* *

student with difficulty in remembering all deadlines

get notified at a certain time before deadline based on my choice

submit my work on time

* *

student who wants to know how to save my money

obtain advices from the Expenditure Tracker by checking the categories which I mainly spent my money on

control my spendings in a particular category

*

student with multiple projects

have a separate project window

view all tasks specific only to projects

*

student with multiple tasks to complete in a day

let the system automatically generate the order of tasks based on priority

start working on the tasks

*

student who does not record their money spending regularly

notified by the Expenditure Tracker to note down the amount of money spent on food, snacks or other categories respectively everyday

Appendix D: Use Cases

(For all use cases below, the Actor is the user, unless specified otherwise)

Use case 1: Add task

System: To-do list

MSS

  1. User enters TDL_add command and keys in the task

  2. To-do list shows the task entered in the list

Use case 2: Edit or Update task

System: To-do list

MSS

  1. User enters TDL_edit command followed by index number

  2. To-do list confirms task is present in the list

  3. User enter relevant contents

  4. To-do list shows the updated task in the list

Extensions

2a. The list is empty.
2b. The given index is invalid.
  2b1. To-do list shows an error message

Use case 3: Delete task

System: To-do list

MSS

  1. User enters TDL_delete command followed by index number

  2. To-do list confirms task is present and deletes the task

Extensions

2a. The list is empty.
2b. The given index is invalid
  2b1. To-do list shows an error message

Use case 4: Check tasks for a module

System: To-do list

MSS

  1. User enters TDL_sort module command

  2. To-do list shows a sorted list of tasks grouped by modules

Use case 5: Check for urgent tasks

System: To-do list

MSS

  1. User enters TDL_sort date command

  2. To-do list shows the all uncompleted modules sorted by deadlines, the task with latest deadline is the first task

Use case 6: Checking tasks with high importance

System: To-do list

MSS

  1. User enters TDL_sort priority command

  2. To-do list shows a sorted list of tasks grouped by priority level in descending order

Use case 7: View all completed tasks

System: To-do list

MSS

  1. User enters TDL_view completed command

  2. To-do list shows a list of tasks that has been marked as completed

Use case 8: View all uncompleted tasks

System: To-do list

MSS

  1. User enters TDL_view uncompleted command

  2. To-do list shows a list of tasks that have not been marked as completed

Use case 9: View all tasks

System: To-do list

MSS

  1. User enters TDL_view all command

  2. To-do list shows a list of tasks regardless of its completion status

Use case 10: Marking a task as completed

System: To-do list

MSS

  1. User enters TDL_complete command followed by index number

  2. To-do list marks task as completed

Extensions

2a. The list is empty.
2b. The given index is invalid
  2b1. To-do list shows an error message

Use case 11: Marking a task as uncompleted

System: To-do list

MSS

  1. User enters TDL_uncomplete command followed by index number

  2. To-do list marks task as uncompleted

Extensions

2a. The list is empty.
2b. The given index is invalid
  2b1. To-do list shows an error message

Use case 12: Receiving reminders for a task

System: To-do list

MSS

  1. To-do list notifies user of task close to deadline

  2. User receives and acknowledges the reminder

Use case 13: Get deadline notification

System: To-do list

MSS

1.The color of one task turns red which means this task is uncompleted and the deadline has passed already 2.The color of one task turns yellow which means this task is uncompleted and the deadline will come within 7 days

Use case 14: Sort Uncompleted tasks by deadline

System: To-do list

MSS

  1. User enter TDL_view uncompleted to list uncompleted tasks

  2. User enter TDL_sort date to sort all uncompleted tasks by deadline date

Use case 15: Add expenditure / income

System: Expenditure Tracker & Calendar

MSS

  1. User enter add command followed by the amount of money

  2. Expenditure tracker receives information and shows the dates to be added

  3. User choose the date

  4. Expenditure tracker notifies user to pick category

  5. User choose the category to be added

  6. Expenditure Tracker record and display the income / outcome on calendar

Use case 16: Check expenditure / income status

System: Expenditure Tracker & Calendar

MSS

  1. User enter check status command

  2. Expenditure tracker asks user to choose whether to check in the visual calendar or key in the starting date and closing date of a particular period

  3. User keys in visual command or manual command

  4. Calendar shows the expenditure / income for each day visually or Expenditure Tracker shows the expenditure / income status by displaying the amount of money.

Use case 17: Delete expenditure / income

System: Expenditure Tracker & Calendar

MSS

  1. User enters ET_delete command followed by index number

  2. Expenditure tracker confirms expenditure is present and deletes the expenditure

Extensions

2a. The list is empty.
2b. The given index is invalid
  2b1. Expenditure list shows an error message

Use case 18: Edit or Update expenditure

System: Expenditure Tracker & Calendar

MSS

  1. User enters ET_edit command followed by index number

  2. Expenditure tracker confirms expenditure is present in the list

  3. User enter relevant contents

  4. Expenditure tracker shows the updated expenditure in the list

Extensions

2a. The list is empty.
2b. The given index is invalid.
  2b1. To-do list shows an error message

Appendix E: Non Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 9 or higher installed.

  2. Should be able to hold up to 500 tasks without a noticeable sluggishness in performance for typical usage.

  3. Command-line commands should be simple and easy to remember.

Appendix F: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Appendix G: Product Survey

Things
A to-do list mobile application

Author: Ran Tian

Pros:

  1. Clean UI that is user friendly

  2. Able to add deadlines for every tasks at hand

  3. Able to create custom tags for tagging tasks

Cons:

  1. Not specialized for students

  2. Unable to sort tasks by tags

  3. Lack of a reminder feature

Appendix H: Instructions for Manual Testing

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.

H.1. Launch and Shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with a set of sample tasks and expenses.

  2. Shutdown

    1. Enter the exit command or close the application directly

  3. Re-launch

    1. Double-click the jar file.
      Expected: Any previous changes to to-do list and/or expenditure tracker are automatically saved and will appear as per normal.

H.2. Adding a task

  1. Adding a task to the to-do list

    1. Prerequisites: No modifications are done to the sample tasks list.

    2. Test case: TDL_add t/Milestone 3 m/CS2113 d/02-11 p/2
      Expected: Task is not added. Error details are shown in the status message.

    3. Test case: TDL_add t/Tutorial 5 m/CS2101 d/12-09 p/1
      Expected: New task is added to the to-do list. Details of the added task is shown in the status message.

    4. Other incorrect add commands to try: TDL_add (with any missing parameters)

H.3. Editing a task

  1. Editing a task in the to-do list

    1. Prerequisites: Must have at least 1 task in the list shown

    2. Test case: TDL_edit 1
      Expected: First task shown in the list is edited with no changes to any parameters. Details of the task is shown in the status message.

    3. Test case: TDL_edit 1 m/CS1231
      Expected: First task shown in the list is edited with the new module code of CS1231. Details of the edited task is shown in the status message.

    4. Test case: TDL_edit 0 m/CS1231
      Expected: No task is edited. Error details are shown in the status message.

    5. Other incorrect edit commands to try: TDL_edit, TDL_edit x (where x is larger than the list size shown)

H.4. Deleting a task

  1. Deleting a task in the to-do list

    1. Prerequisites: Must have at least 1 task in the list shown

    2. Test case: TDL_delete 1
      Expected: First task shown in the list is deleted. Details of the deleted task is shown in the status message.

    3. Test case: TDL_delete 0
      Expected: No task is deleted. Error details shown in the status message.

    4. Other incorrect delete commands to try: TDL_delete, TDL_delete x (where x is larger than the list size shown)

H.5. Marking a task as completed

  1. Marking a task in the to-do list as completed

    1. Prerequisites: Task to be marked must have completion status of uncompleted. Must have at least 1 task in the list shown.

    2. Test case: TDL_complete 1
      Expected: Uncompleted task in index 1 shown in the list is marked as completed. Details of the task is shown in the status message.

    3. Test case: TDL_complete 0
      Expected: No task is marked as completed. Error details shown in the status message.

    4. Other incorrect commands to try: TDL_complete, TDL_complete x (where x is larger than the list size shown)

H.6. Marking a task as uncompleted

  1. Marking a task in the to-do list as uncompleted

    1. Prerequisites: Task to be marked must have completion status of completed. Must have at least 1 task in the list shown.

    2. Test case: TDL_uncomplete 1
      Expected: Completed task in index 1 shown in the list is marked as uncompleted. Details of the task is shown in the status message.

    3. Test case: TDL_uncomplete 0
      Expected: No task is marked as uncompleted. Error details shown in the status message.

    4. Other incorrect commands to try: TDL_uncomplete, TDL_uncomplete x (where x is larger than the list size shown)

H.7. Viewing filtered task list

  1. Viewing a filtered task list by completion status

    1. Prerequisites: Should have at least 1 task of each completion statuses

    2. Test case: TDL_view all
      Expected: All tasks are displayed in the to-do list regardless of completion status.

    3. Test case: TDL_view uncompleted
      Expected: All uncompleted tasks are displayed in the to-do list.

    4. Test case: TDL_view completed
      Expected: All completed tasks are displayed in the to-do list.

    5. Incorrect commands to try: TDL_view, TDL_view complete, TDL_view uncomplete, TDL_view xxx (where xxx is any string of words not mentioned above)
      Expected: No change in the to-do list. Error detail is shown in the status message.

H.8. Sorting task list

  1. Sorting the task list of the to-do list

    1. Prerequisites: Should have at least 3 tasks with different parameters

    2. Test case: TDL_sort default
      Expected: Tasks are now sorted alphabetically by its name.

    3. Test case: TDL_sort module
      Expected: Module code of the tasks are sorted alphabetically.

    4. Test case: TDL_sort date
      Expected: Tasks are now sorted by its date, where oldest date comes first.

    5. Test case: TDL_sort priority
      Expected: Tasks are now sorted by its priority level, where highest priority comes first.

    6. Test case: TDL_sort reverse
      Expected: Tasks list shown is now in reversed order.

    7. Incorrect commands to try: TDL_sort, TDL_sort xxx (where xxx is any string of words not mentioned above)
      Expected: No change in the to-do list. Error detail is shown in the status message.

H.9. Adding an expenditure

  1. Adding an expenditure to the expenditure tracker

    1. Prerequisites: No prerequisites are needed

    2. Test case: ET_add e/iPhone7 Plus d/25-12-2017 m/1000 c/Electronics
      Expected: New expenditure is added to the expenditure tracker. Details of the added expenditure is shown in the status message.

    3. Incorrect add commands to try: ET_add (with any missing parameters)
      Expected: Expenditure is not added. Error details are shown in the status message.

H.10. Editing an expenditure

  1. Editing an expenditure in the expenditure tracker

    1. Prerequisites: Must have at least 1 expenditure in the list shown

    2. Test case: ET_edit 1
      Expected: No expenditure is edited. Error details are shown in the status message.

    3. Test case: ET_edit 1 m/10.50
      Expected: First expenditure shown in the list is edited with the new spending of 10.50 SGD. Details of the edited expenditure is shown in the status message.

    4. Test case: ET_edit 0 m/10.50
      Expected: No expenditure is edited. Error details are shown in the status message.

    5. Other incorrect edit commands to try: ET_edit, ET_edit x (where x is larger than the list size shown)

H.11. Deleting an expenditure

  1. Deleting an expenditure in the expenditure tracker

    1. Prerequisites: Must have at least 1 expenditure in the list shown

    2. Test case: ET_delete 1
      Expected: First expenditure shown in the list is deleted. Details of the deleted expenditure is shown in the status message.

    3. Test case: ET_delete 0
      Expected: No expenditure is deleted. Error details are shown in the status message.

    4. Other incorrect delete commands to try: ET_delete, ET_delete x (where x is larger than the list size shown)

H.12. Viewing filtered expenditure list

  1. Viewing a filtered expenditure list by various parameters

    1. Prerequisites: Should have at least 1 task

    2. Test case: ET_view all
      Expected: All expenditures are displayed in the expenditure tracker.

    3. Test case: ET_view 01-01-2018
      Expected: All expenditures on 01-01-2018 are displayed in the expenditure tracker.

    4. Test case: ET_view Electronics
      Expected: All expenditures are displayed in the expenditure tracker.

    5. Incorrect commands to try: ET_view, ET_view xxx (where xxx is any string of words not mentioned in the User Guide)
      Expected: No change in the expenditure tracker. Error detail is shown in the status message.

H.13. Checking expenditures

  1. Checking of all expenditures in a particular time frame

    1. Prerequisites: No prerequisites are needed

    2. Test case: ET_check start/01-01-2018 end/01-12-2018
      Expected: A pop-up window with a pie-chart of all recorded expenditures in this time frame will be shown.

    3. Test case: ET_check start/01-01-2018 end/1-12-2018
      Expected: No pop-up window will appear. Error detail is shown in the status message.

    4. Other incorrect commands to try: ET_check

H.14. Obtaining expenditure advices

  1. Obtaining expenditure advices based on expenditure history

    1. Prerequisites: No prerequisites are needed

    2. Test case: ET_advice m/1000 numofdays/30
      Expected: A pop-up window with full instructions and details will be shown.

    3. Test case: ET_advice m/1000 numofdays/0
      Expected: No pop-up window will appear. Error detail is shown in the status message.

    4. Other incorrect commands to try: ET_advice

H.15. Viewing of daily summary

  1. Viewing a daily summary of all due tasks and expenditures on a particular day

    1. Prerequisites: No prerequisites are needed

    2. Test case: check d/01-01-2018
      Expected: A pop-up window with the summary for the day 01-01-2018 will be shown.

    3. Test case: check d/01-1-2018
      Expected: No pop-up window will appear. Error detail is shown in the status message.

    4. Other incorrect commands to try: check

H.16. Saving data

  1. Dealing with missing/corrupted data files

    1. {explain how to simulate a missing/corrupted file and the expected behavior}