By: Team CS2103T-W11-1      Since: Sept 2019      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

ArchitectureDiagram
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 .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide to learn how to create and edit 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 five components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • UiLogic: The UI action handler.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

Each of the five 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

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 deleteprob 1.

ArchitectureSequenceDiagram
Figure 3. Component interactions for deleteprob 1 command

The Sequence Diagram below shows how the components interact with each other for the scenario where the user switches tabs in the GUI.

ArchitectureSequenceDiagram1
Figure 4. Component interactions for Switching Tab UI Action

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 component consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, DetailsTabPane, DisplayTabPane, TaskManagementPane, StatusBarFooter etc. All these components, including the MainWindow, inherit from the abstract UiPart class.

UiDisplayTabClassDiagram
Figure 6. Structure of the DisplayTabPane Component

The DetailsTabPane consists of FindRuleListPanel, PlanListPanel, ProblemListPanel and TagListPanel, which are used for displaying entries of FindRule, Plan, Problem and Tag stored in AlgoBase respectively.

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.

  • Listens for changes to Model data so that the UI can be updated with the modified data.

2.3. Logic component

LogicClassDiagram
Figure 7. Structure of the Logic Component

API : Logic.java

  1. Logic uses the AlgoBaseParser 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 problem).

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

  5. In addition, the CommandResult object can also instruct the Ui 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("deleteprob 1") API call.

DeleteSequenceDiagram
Figure 8. Interactions Inside the Logic Component for the deleteprob 1 Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.4. UiLogic Component

UiLogicClassDiagram
Figure 9. Structure of the UiLogic Component

API : UiLogic.java

  1. Performing an action (e.g. switching tabs) triggers the creation of a UiActionDetails object.

  2. UiLogic uses the AlgoBaseUiActionParser class to parse the UiActionDetails object.

  3. This results in a UiAction object which is executed by the UiLogicManager.

  4. The command execution can affect the Model (e.g. deleting a problem).

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

  6. In addition, the UiActionResult object can also instruct the Ui to perform certain actions, such as displaying the results as feedback to the user.

EditSequenceDiagram
Figure 10. Interactions Inside the UiLogic Component for a UiActionDetails with a UiActionType of editPlanUiAction. This UiActionDetails also contains the ID of the problem to be deleted, in this case 11b.
The lifeline for EditProblemUiActionParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.5. Model component

ModelClassDiagram
Figure 11. Structure of the Model Component

API : Model.java

The Model,

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

  • stores the AlgoBase data.

  • exposes unmodifiable ObservableList<Problem>, ObservableList<Tag>, ObservableList<Plan>, ObservableList<Task>, ObservableList<ProblemSearchRule> 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.

We organize different data classes into packages (e.g. Problem), inside which we provide a collection class of that data object (e.g. UniqueProblemList) so that AlgoBase can manage these data objects without knowing the details of each data class.

ProblemPackageDiagram
Figure 12. Structure of the Problem Package

Note that we don’t require plans to be unique, thus unlike problems' collection class is named UniqueProblemList, plan’s collection is simply named PlanList.

PlanPackageDiagram
Figure 13. Structure of the Plan Package
TagPackageDiagram
Figure 14. Structure of the Tag Package
TaskPackageDiagram
Figure 15. Structure of the Task Package

Both problemsearchrule and plansearchrule are packaged under searchrule and they share similar internal structure - note that saving find rule feature only supports saving problem search rule, thus there’s no subclass for FindPlanDescriptor.

ProblemSearchRulePackageDiagram
Figure 16. Structure of the ProblemSearchRule Package
PlanSearchRulePackageDiagram
Figure 17. Structure of the PlanSearchRule Package

As we support preserving the GUI state, we included GuiState as a part of AlgoBase's model.

GuiPackageDiagram
Figure 18. Structure of the GUI Package

2.6. Storage component

StorageClassDiagram
Figure 19. Structure of the Storage Component
ProblemSearchRuleClassDiagram
Figure 20. Structure of the JsonAdaptedProblemSearchRule Component

API : Storage.java

The Storage component,

  • can store UserPrefs objects in JSON format.

  • can retrieve UserPrefs objects from JSON format.

  • can store the AlgoBase app data including GuiState, Plan, Problem, ProblemSearchRule, Tag, Task objects in relational manner in JSON format.

  • can retrieve GuiState, Plan, Problem, ProblemSearchRule, Tag, Task objects from data stored in JSON format.

2.7. Common classes

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

It contains utility files for configuration ConfigUtil, file handling FileUtil, JSON storage JsonUtil, string manipulation StringUtil and others including AppUtil and CollectionUtil.

3. Implementation

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

3.1. Task Management Feature

As an algorithmic problem management tool, one of the most important features will be managing tasks that have been done or are to be done.

This section will describe in details the current implementation and design considerations of the task management feature.

3.1.1. Current Implementation

The task management feature supports eight main operations:

  • AddTask - creates a new task for a problem and add it to a specified plan.

  • CopyTask - copies a task from one plan to another.

  • DeleteTask - deletes an existing task from a specified plan.

  • DoneTask - marks a task as done in a specified plan.

  • EditTask - edits the due date of a task in a specified plan.

  • MoveTask - moves a task from one plan to another.

  • SetPlan - sets a plan as the current plan in main display.

  • UndoneTask - marks a task as undone in a specified plan.

This feature is mainly supported by the Task class. Given below is the class diagram of the Task class.

HighLevelTaskClassDiagram
Figure 21. Class Diagram for Task

Given below is an example usage scenario and how the mechanism for adding tasks behaves at each step.

The following activity diagram summarizes what happens when a user executes the AddTaskCommand:

AddTaskCommandActivityDiagram
Figure 22. Activity Diagram for the Execution of AddTaskCommand

Step 1. The user launches the application.

Step 2. AlgoBase displays a list of existing problems and plans in the UI.

Step 3. The user executes addtask plan/1 prob/1 to add the problem with index 1 in the list to the plan with index 1. The AddTaskCommand calls Model#updateTasks to create a new plan from the original plan with this additional task, and replace the original plan with this updated plan in the PlanList stored in AlgoBase.

The sequence diagram below shows the high-level abstraction of how AlgoBase processes user request to execute addtask plan/1 prob/1:

HighLevelAddTaskSequenceDiagram
Figure 23. High Level Sequence Diagram for the Execution of addtask plan/1 prob/1

The following sequence diagram illustrates the interaction between the Logic and Model components while executing AddTaskCommand:

AddTaskSequenceDiagram
Figure 24. Sequence Diagram for the Execution of AddTaskCommand

3.1.2. Design Considerations

Aspect: Data structure to support the task commands.
  • Alternative 1 (current choice): Use a HashSet to store tasks in a plan.

    • Pros: Duplicate tasks can be checked easily.

    • Cons: Harder to identify tasks by index.

  • Alternative 2: Use an ArrayList to store tasks in a plan.

    • Pros: Tasks can be identified by index easily.

    • Cons: Harder to check for duplicate tasks.

Aspect: How to store problem details within tasks to support the task commands.
  • Alternative 1 (current choice): Store a problem object in each task.

    • Pros: Changes in problem details will be reflected in the relevant tasks as well.

    • Cons: Relational storage is required to keep track of this relationship.

  • Alternative 2: Copy all problem details and store as separate fields in each task.

    • Pros: No need to implement relational storage. There will be less coupling between problems and tasks as well.

    • Cons: Changes in problem details cannot be reflected in the relevant tasks easily.

Aspect: Relational storage to support the task commands.
  • Alternative 1 (current choice): Use an additional id field to identify problems and tasks.

    • Pros: The id field is kept immutable over time, thus ensuring integrity.

    • Cons: An additional field is needed for the models.

  • Alternative 2: Use object hash to identify problems and tasks.

    • Pros: No need to store another additional field in the models.

    • Cons: Object hash can change over time.

3.2. Tag feature

