GitHub CoPilot was used to help speed up tasks like writing documentation, writing JavaDocs, creating TestUtil Classes and autocompleting repetitive method calls. It was also used at times to troubleshoot bugs and help to generate difficult parts of the code (e.g. regex expressions for parsing commands with differing requirements)
Some less commonly used packages of the Java's standard library were also used which includes the java.awt library and the java.net package which are used to implement the link article
feature.
Refer to the guide Setting up and getting started.
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
(consisting of classes Main
and MainApp
) is in charge of the app launch and shut down.
The bulk of the app's work is done by the following 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.Commons
represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
Each of the four main components (also shown in the diagram above),
interface
with the same name as the Component.{Component Name}Manager
class which follows the corresponding API interface
mentioned in the previous point.For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
Logic
component.Model
data so that the UI can be updated with the modified data.Logic
component, because the UI
relies on the Logic
to execute commands.Model
component, as it displays Person
object residing in the Model
.API : Logic.java
Here's a (partial) class diagram of the Logic
component:
The sequence diagram below illustrates the interactions within the Logic
component, taking execute("delete 1")
API call as an example.
Note: The lifeline for DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the Logic
component works:
Logic
is called upon to execute a command, it is passed to an AddressBookParser
object which in turn creates a parser that matches the command (e.g., DeleteCommandParser
) and uses it to parse the command.Command
object (more precisely, an object of one of its subclasses e.g., DeleteCommand
) which is executed by the LogicManager
.Model
when it is executed (e.g. to delete a person).Model
) to achieve.CommandResult
object which is returned back from Logic
.Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AddressBookParser
class creates an XYZCommandParser
(XYZ
is a placeholder for the specific command name e.g., AddCommandParser
) which uses the other classes shown above to parse the user command and create a XYZCommand
object (e.g., AddCommand
) which the AddressBookParser
returns back as a Command
object. If the command deals with Articles then the AddressBookParser
will pass it to the ArticleBookParser
which will then handle to command similarly to the AddressBookParser
.XYZCommandParser
classes (e.g., AddCommandParser
, DeleteCommandParser
, ...) inherit from the Parser
interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model
component,
Person
objects (which are contained in a UniquePersonList
object).Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Person>
that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.UserPref
object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref
objects.Model
represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a Tag
list in the AddressBook
, which Person
references. This allows AddressBook
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.
API : Storage.java
The Storage
component,
AddressBookStorage
, ArticleBookStorage
and UserPrefStorage
, which means it can be treated as any one of these (if only the functionality of only one is needed).Model
component (because the Storage
component's job is to save/retrieve objects that belong to the Model
)Classes used by multiple components are in the seedu.addressbook.commons
package.
This section describes some noteworthy details on how certain features are implemented.
The sort persons command is implemented in the SortCommand
class. The SortCommand
class is a subclass of the PersonCommand
class, which is in turn a subclass of the Command
class. The SortCommand
class is responsible for sorting the persons in the address book according to a field present in the Person
class by overriding the following method in the Command
class:
execute(Model model)
— Sorts the persons in the address book according to a field present in the Person
class which is mapped to the prefix
field in the SortCommand
object.Given below is an example usage scenario and how the sort persons feature behaves at each step.
Step 1. The user launches the application for the first time. The AddressBook
will be initialized with the initial address book state.
Step 2. The user executes sort n/
command. The sort
command calls Model#sortAddressBook("n/")
which sorts the persons in the address book by name in increasing lexicographical order.
The following sequence diagram shows how a sort persons operation goes through the Logic
component:
Similarly, how a sort persons operation goes through the Model
component is shown below:
Aspect: How sort persons executes:
Alternative 1 (current choice): Directly sort the internalList
field present in the UniquePersonList
object.
AddressBook
by the Person
field specified by the related prefix
.Alternative 2: Clone the current internalList
field
present in the UniquePersonList
object, sort the clone, then replace the internalUnmodifiableList
field in the UniquePersonList
object with the sorted clone.
AddressBook
by the Person
field specified by the related prefix
, but only the current view displayed to the user which is refreshed for every opening of the application or commands that changes the view (e.g. List
, Find
commands).AddressBook
since a clone of all Persons
has to be made.The filter mechanism is facilitated by filter
interface. The ArticleFilter and PersonFilter classes will inherit from it.
The filters will store Predicate<>
objects that will determine which Persons or articles will be shown to the user.
ModelManager
will contain a filter, which it will use to generate FilteredLists
Given below is an example usage scenario:
Step 1. The user launches the application. The ModelManager
will be initialized, along with the Filter objects it contains. finalPredicate
will be set to display all articles for now.
Step 2. The user executes filter -a s/ st/ en/ t/DRAFT
to look for articles he is currently working on. The filter article command gets the ArticleFilter
object using getFilter()
. Then it updates the filter object by calling the updateFilter()
method, changing the finalPredicate
.
Step 3. Now that the filter has been updated. The user now looks through PressPlanner to search for the article. He decides to search by title to make it faster. He executes find -a AI
. Beyond matches with the name, PressPlanner is still filtering to show only DRAFT articles, allowing the user to search a smaller set.
Step 4. The user has found his article and wishes to remove the filter. He does this by executing set -a S/ ST/ EN/
. With no instructions, the predicate allows all articles to pass through the filter.
Note: If start date is later than the end date, PressPlanner will refuse to execute the command, double-check the dates to avoid this scenario.
Note: Filters are NOT stored by the program. If you close the app, your filters will be reset.
The proposed lookup feature is enabled by altering Person
and Article
classes to store a list of Article
and Person
objects respectively. The Person
class will have a List<Article>
attribute that stores the articles that the person is involved in. The Article
class will have a List<Person>
attribute that stores the persons involved in the article.
When a Person
object is added/edited, the Model
component will check if the name of the person Person
matches the name of the contributors/interviewees in any Article
in the ArticleBook
. If it does, the Person
object will be updated with new Article
objects in the list of articles it contains. Editing the name will also change the name of the corresponding contributor/interviewee in the Article
objects. Adding a Article
object work similarly, but in reverse. However, editing the name of contributors/interviewees in the Article
objects will not update the corresponding names Person
objects.
The following diagram shows how the LookupCommand is executed:
The ArticlesInPersonPredicate tests the articles by checking whether the list of articles within the Person
object contains the article being tested. The PersonsInArticlePredicate tests the persons by checking whether the list of persons within the Article
object contains the article being tested.
Aspect: How to store associations between Person
and Article
objects:
Person
and Article
objects. Instead, since everytime the app is opened it reads all the persons and articles and adds them to the Model
, the Model
will always recreate the associations between Person
and Article
objects.
Person
and Article
objects in a separate AssociationStorage
object in the Storage
component.
Aspect: What criteria to use to create associations between Person
and Article
objects:
Person
object to match with the name of the contributors/interviewees in the Article
objects.
Person
object to match with the contributors/interviewees in the Article
objects.
Aspect: How editing the names affects the associated objects:
Person
object will also change the name of the corresponding contributor/interviewee in the Article
objects.
Article
objects.Article
objects.Person
object will not change the name of the corresponding contributor/interviewee in the Article
objects.
Article
objects.Person
and Article
objects.This feature closely follows the logic and model design of the sort persons feature mentioned above, by referencing the article classes that are implemented similar to their person counterparts as listed below.
The differences include:
SortArticleCommand
class inherits from the ArticleCommand
class which in turn inherits from the Command
class instead of the SortCommand
class.SortArticleCommandParser
instead of SortCommandParser
class.AddressBookParser
passes command flow to the ArticleBookParser
class.ArticleBook
object instead of the AddressBook
object.sort -a d/
command will invoke the Model#sortArticleBook("d/")
method instead of the Model#sortAddressBook("d/")
method.The following sequence diagram shows how a sort articles operation goes through the Logic component:
Similarly, how a sort articles operation goes through the Model
component is shown below:
Aspect: How sort articles executes:
Alternative 1 (current choice): Directly sort the internalList
field present in the UniqueArticleList
object.
ArticleBook
by the Article
field specified by the related prefix
.Alternative 2: Clone the current internalList
field
present in the UniqueArticleList
object, sort the clone, then replace the internalUnmodifiableList
field in the UniqueArticleList
object with the sorted clone.
ArticleBook
by the Article
field specified by the related prefix
, but only the current view displayed to the user which is refreshed for every opening of the application or commands that changes the view (e.g. List
, Find
commands).ArticleBook
since a clone of all Articles
has to be made.The link feature is implemented in the ArticleCard
class, so that when the user clicks on the link button, the link of the article on the article card will be opened.
The link feature is enabled by filling up link
attribute of Article
class when adding an article. This feature creates a link button on the UI of each Article
that opens up a web browser and directs the user to the webpage of where the actual article is uploaded.
Since the Articlebook
does not store the whole content of the articles, users will be able to read the articles using this feature.
Given below is an example usage scenario:
Step 1. The user launches the application for the first time. The ArticleBook
will be initialized with the initial article book state.
Step 2. The user executes add -a h/Article1 d/20-03-2024 s/draft l/https://www.article1.com
command to add a new article. The add
command calls Logic#addArticleCommand("Article1", 20-03-2024, draft "https://www.article1.com")
which adds the article to the ArticleBook
.
Step 3. Notice that the link
attribute of the Article
object is filled with the link provided by the user.
Step 4. The user clicks on the link button on the UI of the Article
object. The link button will open up a web browser and direct the user to the webpage of where the actual article is uploaded.
Aspect: How the link feature is implemented:
Alternative 1 (current choice): The link feature is implemented in the ArticleCard
class.
Alternative 2: The link feature is implemented in a separate class.
The class diagram below shows how the Article
will look and interact after implementation of the link feature.
The proposed 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.
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.
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
.
Note: 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.
Note: If the currentStatePointer
is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook 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 an undo operation goes through the Logic
component:
Note: The lifeline for UndoCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Similarly, how an undo operation goes through the Model
component is shown below:
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.
Note: If the currentStatePointer
is at index addressBookStateList.size() - 1
, pointing to the latest address book state, then there are no undone AddressBook 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.
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. Reason: It no longer makes sense to redo the add n/David …
command. This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
Aspect: How undo & redo executes:
Alternative 1 (current choice): Saves the entire address book.
Alternative 2: Individual command knows how to undo/redo by itself.
delete
, just save the person being deleted).{more aspects and alternatives to be added}
The proposed templating feature is enabled by creating a Template
superclass that Article
inherits from.
The Template
class will have the following attributes:
Name
- The name of the template.Authors
- A list of Person
objects that are the authors of the article.Sources
- A list of Person
objects that are the sources of the article.Tags
- A list of tags that are associated with the article.The Template
class will also have getter methods for accessing each of the attributes.
The Article
class will be augmented to have the applyTemplate
method, which will take a Template
object as an argument and apply the template to the article. This will involve setting the Authors
, Sources
, Tags
, and Status
attributes of the article to the corresponding attributes of the template if the values are not null
.
The Model
component will be augmented with a UniqueTemplateList
to store the templates. The Model
will also have methods to add, delete, and list templates.
Step 1. The user creates a new Template
object by entering the correct CLI input and providing the index of an article and the attributes to be used in the template.
Step 2. MakeTemplateCommandParser
parses the attribute prefixes and corresponding values from the user input.
Step 3. MakeTemplateCommand
is created with the parsed attributes.
Step 4. The newly made Template
object is added to the UniqueTemplateList
in the Model
component and throws an error if there is a duplicate.
Step 5. The user can apply the template to an article by entering the correct CLI input and providing the index of the article and the index of the template.
Step 6. ApplyTemplateCommandParser
parses the indexes from the user input.
Step 7. ApplyTemplateCommand
is created with the parsed indexes.
Step 8. The ApplyTemplateCommand
is executed, and the template is applied to the article.
The following sequence diagram shows how the MakeTemplateCommand
is executed:
{Explain here how the data archiving feature will be implemented}
Target user profile:
Value proposition: An app for freelance journalists that can streamline their workflow by organizing sources, tracking outlets interested in their stories, and managing collaborations with peers/editors. With features like tagging and grouping contacts, it facilitates efficient research, ensuring reporters can quickly reach out and report on breaking 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 | list all people | see all people I have added |
* * * | user | add a new person | |
* * * | user | delete a person | remove person entries that I no longer need |
* * * | user | edit a person | modify the details of a person anytime |
* * * | user | find a person by name | locate details of persons without having to go through the entire list |
* * * | user | lookup associated articles to a person | find all articles related to that person |
* * * | user with many persons in the address book | sort persons by name | locate a person easily |
* * * | user | clear all person entries | remove all template or unwanted person data |
* * | user | hide private contact details | minimize chance of someone else seeing them by accident |
* * * | user | list all articles | see all articles I have added |
* * * | user | add a new article | |
* * * | user | delete an article | remove article entries that I no longer need |
* * * | user | edit an article | modify the details of an article anytime |
* * * | user | find an article by headline | locate details of articles without having to go through the entire list |
* * * | user | filter articles by common attributes | locate details of articles with common attributes without having to go through the entire list |
* * * | user | remove filter for articles | display the complete list of articles again after the filter is no longer needed |
* * * | user | lookup associated people to an article | find all people related to that article |
* * * | user with many articles in the address book | sort articles by date | locate the most recent articles easily |
{More to be added}
(For all use cases below, the System is the PressPlanner
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - List all people
MSS
User requests to list all people.
PressPlanner lists out all people.
Use case ends.
Use case: UC02 - Add a person
MSS
User requests to add a person.
PressPlanner adds the person.
PressPlanner shows the added person to user.
Use case ends.
Extensions
1a. Command was invalid.
1a1. PressPlanner shows an error message.
Use case resumes at step 1.
Use case: UC03 - Delete a person
MSS
User requests to list persons.
AddressBook shows a list of persons.
User requests to delete a specific person in the list.
AddressBook deletes the person.
Use case ends.
Extensions
2a. The list is empty.
Use case ends.
3a. The given index is invalid.
3a1. AddressBook shows an error message.
Use case resumes at step 2.
Use case: UC04 - Edit a person
MSS
User requests to list all persons (UC01).
User requests to edit a specific person in the list by providing at least one change to an attribute of the article.
PressPlanner updates the article with the changes requested.
PressPlanner shows the updated article to user.
Use case ends.
Extensions
2a. The given index is invalid.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
Use case: UC05 - Find people
MSS
User requests to find people with names containing given keywords.
PressPlanner displays a filtered list of people found, each having a name containing at least one of the given keywords.
Use case ends.
Extensions
1a. No keywords are specified.
1a1. PressPlanner shows an error message.
Use case resumes at step 1.
Use case: UC06 - Lookup associated articles for a person
MSS
User requests to list all people (UC01).
User requests to lookup associated articles for a specific person in the list.
PressPlanner displays a filtered list of articles found, each having the person as a contributor or interviewee.
Use case ends.
Extensions
2a. The given index is invalid.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
3a. The list is empty as there are no articles associated with the person.
Use case ends.
Use case: UC07 - Sort people by their names
MSS
User requests to list all people (UC01).
User requests to sort people by their names.
PressPlanner sorts the people by their names in ascending alphabetical order and displays the sorted list of people.
Use case ends.
Extensions
1a. The list is empty.
Use case ends.
1b. The list is already sorted before and no edits to a person (UC04) modifies a person's name and changes that person's relative alphabetical ordering in the list or adding of a person (UC02) which results in that person not being ordered with respect to the rest of the list were performed afterwards.
Use case ends.
2a. Invalid sorting attribute is given.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
Use case: UC08 - Filter people
MSS
User requests to filter people by tag.
PressPlanner returns a filtered list of people, all of whom have the matching tag.
Use case ends.
Extensions
1a. User enters a non-alphanumeric tag.
1a1. PressPlanner shows an error message.
Use case resumes at step 1.
Use case: UC09 - List all articles
MSS
User requests to list articles.
PressPlanner lists out all articles.
Use case ends.
Use case: UC10 - Add an article
MSS
User requests to add article.
PressPlanner adds article.
PressPlanner displays success message to User.
Use case ends.
Extensions
1a. Command was invalid.
1a1. PressPlanner shows an error message.
Use case resumes at step 1.
Use case: UC11 - Delete an article
MSS
User requests to list all articles (UC09).
User requests to delete a specific article in the list.
PressPlanner deletes the article.
PressPlanner shows delete success message to user.
Use case ends.
Extensions
2a. The given index is invalid.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
Use case: UC12 - Edit an article
MSS
User requests to list all articles (UC09).
User requests to edit a specific article in the list by providing at least one change to an attribute of the article.
PressPlanner updates the article with the changes requested.
PressPlanner shows the updated article to user.
Use case ends.
Extensions
2a. The given index is invalid.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
2b. No changes to an attribute of the article is specified.
2b1. PressPlanner shows an error message.
Use case resumes at step 2.
Use case: UC13 - Find articles
MSS
User requests to find articles with headlines containing given keywords.
PressPlanner displays a filtered list of articles found, each having a headline containing at least one of the given keywords.
Use case ends.
Extensions
1a. No keywords are specified.
1a1. PressPlanner shows an error message.
Use case resumes at step 1.
Use case: UC14 - Filter articles
MSS
User requests to filter articles by status, date of publication or tag.
PressPlanner displays a filtered list of articles, all of which fits the user's criteria.
Use case ends
Extensions
1a. User gives an invalid status, tag or date.
1a1. PressPlanner shows an error message
Use case resumes at step 1.
1b. User omits any prefix.
1b1.PressPlanner shows an error message
Use case resumes at step 1.
Use case: UC15 - Lookup associated people for an article
MSS
User requests to list all articles (UC09).
User requests to lookup associated persons for a specific article in the list.
PressPlanner displays a filtered list of persons found, each featuring in the article as a contributor or interviewee.
Use case ends.
Extensions
2a. The given index is invalid.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
3a. The list is empty as there are no persons associated with the article.
Use case ends.
Use case: UC16 - Sort articles by their date
MSS
User requests to list all articles (UC09).
User requests to sort articles by their dates.
PressPlanner sorts the articles by their dates in descending chronological order and displays the sorted list of articles.
Use case ends.
Extensions
1a. The list is empty.
Use case ends.
1b. The list is already sorted before and no edits to an article (UC12) modifies an article's date and changes that article's relative chronological ordering in the list or adding of an article (UC10) which results in that article not being ordered with respect to the rest of the list were performed afterwards.
Use case ends.
2a. Invalid sorting attribute is given.
2a1. PressPlanner shows an error message.
Use case resumes at step 2.
Use case: UC17 - Open Webpage of Articles
MSS
11
or above installed.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
Download the jar file and copy into an empty folder
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
Saving window preferences
Resize the window to an optimum size. Move the window to a different location. Close the window.
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
{ more test cases … }
Sorting people after inserting a person
Prerequisites: There are 6 person entries in PressPlanner on first time launch, already in ascending alphabetical order, perform the following testcases in order.
Test case: add n/Aaron Tan p/82927320 e/a@gmail.com a/ Blk 123 Jurong Ring Road, #01-123
followed by sort n/
Expected: The person entries are sorted by their names in ascending alphabetical order. The person named "Aaron Tan"
should be the first entry. Timestamp in the status bar is updated.
Test case: add n/Annie Lee p/82927320 e/a@gmail.com a/ Blk 123 Jurong Ring Road, #01-123
followed by sort N/
Expected: The person entries are sorted by their names in ascending alphabetical order. The person named "Annie Lee"
should now be the third entry, after the person named "Alex Yeoh"
. Timestamp in the status bar is updated.
Test case: add n/Zachery Tan p/82927320 e/a@gmail.com a/ Blk 123 Jurong Ring Road, #01-123
followed by sort z/
Expected: No reordering of people is done. Error details shown in the status message. Status bar remains the same.
Other incorrect sort person commands to try: sort
, sort x
, ...
(where x is anything that is not n/
or N/
)
Expected: Similar to previous.
Adding an article
Test case: add -a h/Article1 c/Author1 i/Interviewee1 t/Science d/01-01-2019 s/PUBLISHED
Expected: Article1 is added to the list. Details of the added article shown in the status message.
Test case: add -a h/Article2 d/01-01-2021 s/PUBLISHED
Expected: Article2 is added to the list. Details of the added article shown in the status message.
Test case: add -a h/Article3 c/Author3 s/DRAFT
Expected: Error message is shown. Article3 is not added to the list.
Deleting an article while all article are being shown
Prerequisites: List all articles using the list -a
command. Multiple articles in the list.
Test case: delete -a 1
Expected: First article is deleted from the list. Details of the deleted article shown in the status message.
Test case: delete -a 0
Expected: No article is deleted. Error details shown in the status message. Status bar remains the same.
Other incorrect delete commands to try: delete -a
, delete -a x
, ...
(where x is larger than the list size)
Expected: Similar to previous.
Edit an article while all articles are being shown
Prerequisites: List all articles using the list -a
command. Multiple articles in the list.
Test case: edit -a 1 h/Article1
Expected: First article is edited to Article1. Details of the edited article shown in the status message.
Test case: edit -a 0 h/Article1
Expected: No article is edited. Error details shown in the status message.
Other incorrect edit commands to try: edit -a
, edit -a x
, ...
(where x is larger than the list size)
Expected: Similar to previous.
Finding articles by their headlines using keywords
Prerequisites: There is 1 article entry in PressPlanner on first time launch, perform the following testcases in order after adding the following articles provided as add article commands.
add -a h/one d/01-01-2001 s/draft
add -a h/one two d/01-01-2001 s/draft
add -a h/one two three d/01-01-2001 s/draft
Test case: find -a one
Expected: The only article with the headline one
is shown in the list of articles. The status message shows the number of articles found. Timestamp in the status bar is updated.
Test case: find -a TWO
Expected: Two articles are shown with headlines one two
and one two three
. The status message shows the number of articles found. Timestamp in the status bar is updated.
Test case: find -a thre
Expected: No articles are found. The status message shows the number of articles found is 0
. Timestamp in the status bar is updated.
Prerequisites: Populate PressPlanner with sufficient articles. You may use the following add commands:
Use these commands to populate PressPlanner.
add -a h/Test-1 c/Author1 i/Interviewee1 t/Science d/01-01-2019 s/PUBLISHED
add -a h/Test-2 c/Author2 i/Interviewee2 d/01-01-2021 s/PUBLISHED
add -a h/Test-3 c/Author3 d/01-01-2019 s/DRAFT
Test case: filter -a s/ st/ en/ t/
Expected:There will be no change in displayed articles.
Test case: filter -a s/DRAFT st/ en/ t/
Expected: Only articles with draft status will be displayed.
Test case: filter -a s/ st/01-01-2020 en/12-12-2022 t/
Expected: Only articles published between 01-01-2020 and 12-12-2022 will be displayed.
Test case: filter -a s/ st/ en/ t/Science
Expected: Only articles with the tag Science
will be displayed.
Test case: filter -a s/ st/
Expected: An error informing the user that the command format is incorrect will be shown.
Test case: filter -a s/ st/ en/ t/non-alphanumeric
Expected: An error informing the user that tags only consisting of alphanumeric characters will be shown.
Test case: filter -a s/ st/01-01-2020 en/01-01-2001 t/
Expected: An error informing the user that start dates must come before end dates will be shown.
Lookup person/article after adding a person/article
Prerequisites: Assume non-empty list of persons and articles. Change index numbers as needed.
Test case: add n/Alice1 p/12345678 e/alice@email.com a/Blk 424 #11-0536 Yishun Ring Road
lookup 1
Expected: Alice1 is added to the list. An empty list of articles associated with Alice1 is shown.
Testcase: add -a h/Article1 c/Alice1 d/11-09-2021 s/DRAFT
lookup -a 1
Expected: Article1 is added to the list. Alice1 is shown as a list of persons associated with Article1.
Lookup person: lookup 1
Expected: Article1 is shown as a list of articles associated with Alice1.
Test case: lookup 0
Expected: Error message is shown.
Test case: lookup -a 0
Expected: Error message is shown.
Delete the person and article added in the prerequisites. Then repeat the above testcases by altering the orders such that the article is added first and then person. The commands should differ accordingly.
Lookup after editing person and article
Test case: edit 1 n/Alice2
Expected: Alice is edited to Alice2. This is reflected in the article Article0 contributor tag as well.
Test case: edit -a 1 h/Article1
Expected: Article0 is edited to Article1.
Test case: lookup 1
Expected: Article1 is shown as a list of articles associated with Alice2.
Test case: lookup -a 1
Expected: Alice2 is shown as a list of persons associated with Article1.
Sorting articles after inserting an article with a date of "0X-01-2100"
replacing "X"
with a number starting from 1 up to 9
Prerequisites: There is 1 article entry in PressPlanner on first time launch, perform the following testcases in order.
Test case: add h/Article1 d/01-01-2100 s/draft
followed by sort -a d/
Expected: The article entries are sorted by their dates in descending chronological order. The article with the headline Article1
and date "01-01-2100"
should be the first entry. Timestamp in the status bar is updated.
Test case: add h/Article2 d/02-01-2100 s/draft
followed by sort -a D/
Expected: The article entries are sorted by their dates in descending chronological order. The article the headline Article2
and date "02-01-2100"
should be the first entry, before Article1
with the date "01-01-2100"
. Timestamp in the status bar is updated.
Test case: add h/Article3 d/03-01-2100 s/draft
followed by sort -a z/
Expected: No reordering of articles is done. Error details shown in the status message. Status bar remains the same.
Other incorrect sort article commands to try: sort -a
, sort -a x
, ...
(where x is anything that is not d/
or D/
)
Expected: Similar to previous.
Opening a link to an article
Create articles using add -a h/Article1 d/20-03-2024 s/draft l/https://www.google.com
, add -a h/Article2 d/20-03-2024 s/draft l/https://www.facebook.com/
and add -a h/Article3 d/20-03-2024 s/draft l/
commands.
Test case: add -a h/Article1 d/20-03-2024 s/draft l/https://www.google.com
, followed by click on the link button of the first article.
Expected: The link to google is opened in the default web browser.
Test case: add -a h/Article2 d/20-03-2024 s/draft l/https://www.facebook.com/
, followed by click on the link button of the last article.
Expected: The link to facebook is opened in the default web browser.
Test case: add -a h/Article3 d/20-03-2024 s/draft l/
, followed by click on the link button of an article that does not have a link.
Expected: Nothing happens.
{ more test cases … }
Dealing with missing/corrupted data files
Make URL failure more explicit: Currently when a URL cannot be opened the app shows that by not opening anything. This can be improved by showing an error message.
The filter command can work for individual prefixes: Currently the filter command only works for all prefixes. It can be improved by allowing the user to filter by individual prefixes.
Automatically sort persons by their names in ascending alphabetical ordering: Currently whenever the user makes an edit to a person's name or adds new person entries which may result in a violation of the previous ordering, the user would have to execute the sort n/
command to re-sort the person entries. It can be improved by automatically sorting people whenever new entries, or certain edits to them are made to reduce such inconveniences to the user.
Automatically sort articles by their publication dates in descending order: Currently whenever the user makes an edit to an article's publication date or adds new article entries which may result in a violation of the previous ordering, the user would have to execute the sort -a d/
command to re-sort the articles. It can be improved by automatically sorting articles whenever new entries, or certain edits to them are made to reduce such inconveniences to the user.
Provide alternative methods to create associations between persons and articles: Currently the user can only create associations between persons and articles when adding/editing the persons or articles. It might not always be desirable to create associations when adding/editing persons or articles. This can be improved by providing an alternative method to create associations between persons and articles by using IDs unique to each person and article. Instead of using names to create associations, the user can use the IDs to create associations between persons and articles.
Allow the user to filter people: Currently the user can only filter articles. It can be improved by allowing the user to filter people as well.
Allow editing or deleting at any index for duplicate articles: Currently, the user can only edit or delete the first article when there are multiple draft articles with the identical attributes. It can be improved by allowing the user to edit or delete any article with the same headline.
Enhance prefix validation: Currently, the user can use duplicate prefixes for the same attribute when adding or editing persons or articles, or even add incorrect prefixes in their commands. It can be improved by enhancing the prefix validation to prevent the user from using duplicate prefixes for the same attribute and to guide the user to use the correct prefixes in their commands.
Enable greater ease in adding/editing/deleting cumulative attributes: Currently these tags for both person and article, and contributor, interviewee and outlets for articles are not cumulative. If user wants to add one more, they will have to add the existing ones at the same time using edit. They cannot also delete any single one, but have to clear all existing ones and add the ones that they want to remain again using edit. The enhancement can let there be a index for those attributes enabling the user to add/edit/delete them with greater ease.
Allow non-alphanumeric inputs for tags: Currently, the user can only use alphanumeric characters for tags. It can be improved by allowing the user to use non-alphanumeric characters for tags.