3.2.1. Implementation

The tag mechanism is facilitated by UniqueTagList. It creates a list of Tag, stored internally as an uniqueTagList. Additionally, it implements the following operations:

  • AddTag - creates a new tag in AlgoBase’s uniqueTagList in the algobase history.

  • DeleteTag - deletes a current tag which have already in the uniqueTagList.

  • EditTag - edits the current tag name which have already been in the uniqueTagList.

  • ListTag - shows the tags in the uniqueTagList in the algobase GUI for users.

TagClassDiagram
Figure 25. Class Diagram for Tag

These operations are exposed in the Model interface as Model#addTag(), Model#deleteTag(), Model#listTag() and Model#editTag() respectively.

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

Step 1. The user launches the application for the first time. The UniqueTagList will be initialized with the initial algobase state

Step 2. The user executes addtag t/easy to add a tag named [easy] with default color which have not applied in any problems. The addtag command calls Model#addtag(), causing the taglist added a tag after the ‘addtag t/easy’ command executes to be saved in the uniqueTagList.

The following sequence diagram shows how the addtag operation works:

AddTagSequenceDiagram
Figure 26. Sequence Diagram for AddTagCommand

Step 3. The user decides to execute the command listtag to show a tag list in the GUI of algobase. The listtag command calls Model#listtag(), causing the taglist shows the current components of uniqueTagList. Commands that do not modify the data, such as listtag, will not call Model#addTag(), Model#deleteTag() or Model#editTag(). Thus the uniqueTagList remains unchanged.

Step 4.The user executes edittag 1 t/hard c/BLUE to edit the current tag [easy] to [hard] in the uniqueTagList. The edittag 1 t/hard c/BLUE Command executes edittag, causing the taglist find the tag with index 1 in the tag list and change tag [easy] into [hard] and change tag color from default color to blue, and change all [easy] tag into [hard] in blue color in all problems.

Step 5. The user executes deletetag t/hard to delete the current tag [easy] in the uniqueTagList. The deletetag t/hard command executes deletetag, causing the taglist delete the [hard] tag in uniqueTagList and [hard] tag in all problems. (diagram)

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

TagCommandActivityDiagram
Figure 27. Activity Diagram for tag commands

3.2.2. Design considerations

Aspect: Data structure to support the tag commands.
  • Alternative 1 (current choice): Use a list in current AlgoBase to save the content of different tags which used in tagging different problems. While problems create new tags for problems, it will also add into tag-list in AlgoBase. While the tag in problems changes, the tag in tag-list will not change and add a new tag into the tag-list in AlgoBase. While modifying tag in tag-list will change the tag for all related problem.

    • Pros: Users can manage the tags conveniently.

    • Cons: May lead to many tags do not combine with problems.

  • Alternative 2: Simply keep tags as a part of problems. While execute the tag command will search for all tags in problems for every times it execute.

    • Pros: No need to save the tag separately in the storage, all tags are under problems.

    • Cons: Difficult to manage tags in different problems. Waste time for computer to execute.

3.3. Find Problem Feature

Since AlgoBase is a management tool for algorithmic questions, the search functionality is crucial to the user’s experience with AlgoBase. For instance, the planning feature heavily relies on findprob command to determine the exact set of problems the user wants to include in a training plan.

This section will describe in detail the current implementation and design considerations of the find problem feature (i.e. search feature) of AlgoBase.

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

FindCommandActivityDiagram
Figure 28. Activity Diagram for the Execution of findprob Command

3.3.1. Current Implementation

The find problem feature mainly involves three parts:

  1. validating and parsing user input

  2. creating a filtering predicate from user’s search constraints

  3. update the displayed problem list with the filtering predicate.

The find problem feature is facilitated by the following classes:

  • FindProblemDescriptor

    It stores predicates that are needed to describe a FindCommand

    Additionally, it implements the following operation(s):

    • FindProblemDescriptor#isAnyFieldProvided() - Determines if there is at least one search restriction included in this instance of FindProblemDescriptor.

    • FindProblemDescriptor#equals(…​) - Two instances of FindProblemDescriptor are equal if and only if all of their predicates are equal.

  • FindCommandParser It validates and parses user input to an instance of FindCommand.

If the user provides difficulty range as one of the search restrictions, FindCommandParser expects the format LOWER_BOUND <= difficulty <= UPPER_BOUND while LOWER_BOUND and UPPER_BOUND are valid strings for doubles (i.e. parsable by Double.parseDouble(…​)).
  • FindCommand

    It creates and stores the predicate from an instance of FindProblemDescriptor. predicate is used to perform the filtering of the displayed problem list when the command is executed.

    predicate returns true only when the provided problem fulfills all restrictions described by the provided instance of FindProblemDescriptor.

    Additionally, it implements the following operation(s):

    • FindCommand#execute(…​) - This method overrides Command#execute(…​). It filters problems in filteredProblemList in model with predicate.

    • FindCommand#equals(…​) - Two instances of FindCommand are equal if and only if their predicate are equal.

FindCommandClassDiagram
Figure 29. Class Diagram of the Find Feature
  • Predicates that implements interface Predicate<Problem>

    These are classes that describes whether an instance of Problem is considered a match under a certain field with provided keyword(s).

    • NameContainsKeywordsPredicate

      • It ignores case.

      • It returns true as long as one of the keywords appear in the name as a word. (“As a word” means the matching is done word by word. For instance, hello doesn’t match helloworld.)

    • AuthorMatchesKeywordPredicate

      • It is case sensitive and matches the entire author string (i.e. requires an exact match).

    • DescriptionContainsKeywordsPredicate

      • It ignores case.

      • It returns true only when all of the keywords appear in the description as a word.

    • SourceMatchesKeywordPredicate

      • It requires an exact match.

    • DifficultyIsInRangePredicate

      • It matches problems with LOWER_BOUND <= difficulty <= UPPER_BOUND

    • TagIncludesKeywordsPredicate

      • Each keyword will be considered as a tag, and two tags are considered equal only when their names are exactly the same (i.e. an exact match).

      • It returns true when the provided tags are a subset of the tags of the provided problem.

PredicateClassDiagram
Figure 30. Class Diagram for Predicates in the Find Feature

Given below is an example usage scenario and how the find problem mechanism behaves at each step.

Step 1. The user executes findprob t/recursion diff/2.0-4.0 to find a problem with a tag “recursion” and difficulty between 2.0 and 4.0.

Step 2. FindCommandParser processes the user input and returns a FindCommand instance with the information of user’s search restrictions.

If no valid search restriction is provided by the user, FindCommandParser will throw a parsing exception, which is handled and displayed to the user.

Step 3. LogicManager invokes execute() method of the returned FindCommand. FindCommand updates the problem list with user’s search constraints.

FindCommandSequenceDiagram
Figure 31. Sequence Diagram for the Execution of findprob Command

3.3.2. Design Considerations

Aspect: How to update the displayed problem list in the UI
  • Alternative 1 (current choice): Let UI display problems in a FilteredList<Problem> and update the displayed problem by calling setPredicate on the FilteredList.

    • Pros: Provides good protection over unexpected changes on the displayed problem list.

    • Cons: Need to write a complex logic to generate one predicate out of multiple search constraints.

  • Alternative 2: Let UI displays problems in an ObservableList<Problem> and update the list directly.

    • Pros: The implementation would be more straightforward as the logic can update the displayed list directly.

    • Cons: Leaves room for potential unexpected changes on the displayed problem list as the observable list is open to any kind of operation.

Aspect: How to deal with the case where no search restriction is provided (i.e. user types in findprob with no arguments given)
  • Alternative 1 (current choice): Treat it as an exception and notify the user to provide at least one constraint.

    • Pros: Makes the meaning of findprob command clear - you can’t search for problems without giving any conditions.

    • Cons: Has to check there is at least one predicate provided, making the implementation a bit more complicated.

  • Alternative 2: Treat it as no restriction (i.e. findprob is equivalent to list in this case)

    • Pros: Easier implementation (if all predicates are always-true predicates, using .and method to chain them together would naturally result in an always-true predicate).

    • Cons: Confusing definition of the search feature.

Aspect: How to make predicates optional (i.e. user doesn’t have to provide restrictions for all searchable fields)
  • Alternative 1 (current choice): Use FindProblemDescriptor in which the getter for the predicate returns Optional<Predicate>.

    • Pros: If the parser doesn’t receive keyword(s) for a specific field, it simply doesn’t call the descriptor’s setter for that field. It doesn’t need to deal with null, and null is dealt gracefully using Optional.ofNullable(…​)

    • Cons: Rather troublesome implementation of the descriptor.

  • Altermative 2: Store predicates in FindProblemCommand and check for not-provided predicates by comparing it with null.

    • Pros: More straightforward implementation.

    • Cons: If we are to add more predicates, it’s more likely that we forget to check null value of the new predicate.

3.4. Save Find Rules Feature

AlgoBase provides many ways to organizing your problems including tags and plans. However, both organizing features require persistent user involvement - if the user added a new problem belonging to a category, the user needs to manually assign a tag to the problem or add the problem to a plan. Since AlgoBase’s findprob command enables the user to filter problems with great flexibility, we allow them to save certain find rules so that they can re-apply these rules to quickly locate problems of their need.

This section will describe in detail the current implementation and design considerations of the save find rules (or problem search rules) feature of AlgoBase.

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

AddFindRuleActivityDiagram
Figure 32. Activity Diagram for the Execution of addfindrule Command

3.4.1. Current Implementation

The save find rules feature is facilitated by the following classes:

  • ProblemSearchRule
    It stores both the Name of the find rule and all predicates included in this find rule. A ProblemSearchRule doesn’t have to include all possible predicates as the user may not provide all of them. Missing predicates will be stored as null in this class.

  • UniqueFindRuleList
    It stores the find rules and makes sure that every find rule in this list has a unique name.

    • UniqueFindRuleList stores a ObservableList<ProblemSearchRule> for UI purposes.

Except for ProblemSearchRule, we refer to these rules as FindRule in all other places. This is to prevent possible naming conflicts if AlgoBase is to support saving find rules on other items (e.g. Plans, etc.). FindRule corresponds to FindCommand. Thus, if you are to implement saving find plan rules, name them as PlanSearchRule, AddFindPlanRuleCommand, UniqueFindPlanRuleList, etc.

Under the category of save find rules feature, we have the following Command classes and their corresponding Parser classes:

  • AddFindRuleCommand

  • DeleteFindRuleCommand

  • ApplyCommand
    It applies a problem-finding rule by specifying the index of the displayed find rule.

Since these commands share similar implementations, we will only take AddFindRuleCommand as an example since it’s the most complicated one among the three.

Implementation of addfindrule feature

The addfindrule feature is facilitated by AddFindRuleCommand and AddFindRuleCommandParser class.

AddFindRuleClassDiagram
Figure 33. Class Diagram for Add Find Rule Feature

The sequence diagram below shows the high-level abstraction of how AlgoBase processes the request when user types in addfindrule rule1 n/Sequences:

HighLevelAddFindRuleSequenceDiagram
Figure 34. High-level Sequence Diagram for the Execution of addfindrule rule1 n/Sequences

The sequence diagram below illustrates the interaction between the Logic and Model component when executing AddFindRuleCommand. Notice that the constructor for ProblemSearchRule requires Name to be non-null and accepts null values for other predicates. Thus if the predicate is not present in the arguments, AddFindRuleCommandParser will pass null to the constructor of ProblemSearchRule.

AddFindRuleSequenceDiagram
Figure 35. Sequence Diagram for the Execution of addfindrule Command

3.4.2. Design Considerations

Aspect: To implement ProblemSearchRule as a subclass of FindProblemDescriptor or implement it as an immutable concrete class.

Since AlgoBase is forked from AddressBook 3, it also inherits AB3’s design choice on all data classes - they are all immutable classes with all fields being final. However, ProblemSearchRule is essentially saving the information of a command input, where the user may provide any number of predicates as the argument. We implement mutable FindProblemDescriptor to accommodate variable user inputs, now we have to consider whether to keep ProblemSearchRule immutable or not.

  • Alternative 1 (current choice): ProblemSearchRule extends FindProblemDescriptor with an additional field name

    • Pros: Greatly reduces the amount of duplicate code as ProblemSearchRule shares most fields with FindProblemDescriptor

    • Cons: ProblemSearchRule as a data class is no longer immutable. We have to be careful not to call any setters it inherits from FindProblemDescriptor.

  • Alternative 2: ProblemSearchRule as an individual class with immutable fields.

    • Pros: Provides good protection over unexpected changes to the data fields.

    • Cons: Lots of duplicated code.

3.5. Graphical User Interface Features

An intuitive GUI facilitates the overall user friendliness of the application. The user should be able to navigate around the application easily to facilitate a smooth experience using AlgoBase. While the command line is fast for typing short commands, it us not ideal if the user is editing large amounts of text (e.g. when the user is adding description for a new problem). In this case, having a GUI will be more beneficial to the user and facilitates a smoother user experience.

Additionally, multitasking is important as a user may be tackling multiple algorithmic questions at a single time. This, we introduced tabbing, which facilitates multitasking in AlgoBase, which is an important requirement for competitive programmers.

3.5.1. Graphical User Interface Enhancements

Current Implementation

The following classes facilitate the handling of GUI actions:

  • UiActionType - An Enum of the types of UI actions that exist in AlgoBase.

  • UiActionDetails - An object containing details of a UI action.

  • UiAction - Interface with instructions for executing a UI action.

  • UiLogicManager - Implements Uilogic and manages the overall UI Logic.

  • AlgoBaseUiActionParser - Parses a UiActionDetails object into an implementation of UiAction.

  • UiActionResult - The result of executing the UI action.

When the user makes a change in the GUI, the change is propagated from Ui to UiLogic to Model and to Storage, as represented in the diagram below:

ArchitectureSequenceDiagram1
Figure 36. An example of a high level representation of the GUI Actions.

This process of how the application handles UI Actions is captured by the example in the Sequence Diagrams below:

EditProblemUiActionSequenceDiagram0
Figure 37. Interaction between UI and UiLogic

Step 1: The user edits the ProblemDetails controller class through his/her actions in the GUI.

Step 2: The ProblemDetails class constructs a new UiActionDetails object of type UiActionType.EditProblem.

Step 3: The executeUiAction of the MainWindow class is called with the UiActionDetails object, which in turn calls the execute method of UiLogicManager.

Step 4: The method call returns a UiActionResult object, which may optionally contain feedback for the user.

The following diagram goes into more details on how the UiLogic handles the UiActionDetails:

EditProblemUiActionSequenceDiagram1
Figure 38. Interactions between classes in the UiLogic component.

Step 1: The UiLogicManager passes the UiActionDetails object to the AlgoBaseUiActionParser, which in turn passes it to the EditProblemUiActionParser based on its Action type.

Step 2: The EditProblemUiActionParser converts the UiActionDetails object into a EditProblemUiAction object, and passes it back to the UiLogicManager.

Step 3: The UiLogicManager executes the EditProblemUiAction together with the Model, and returns the UiActionResult.

3.5.2. Graphical User Interface State

Current Implementation

The state of the GUI is stored in a GuiState object, which is in turn stored in the Model. The GuiState object contains a TabManager object, which manages tab information such as the tabs that are open and the tabs that are currently selected.

The following class diagram illustrates how the classes in the GuiState interact with one another:

GuiPackageDiagram
Figure 39. Class Diagram for the GuiState class

The following Activity diagram illustrates the series of actions that occur when the user opens a new tab:

OpenTabUiActionActivityDiagram
Figure 40. Activity Diagram for Opening a new Tab from the GUI

In AlgoBase, the state of the GUI is also saved to Storage after every action. This is so that when the user closes the application and opens it again later, the state is stored. The Sequence diagram below also shows how the GuiState is saved to Storage:

SwitchTabsSequenceDiagram3
Figure 41. Sequence Diagram for storing new GUI state

The StorageManager saves the modified GuiState as a new JSON file. This is done with the help of the JsonSerializableGui, JsonSerializableTabManager and JsonSerializableTab classes that are wrappers for the GuiState, TabManager and TabData classes. These wrapper classes can be converted into JSON format for storage without any data loss.

Design Considerations
Aspect Alternative 1 (Current Choice) Alternative 2

How to implement Commands and UI Actions in the same application

Handle Commands and UI Actions separately.

Pros: Higher modularity. Allows separation the different architectures as well (Synchronous for Commands & Event-Driven for UI Actions)

Cons: Multiple Logic managers (LogicManager and UiLogicManager)

Handle Commands and UI Actions together.

Pros: Less code and higher reusability.

Cons: Higher coupling and less cohesion.

How to handle different kinds of UI Actions

Using a command structure with a central parser and many smaller parsers.

Pros: Higher extensibility, easier to add new UI Actions

Cons: Have to write more code to achieve the same functionality.

Handling each UI action individually.

Pros: Can write less code to achieve the same functionality.

Cons: Lower extensibility, harder to add new UI Actions

3.6. Command Line Tab Management

3.6.1. Current Implementation

The following commands facilitate the management of tabs:

  • switchTab - Switch between tabs within a specified Tab pane.

  • openTab - Opens a new tab containing details of a model.

  • closeTab - Closes an existing tab.

These operations are exposed in the TabManager class respectively as:

  • SwitchTab: TabManager#switchTab

  • OpenTab: TabManager#openTab

  • CloseTab: TabManager#closeTab

The following Activity Diagrams illustrate what happens when the user executes a SwitchTabCommand or OpenTabCommand

SwitchTabCommandActivityDiagram
Figure 42. Activity Diagram for the Execution of switchtab Command
OpenTabCommandActivityDiagram
Figure 43. Activity Diagram for the Execution of opentab Command

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

SwitchTabsSequenceDiagram0
Figure 44. Sequence Diagram for instantiating a SwitchCommand object

Step 1: The user executes switchtab tt/display i/1 to switch to the first tab in the display tabpane.

Step 2: SwitchTabCommandParser processes the user input, retrieving the tab type (display) and the index (1).

Step 3: These two attributes are passed into the constructor of a SwitchTabCommand and a corresponding SwitchTabCommand object is returned to the LogicManager

SwitchTabsSequenceDiagram1
Figure 45. Sequence Diagram for updating the tab index in the TabManager

Step 4: LogicManager invokes execute() method of the returned SwitchTabCommand, which retrieves the TabManager from the Model object. The setDisplayTabPaneIndex(1) method is invoked with the index 1 that the SwitchTabCommand was instantiated with.

Step 5: Invoking this method updates the integer value in the displayTabIndex field (type ObservableIntegerValue) of the TabManager.

SwitchTabsSequenceDiagram2
Figure 46. Sequence Diagram for reflecting the tab changes

Step 6: A listener was added to the displayTabIndex field when the application was initialized. When a change in the value is detected, it triggers the selectTab(1) method with the value of the new index passed as an argument. This updates the selected tab in the UI.

SwitchTabsSequenceDiagram3
Figure 47. Sequence Diagram for storing new GUI state

Step 7: After the command is executed, the state of the GUI changes. This causes the StorageManager to save the modified GUI state as a new JSON file. This is done with the help of the JsonSerializableGui, JsonSerializableTabManager and JsonSerializableTab classes that are wrappers for the GuiState, TabManager and TabData classes. These wrapper classes can be converted into JSON format for storage without any data loss.

3.6.2. Design Considerations

Aspect Alternative 1 (Current Choice) Alternative 2

Implementation of Tab Logic

Implement Tab Logic separately within model and UI.

Pros: Modularizes the logic and reduces the need for tighter coupling between model and UI

Cons: Multiple sources of truth and more modules to be implemented

Implement Tab Logic as a singular module

Pros: Single source of truth for state of tabs

Cons: Increasing coupling between Model and UI, which in turn reduces testability

How to update the tab in the UI

Using a listener to detect changes to state of tab

Pros: Reduces coupling between the TabManager class and the UI

Cons: As callback functions are utilized, it is not immediately obvious how changes in state of TabManager leads to a change in the UI

Updating the UI synchronously

Pros: Execution is sequential and it is easier to keep track of the flow of the program.

Cons: Increases coupling between the TabManager class and the UI and reduces testability.

3.7. Training Plan Feature

Training plan feature allows users to create customized training plans with specific starting date and end date and that consist of selected problems in AlgoBase. Each problem is wrapped up as a task in the plan. Users can record their progress by marking problems in plans as done or undone, and they can edit, delete or search for plans.

3.7.1. Current Implementation

The training plan mechanism is faciliated by AlgoBase, which keeps a list of training plans. It supports the following operations:

  • Algobase#addPlan() — Adds a new training plan.

  • AlgoBase#setPlan() — Replaces an existing plan by an edited version.

  • AlgoBase#removePlan() — Deletes a training plan.

  • AlgoBase#getPlanList() — Returns a list of training plans.

PlanClassDiagram
Figure 48. Class Diagram of Plan

Given below is an example usage scenario and how the AlgoBase behaves at each step.

Step 1. The user launches the application for the first time. The AlgoBase will be initialized with the initial empty state.

Step 2. The user switches to the plan tab and executes addplan n/CS2040 d/past year questions start/2019-01-01 end/2019-05-04 command to add a new plan to AlgoBase. The addplan command checks if Model#hasPlan() and calls Model#addPlan(), causing the modified state of plans after the addplan command executes to be saved in the PlanList.

AddPlanSequenceDiagram
Figure 49. Sequence Diagram for the execution of AddPlanCommand

Step 3. The user executes listplan to list all plans. The listplan command calls Model#updateFilteredPlanList(). The plan CS2040 is numbered 1 in the displayed list.

Step 4. The user finds out that the exam date of CS2040 has changed, and decides to change the end date of the training plan by executing the editplan 1 end/2019-05-05 command. The editplan command will check if Model#hasPlan(), and then call Model#setPlan() and Model#updateFilteredPlanList(), which will replace the original plan with the modified plan in the PlanList.

EditPlanCommandActivityDiagram
Figure 50. Activity Diagram for the Execution of EditPlanCommand
The user can also add value for an empty field by executing editplan command if the field has not been specified when adding the plan.

Step 5. The user then decides to execute the command findplan start/2019-03-01 end/2019-03-31 to find out what plans he has in March. The findplan command constructs a FindPlanDescriptor, and then executes Model#getFilteredPlanList() and Model#updateFilteredPlanList(FindPlanDescriptor). A list of plans in AlgoBase that has overlapping time range with the specified starting date and end date will be displayed on the plan list panel.

FindPlanDescriptorClassDiagram
Figure 51. Class Diagram for FindPlanDescriptor
If the user wants to find plans with overlapping time range, both the starting date and the end date should be specified, and the starting date should be before or at least equal to the end date, or an error message will be displayed to inform the user the correct form of input.

Step 6. The user executes deleteplan 1, which calls Model#getFilteredPlanList() and Model#deletePlan. The Model#getFilteredPlanList() returns the last shown plan list, which is list of plans returns by the findplan command in step 4. Therefore, the first plan with overlapping time range is deleted.

3.7.2. Design Considerations

Aspect: Data Structure of TimeRange class
  • Alternative 1 (current choice): Abstract out a TimeRange class in package plansearchrule.

    • Pros: Easy to implement.

    • Cons: Generating a TimeRange object in findplan command adds coupling, and is not very intuitive.

  • Alternative 2: Abstract out startDate and endDate fields in plans to a single field TimeRange .

    • Pros: More OOP (startDate and endDate are currently LocalDate objects).

    • Cons: We must ensure that the implementation complies with other date-related commands and storage of plans, such as adding or editing due dates of tasks in plans and the json file.

Aspect: How to find plans with certain tasks
  • Alternative 1 (current choice): By exactly-matching names.

    • Pros: Easy to implement.

    • Cons: Users need to figure out the exact name of the task they would like to find, which is more time-consuming.

  • Alternative 2: By indicating index of the original problem.

    • Pros: Complies with other usages of prefix task/.

    • Cons: Adds coupling due to access to filteredProblemList in the model.

  • Alternative 3: By exactly-matching tags of the original problem.

    • Pros: User-friendly.

    • Cons: Adds coupling due to access to filteredProblemList in the model as the wrapped-up task does not have a tag list field.

Appendix A: Product Scope

Target user profile:

  • has a need to manage a significant number of contacts

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition:

  • To manage algorithmic problems and training plans faster than using Excel sheets

Appendix B: 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 App

* * *

user

add a new problem

keep track of the problems for future usage

* * *

user

delete a problem

remove entries that I no longer need

* * *

user

find a problem by keyword

locate details of problems without having to go through the entire list

* *

user

do advanced search on problems

locate details of problems without having to go through the entire list

* *

user

do fuzzy search on problems

locate details of problems without having to go through the entire list

* * *

user

create custom tags

categorize problems via tags

* * *

user

add tags to problems

categorize problems via tags

* *

user

sort problems according to difficulty

locate problems easily

* *

user

add remarks to problems

have reference in the future

* * *

user

create plans containing problems

better prepare for interview

* * *

user

add tasks to a plan

better prepare for interview

* * *

user

mark tasks as done/undone within plans

keep track of progress within each plan

* * *

user

edit due dates of tasks

better manage progress for each plan

* * *

user

move tasks among plans

better manage progress for each plan

* * *

user

import database from JSON files

easily transfer data from one computer to another

* * *

user

export data into JSON format

easily transfer data from one computer to another

* *

advanced user

export data into CSV format

do some manipulation/processing on the data

Appendix C: Use Cases

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

Use Case 1: Add Problems

MSS

  1. User requests to add a new problem by entering the name of the problem, optionally specifying the description, author, weblink, source as well as any remarks or tags.

  2. AlgoBase adds a new problem with the provided details.

  3. AlgoBase indicates successful addition of new problem.

  4. AlgoBase displays details of problem added.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that an existing name already exists.

    • 2a1. AlgoBase informs user that problem was not successfully added because the name already exists.

      Use case ends.

  • 2b. AlgoBase detects that name is missing or format for some field(s) is invalid.

    • 2b1. AlgoBase informs user that problem was not successfully added because the format is invalid.

      Use case ends.

Use Case 2: Edit Problems

MSS

  1. User requests to edit an existing problem by entering the index, followed by fields that the user intends to edit (including name, description, weblink, author, source, remark, tag, etc.).

  2. AlgoBase edits the problem using the provided details.

  3. AlgoBase indicates successful edition of the existing problem.

  4. AlgoBase updates the UI with the updated problem.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the index is out of bounds.

    • 2a1. AlgoBase informs user that the edition is unsuccessful because the index is out of bounds.

      Use case ends.

  • 2b. AlgoBase detects that no fields are provided.

    • 2b1. AlgoBase informs user that nothing is updated.

      Use case ends.

Use Case 3: Delete Problems

MSS

  1. User requests to delete an existing problem by entering index.

  2. AlgoBase deletes the problem from storage.

  3. AlgoBase indicates successful deletion of the existing problem.

  4. AlgoBase updates the UI with the remaining problems.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the index is out of bounds.

    • 2a1. AlgoBase informs user that the deletion is unsuccessful because the index is out of bounds.

      Use case ends.

Use Case 4: List Problems

Guarantees

A list of existing problems will be displayed.

MSS

  1. User requests for a list of all existing problems.

  2. AlgoBase retrieves all problems in storage.

  3. AlgoBase displays in the UI the list of problems stored in AlgoBase.

    Use case ends.

Extensions

  • 2a. AlgoBase detects no existing problems stored.

    • 2a1. AlgoBase informs user that there is no existing problems.

      Use case ends.

Use Case 5: Find Problems

Guarantees

A list of existing problems with matching keywords in specified fields will be displayed.

MSS

  1. User requests to find problems by specifying keywords in certain fields.

  2. AlgoBase retrieves all problems with matching keywords in specified fields from storage.

  3. AlgoBase displays in the UI the list of problems with matching keywords in specified fields.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that no keywords in any fields are specified.

    • 2a1. AlgoBase informs user that at least one constraint should be provided.

      Use case ends.

Use Case 6: Sort Problems

Guarantees

A list of problems will be displayed in a specific order provided by user.

MSS

  1. User requests to sort a set of problems by specifying rules of ordering.

  2. AlgoBase sorts the problem list using the provided order.

  3. AlgoBase displays the set of questions in sorted order.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that no sorting method is specified.

    • 2a1. AlgoBase informs user that no sorting method is given.

      Use case ends.

Use Case 7: Add Tag

MSS

  1. User requests to add a tag.

  2. AlgoBase creates the tag with taq name and tag color.

  3. AlgoBase displays the tag list.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that tag name or tag color has an invalid format.

    • 2a1. AlgoBase informs user that the form of new tag is invalid.

      Use case ends.

Use Case 8: Delete Tag

MSS

  1. User requests to delete a tag.

  2. AlgoBase deletes the tag in tag list.

  3. AlgoBase deletes the tag in every problems.

  4. AlgoBase displays the tag list.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the index of tag in not valid.

    • 2a1. AlgoBase informs user that the index of tag is invalid.

      Use case ends.

Use Case 9: Edit Tag

MSS

  1. User requests to edit a tag.

  2. AlgoBase edits the tag with taq name and tag color.

  3. AlgoBase displays the tag list.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that tag name or tag color has an invalid format.

    • 2a1. AlgoBase informs user that the form of new tag is invalid.

      Use case ends.

Use Case 10: List Tag

MSS

  1. User requests to list the tags.

  2. AlgoBase displays the tag list.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that tag name or tag color has an invalid format.

    • 2a1. AlgoBase informs user that the form of new tag is invalid.

      Use case ends.

Use Case 11: Add Tasks to Plan

MSS

  1. User requests to add a new task by entering the index of the problem, index of the plan and optionally a due date.

  2. AlgoBase creates a new task with the specified problem (and due date).

  3. AlgoBase adds the newly created task to the specified plan.

  4. AlgoBase indicates successful addition of new task to plan.

  5. AlgoBase displays details of task added.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the index of problem is out of bounds.

    • 2a1. AlgoBase informs user that the addition is unsuccessful because the index of problem is out of bounds.

      Use case ends.

  • 3a. AlgoBase detects that the index of plan is out of bounds.

    • 3a1. AlgoBase informs user that the addition is unsuccessful because the index of plan is out of bounds.

      Use case ends.

  • 3b. AlgoBase detects that the given due date is outside the range of the target plan.

    • 3b1. AlgoBase informs user that the addition is unsuccessful because the given due date is not within range of target plan.

      Use case ends.

Use Case 12: Copy Tasks between Plans

MSS

  1. User requests to copy an existing task from one plan to another by entering the index of the task and the indices of the plans involved.

  2. AlgoBase copies the specified task from the specified "from" plan to the "to" plan.

  3. AlgoBase indicates that the existing task is copied successfully.

  4. AlgoBase displays list of tasks of the updated "to" plan.

    Use case ends.

Extensions

  • 2b. AlgoBase detects that the index of task is out of bounds.

    • 2b1. AlgoBase informs user that the update is unsuccessful because the index of task is out of bounds.

      Use case ends.

  • 2c. AlgoBase detects that task to be copied already exists in the target plan.

    • 2c1. AlgoBase informs user that the update is unsuccessful because the task already exists.

      Use case ends.

Use Case 13: Delete Tasks from Plan

MSS

  1. User requests to delete an existing task by entering the index of the plan and index of the task.

  2. AlgoBase deletes the specified task from the specified plan.

  3. AlgoBase indicates successful deletion of the existing task.

  4. AlgoBase updates the UI with the remaining tasks in the plan.

    Use case ends.

Extensions

Use Case 14: Edit Due Dates of Tasks

MSS

  1. User requests to edit due date of an existing task by entering the index of the plan, index of the task and new due date.

  2. AlgoBase edits the due date of the specified task in the specified plan.

  3. AlgoBase indicates that the existing task is edited successfully.

  4. AlgoBase displays details of the task updated.

    Use case ends.

Extensions

Use Case 15: Mark Tasks as Done in Plan

MSS

  1. User requests to mark an existing task as done by entering the index of the plan and index of the task.

  2. AlgoBase marks the specified task as done in the specified plan.

  3. AlgoBase indicates that the existing task is marked as done successfully.

  4. AlgoBase displays details of the task updated.

    Use case ends.

Extensions

  • 2c. AlgoBase detects that target task is already marked as done.

    • 2c1. AlgoBase informs user that the update is unsuccessful because the task is already done.

      Use case ends.

Use Case 16: Mark Tasks as Undone in Plan

MSS

  1. User requests to mark an existing task as undone by entering the index of the plan and index of the task.

  2. AlgoBase marks the specified task as undone in the specified plan.

  3. AlgoBase indicates that the existing task is marked as done successfully.

  4. AlgoBase displays details of the task updated.

    Use case ends.

Extensions

Use Case 17: Move Tasks between Plans

MSS

  1. User requests to move an existing task from one plan to another by entering the index of the task and the indices of the plans involved.

  2. AlgoBase moves the specified task from the specified "from" plan to the "to" plan.

  3. AlgoBase indicates that the existing task is moved successfully.

  4. AlgoBase displays list of tasks of the updated "to" plan.

    Use case ends.

Extensions

Use Case 18: Set Current Plan in Main Display

MSS

  1. User requests to set a plan as the current plan in main display.

  2. AlgoBase sets the specified plan as the current plan.

  3. AlgoBase indicates that the specified plan is successfully set as the current plan.

  4. AlgoBase displays updated current plan in main display.

    Use case ends.

Extensions

Use Case 19: Switch between View of Items

MSS

  1. User requests to switch the current view of items to a different view of items.

  2. AlgoBase displays the list of items corresponding to that view.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the specified view of items does not exist.

    • 2a1. AlgoBase informs user that the specified view of items does not exist.

      Use case ends.

Use Case 20: See details of an item

MSS

  1. User requests to see the details of a specified item from the list of items.

  2. AlgoBase displays the details of that item.

    Use case ends.

Use Case 21: Export AlgoBase data

MSS

  1. User requests to export AlgoBase data to a specified path.

  2. AlgoBase exports AlgoBase data to a file name algobase.json in the specified location.

  3. AlgoBase indicates that AlgoBase data are exported successfully.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the specified path is invalid.

    • 2a1. AlgoBase informs user that the export is unsuccessful because the path is invalid.

      Use case ends.

Use Case 22: Import AlgoBase data

MSS

  1. User requests to import data from a specified file into AlgoBase.

  2. AlgoBase imports data from the specified file into AlgoBase.

  3. AlgoBase indicates that the data are imported into AlgoBase successfully.

    Use case ends.

Extensions

  • 2a. AlgoBase detects that the specified file does not exist.

    • 2a1. AlgoBase informs user that the import is unsuccessful because the file path is invalid.

      Use case ends.

Appendix D: Non Functional Requirements

  1. Every change is saved immediately and no manual saving is needed.

  2. A user with above average typing speed for regular Unix commands should be able to accomplish most of the tasks faster using commands than using the mouse.

  3. Should work on any mainstream OS as long as it has Java 11 or above installed.

  4. Should work on both 32-bit and 64-bit environments.

  5. Should be able to hold up to 1000 problems with response time less than 1 second for typical usage.

  6. Should work without installation (i.e. portable).

  7. Should be for a single user i.e. (not a multi-user product).

  8. Storage file should be human interpretable and editable for someone who’s familiar with JSON.

  9. Not required to store solutions to problems.

Appendix E: Glossary

JSON

JavaScript Object Notation

Mainstream OS

Windows, Linux, Unix, OS-X

Environment

An execution environment offered by mainstream OSes as defined above

Response Time

An execution environment offered by mainstream OSes as defined above

Solutions to Problems

Source code or executable that aims to solve the corresponding problem

Appendix F: 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.

F.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 problems. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the jar file.
      Expected: The most recent window size and location is retained.

F.2. Problem

F.2.1. Adding a problem

  1. Test case: addprob n/Sequences d/find number of inversions t/algorithm
    Expected: A problem named 'Sequences' and tagged 'algorithm' is added to AlgoBase.

  2. Test case: addprob n/ d/unnamed problem
    Expected: No problem is added. The problem’s name shouldn’t be blank. Error details shown in the status message.

F.2.2. Deleting a problem

  1. Prerequisites: List all problems using the listprob or findprob or sortprob command. Multiple problems in the list.

  2. Test case: deleteprob 1
    Expected: First problem is deleted from the list, details shown in the status message, timestamp in the status bar is updated. Otherwise show message will ask to force delete all related tasks in plans.

  3. Test case: deleteprob 0
    Expected: No problem is deleted. Error details shown in the status message. Status bar remains the same.

  4. Other incorrect delete commands to try: delete, deleteprob x (where x is larger than the list size)
    Expected: Similar to previous.

F.2.3. Editing a problem

  1. Prerequisites: List all problems using the listprob or findprob or sortprob command. Multiple problems in the list.

  2. Test case: editprob 1 n/Two Sequences
    Expected: Change the name of the first problem to 'Two Sequences'.

  3. Test case: editprob 2 t/
    Expected: Removes all tags from the second problem.

  4. Test case: editprob x
    Expected: No problem is edited. Index of problem should be a valid integer. Error details shown in the status message.

F.2.4. Listing problems

  1. Test case: listprob
    Expected: All problems in AlgoBase are listed in the problem panel.

F.2.5. Sorting problems

  1. Test case: sortprob m/name
    Expected: The current problem list is sorted with respect to names in ascending order.

  2. Test case: sortprob m/difficulty ord/descend
    Expected: The current problem list is sorted with respect to difficulty in descending order.

  3. Test case: sortprob m/diff
    Expected: The current problem list remains unchanged and an error is thrown to inform the user that the method name is incorrect.

  4. Test case: sortprob m/diff m/name
    Expected: The current problem list is sorted with respect to name in ascending order.

  5. Test case: sortprob m/name m/diff
    Expected: The current problem list remains unchanged and an error is thrown to inform the user that the method name is incorrect.

F.2.6. Finding a problem

  1. Test case: findprob n/sort
    Expected: All problems whose name includes “sort” (case-insensitive) is listed in the “Problems” panel.

  2. Test case: findprob
    Expected: An error is thrown and the user is informed that at least one constraint should be provided.

F.3. Tag

F.3.1. Adding a tag

  1. Test case: addtag t/test c/BLUE
    Expected: New Tag [test] added to AlgoBase.

  2. Test case: type in addtag t/test c/BLUE for twice
    Expected: Tag [test] already exists in AlgoBase.

F.3.2. Deleting a tag

  1. Test case: deletetag 1
    Expected: Tag [test] deleted.

  2. Test case: deletetag 9999
    Expected: The Tag index provided is invalid

F.3.3. Editing a tag

  1. Test case: edittag 1 t/edited c/RED
    Expected: Tag [edited] edited.

  2. Test case: edittag t/edited c/RED
    Expected: An error is thrown and the user is informed that the format of command is invalid.

F.3.4. Listing a tag

  1. Test case: listtag
    Expected: All tags listed.

F.4. Find Rule

F.4.1. Adding a problem-finding rule

  1. Prerequisites: there is no find rules named “rule1” or “rule2” or “rule3” in the existing AlgoBase, and find rules with a certain name is never added more than once.

  2. Test case: addfindrule rule1 n/Sequences
    Expected: A new find rule named “rule1” is added and the new rule appears in the “Find Rules” panel.

  3. Test case: afr rule2 n/sequences
    Expected: A new find rule named “rule2” is added and the new rule appears in the “Find Rules” panel.

  4. Test case: afr rule3
    Expected: An error is thrown and the user is informed that at least one constraint should be provided.

F.4.2. Applying a problem-finding rule

  1. Prerequisites: there are four find rules in the existing AlgoBase.

  2. Test case: apply 1
    Expected: The first find rule is applied, the problems in the “Problems” panel are updated accordingly.

  3. Test case: apply 0
    Expected: An error is thrown and the user is informed that the command format is invalid.

  4. Test case: apply 100
    Expected: An error is thrown and the user is informed that the provided find rule index is invalid.

F.4.3. Deleting a problem-finding rule

  1. Prerequisites: there are four find rules in the existing AlgoBase.

  2. Test case: deletefindrule 1
    Expected: The first find rule is deleted and the find rules list is updated.

  3. Test case: dfr 1
    Expected: The first find rule is deleted and the find rules list is updated.

F.5. Plan

F.5.1. Adding a plan

  1. Test case: addplan n/ByteDance d/coding test for Software engineering
    Expected: A new plan with respective information is added and displayed on plan tab. Start date is now and end date is one month from now.

  2. Test case: addplan n/ByteDance d/coding test for Software engineering
    Expected: No plan is added. No plans with duplicate names can be added. Error details shown in the status message.

  3. Test case: addplan n/Graph start/2019-1-1 end/2019-3-3
    Expected: No plan is added. The date should be in yyyy-MM-dd format. Error details shown in the status message.

  4. Test case: addplan n/Graph end/1912-06-23
    Expected: No plan is added. If no starting time is specified, the starting time will be LocalDate#now(), and the starting time should not be after end time. Error details shown in the status message.

F.5.2. Editing a plan

  1. Prerequisites: List all plans using the listplan or findplan command. Multiple plans in the list.

  2. Test case: editplan 1 d/give up start/2019-01-01 end/2020-02-02
    Expected: The description and the dates of the first displayed plan is changed.

  3. Test case: editplan 1 end/2018-02-02
    Expected: Edit command is invalid. Error details shown in the status message. Starting date should be before or equal to end date.

  4. Test case: editplan 1 end/2019-02-02 f/
    Expected: The end date of the first displayed plan is changed to 2019-02-02. Any task’s due date after 2019-02-02 will be changed to 2019-02-02. ..Test case: editplan 1 start/2019-01-30 f/
    Expected: The starting date of the first displayed plan is changed to 2019-01-30. Any task’s due date before 2019-01-30 will be changed to the plan’s end date.

F.5.3. Finding plans

  1. Test case: findplan n/bytedance
    Expected: The plan named 'ByteDance' is listed.

  2. Test case: findplan start/2019-01-01 end/2019-12-12
    Expected: Plans whose time range overlaps with the given time range are listed in the plan panel.

  3. Test case: findplan start/2019-01-01
    Expected: Invalid command. Both range start and range end should be specified. Error details shown in the status message.

  4. Test case: findplan start/2019-01-01 end/2018-01-02
    Expected: Invalid command. Range start should not be after range end. Error details shown in the status message.

F.5.4. Deleting a plan

  1. Prerequisites: List all plans using the listplan or findplan command. Multiple plans in the list.

  2. Test case: findplan n/bytedance
    deleteplan 1
    Expected: The plan with name 'ByteDance' is deleted.

  3. Test case: listplan
    deleteplan 1
    Expected: The first plan among all plans is deleted.

F.5.5. Listing plans

  1. Test case: listplan
    Expected: All plans in Algobase are listed in the plan display tab.

F.5.6. Setting a plan as current plan

  1. Prerequisites

    1. There are exactly 2 training plans in AlgoBase.

  2. Test case: setplan 2
    Expected: Plan 2 is set as the current plan. The task management pane is updated. Current plan in the task management is updated to plan 1.

  3. Test case: setplan 20
    Expected: No task is added. Error details shown in the status message, indicating that the given plan index is invalid.

F.6. Task

F.6.1. Adding a task to an existing plan

  1. Prerequisites

    1. There is at least 1 training plan and 10 problems in AlgoBase.

    2. Plan 1 is empty.

    3. Start and end dates of plan 1 are 2019-11-15 and 2019-12-15 respectively.

  2. Test case: addtask plan/1 prob/1
    Expected: A new task is created from problem 1 with due date on 2019-12-15, and added to task list in plan 1. Current plan in the task management is updated to plan 1.

  3. Test case: addtask plan/1 prob/2 due/3030-01-01
    Expected: No task is added. Error details shown in the status message, indicating that the due date is not within the range of plan.

F.6.2. Editing due date of a task

  1. Prerequisites

    1. There is at least 1 training plan in AlgoBase.

    2. Plan 1 has at least 1 task.

    3. Start and end dates of plan 1 are 2019-11-15 and 2019-12-15 respectively.

  2. Test case: edittask plan/1 task/1 due/2019-11-20
    Expected: The due date of the first task in plan 1 is updated to 2019-11-20.

  3. Test case: edittask plan/1 task/1 due/3030-01-01
    Expected: Error details shown in the status message, indicating that the due date is not within the range of plan.

F.6.3. Deleting a task

  1. Prerequisites

    1. There is exactly 1 training plan in AlgoBase.

    2. Plan 1 has at least 1 task.

  2. Test case: deletetask plan/1 task/1
    Expected: The first task in plan 1 is deleted.

  3. Test case: deletetask plan/100 task/1
    Expected: Error details shown in the status message, indicating that the plan index is invalid.

F.6.4. Marking a task as done

  1. Prerequisites

    1. There is at least 1 training plan in AlgoBase.

    2. Plan 1 has at least 2 tasks.

    3. The first task in plan 1 is not yet done.

    4. The second task in plan 1 is already done.

  2. Test case: donetask plan/1 task/1
    Expected: The first task in plan 1 is marked as done.

  3. Test case: donetask plan/1 task/2
    Expected: Error details shown in the status message, indicating that the specified task is already done.

F.6.5. Marking a task as undone

  1. Prerequisites

    1. There is at least 1 training plan in AlgoBase.

    2. Plan 1 has at least 2 tasks.

    3. The first task in plan 1 is already done.

    4. The second task in plan 1 is not yet done.

  2. Test case: undonetask plan/1 task/1
    Expected: The first task in plan 1 is marked as undone.

  3. Test case: undonetask plan/1 task/2
    Expected: Error details shown in the status message, indicating that the specified task is not yet done.

F.6.6. Copying a task between plans

  1. Prerequisites

    1. There are at least 2 training plans in AlgoBase.

    2. Plan 1 has at least 2 tasks.

    3. Plan 2 has exactly 1 task, which is the same the the first task in plan 1.

  2. Test case: copytask task/2 from/1 to/2
    Expected: The second task in plan 1 is copied to plan 2.

  3. Test case: copytask task/1 from/1 to/2
    Expected: Error details shown in the status message, indicating that the specified task is already in plan 2.

F.6.7. Moving a task between plans

  1. Prerequisites

    1. There are at least 2 training plans in AlgoBase.

    2. Plan 1 has at least 2 tasks.

    3. Plan 2 has exactly 1 task, which is the same the the first task in plan 1.

  2. Test case: movetask task/2 from/1 to/2
    Expected: The second task in plan 1 is copied to plan 2.

  3. Test case: movetask task/1 from/1 to/2
    Expected: Error details shown in the status message, indicating that the specified task is already in plan 2.

F.7. GUI

F.7.1. Switching tabs

  1. Switching between Tabs

    1. Prerequisites: Currently at the first display tab (Problem).

    2. Test case: switchtab tt/display i/2
      Expected: The display tab is now at the Tags tab.

    3. Test case: st tt/1 i/2
      Expected: The display tab is now at the Tags tab.

    4. Test case: switchtab tt/details i/2
      Expected: The details tab is now at the second tab.

    5. Test case: st tt/2 i/2
      Expected: The details tab is now at the second tab.

    6. Test case: st tt/2 i/5 (Assuming only 4 details tab exist)
      Expected: The details tab is not changed. Error message is shown.

  2. Switching to non-existent Tab Type index

    1. Test case: switchtab tt/3 i/1
      Expected: No tabs are changed. Error message is shown.

F.7.2. Opening a new tab

  1. Opening a new Details Tab for a Problem or Plan

    1. Prerequisites: At least 1 problem or plan exists in the current problem display tab.

    2. Test case: opentab m/problem i/1
      Expected: A new details tab containing the problem at index 1 of the currently displayed problem list is opened. The tab is selected as well.

    3. Test case: opentab m/plan i/1
      Expected: A new details tab containing the plan at index 1 of the currently displayed plan list is opened. The tab is selected as well. The plan tab also updates to display the selected plan.

    4. Test case: ot m/3 i/1
      Expected: A new details tab containing the plan at index 1 of the currently displayed plan list is opened. The tab is selected as well. The plan tab also updates to display the selected plan.

    5. Test case: opentab m/problem i/0
      Expected: No details tab are opened. Error message is shown.

    6. Test case: ot m/3 i/4 (Assuming only 3 plans exist)
      Expected: No details tab are opened. Error message is shown.

  2. Opening an existing Details Tabs for a Problem or Plan

    1. Prerequisites: At least 1 problem or plan exists and it is already in a details tab.

    2. Test case: opentab m/problem i/1 (Assuming the first problem is in a Details Tab)
      Expected: The existing details tab containing the problem is selected.

    3. Test case: ot m/3 i/1 (Assuming the first plan is in a Details Tab)
      Expected: The existing details tab containing the plan is selected. The plan tab also updates to display the selected plan.

  3. Opening a non-existent Model Type index

    1. Test case: ot m/5 i/1
      Expected: No tabs are opened. Error message is shown.

F.7.3. Closing an existing tab

  1. Prerequisites: At least one Details Tab exist.

  2. Test case: closetab i/1 while first tab is selected (Assuming there are 3 details tabs)
    Expected: The first tab is closed and the new first tab (previously second tab) is selected.

  3. Test case: ct i/1 while first tab is selected (Assuming there are 3 details tabs)
    Expected: The first tab is closed and the new first tab (previously second tab) is selected.

  4. Test case: closetab i/3 while first tab is selected (Assuming there are 3 details tabs)
    Expected: The last tab is closed and the new first tab (previously second tab) is selected.

  5. Test case: ct i/3 while first tab is selected (Assuming there are 3 details tabs)
    Expected: The last tab is closed and the new first tab (previously second tab) is selected.

  6. Test case: ct i/0 while current tab is selected (Assuming there are 3 details tabs)
    Expected: No details tab are closed. Error message is shown.

  7. Test case: ct i/4 while current tab is selected (Assuming there are 3 details tabs)
    Expected: No details tab are closed. Error message is shown.

F.7.4. Editing a problem from GUI

  1. Prerequisites: At least one problem exists and it is opened in a Details Tab.

  2. Test case: No changes are made to the Problem.
    Expected: The Edit Problem button should be disabled and not clickable.

  3. Test case: Some valid changes are made and the user clicks on Edit Problem button.
    Expected: Name of the edited problem shown in the status message. Field updates are reflected in the Display, Details and Plan tabs. Edit Problem button is disabled.

  4. Test case: Some invalid changes are made and the user clicks on Edit Problem button.
    Expected: Error details shown in the status message. Field updates are not reflected in the Display and Plan tabs, and Details Tab remains in edit mode. Edit Problem button is not disabled.

F.7.5. Deleting a problem from GUI

  1. Prerequisites: At least one problem exists and it is opened in a Details Tab.

  2. Test case: User clicks on the Delete button.
    Expected: A warning dialog shows up with a Confirm and Cancel button.

  3. Test case: User clicks on the Delete button then clicks Confirm on the warning dialog.
    Expected: The Warning dialog and Details tab is closed, and the problem is removed from the plan as well as Display and Plan tabs.

  4. Test case: User clicks on the Delete button then clicks Cancel on the warning dialog.
    Expected: The Warning dialog is closed and no other changes are made.

F.7.6. Editing a plan from GUI

  1. Prerequisites: At least one plan exists and it is opened in a Details Tab.

  2. Test case: No changes are made to the Plan.
    Expected: The Edit Plan button should be disabled and not clickable.

  3. Test case: Some valid changes are made and the user clicks on Edit Plan button.
    Expected: Name of the edited plan shown in the status message. Field updates are reflected in the Display, Details and Plan tabs. Edit Plan button is disabled.

  4. Test case: Some invalid changes are made and the user clicks on Edit Problem button.
    Expected: Error details shown in the status message. Field updates are not reflected in the Display and Plan tabs, and Details Tab remains in edit mode. Edit Plan button is not disabled.

F.7.7. Deleting a plan from GUI

  1. Prerequisites: At least one plan exists and it is opened in a Details Tab.

  2. Test case: User clicks on the Delete button.
    Expected: A warning dialog shows up with a Confirm and Cancel button.

  3. Test case: User clicks on the Delete button then clicks Confirm on the warning dialog.
    Expected: The Warning dialog and Details tab is closed, and the plan is removed from the Display and Plan tabs.

  4. Test case: User clicks on the Delete button then clicks Cancel on the warning dialog.
    Expected: The Warning dialog is closed and no other changes are made.

F.7.8. Switching tabs from GUI

  1. Switching between Display Tabs

    1. Prerequisites: Currently at the first display tab (Problem).

    2. Test case: Click on Training Plans Tab
      Expected: The display tab is now at the Training Plans tab.

  2. Switching between Details Tabs

    1. Prerequisites: At least 2 Details Tabs are opened. Currently at the first details tab.

    2. Test case: Click on a different tab
      Expected: The display tab is now at the tab that is clicked on.

F.7.9. Opening a new tab from GUI

  1. Opening a new Details Tabs for a Problem or Plan

    1. Prerequisites: There is at least 1 problem or plan in the Display Tab currently.

    2. Test case: The user double clicks on a problem or plan in the display tab.
      Expected: The problem or plan is added as the last tab of the Details Tabs and is selected.

  2. Opening an existing Details Tabs for a Problem or Plan

    1. Prerequisites: At least 1 problem or plan exists and it is already in a details tab.

    2. Test case: The user double clicks on a problem or plan in the display tab that is already in a details tab. Expected: The tab is switched to details tab containing the problem or plan.

F.7.10. Closing an existing tab from GUI

  1. Prerequisites: At least one Details Tab exist.

  2. Test case: User clicks on the x button next to the tab.
    Expected: The Details tab corresponding to that tab is closed.

F.8. Data

  1. Test case: Delete the data folder in project root folder and launch AlgoBase.
    Expected: No errors shown. A new data file is created silently.

  2. Test case: Delete some mandatory fields in the data file located at data/algobase.json and launch AlgoBase.
    Expected: Error details shown in the status message, indicating corrupted data file.