Developer Guide
- Table of Contents
Acknowledgements
Resource | Used in | To |
---|---|---|
https://stackoverflow.com/a/14018549/13742805 | StringUtil.java | Help with parsing lower-case strings |
https://stackoverflow.com/a/4217164/13742805 | CommandParser.java | Force subclasses to have the same initial method calls |
https://stackoverflow.com/a/30974991/13742805 | LambdaUtil.java | A lambda function that throws a checked Exception |
https://stackoverflow.com/questions/12087419/adding-days-to-a-date-in-java | LoanCommand.java | Add certain number of days to the current day |
https://stackoverflow.com/questions/62054264/check-invalid-date-by-localdate | LoanCommandParser.java | Parse dates properly |
PrettyTimeParser library | LoanCommandParser.java | Allow for higher amounts of flexibility of date formats |
A list of the sources of all reused/adapted ideas, code, documentation, and third-party libraries – with links to the original source as well
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
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
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 methods where necessary.
Commons
represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete user 1
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, BookListPanel
, 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,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
andBook
objects residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses thePrimaryParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddUserCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add a person). - The result of the command execution is encapsulated as a
CommandResult
object which is returned fromLogic
.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
PrimaryParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddUserCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddUserCommand
) which thePrimaryParser
returns back as aCommand
object. - Commands can be decomposed into subcommands. For example, to parse
delete user 1
,PrimaryParser
callsDeleteCommandParser
.DeleteCommandParser
then parsesuser 1
and returns aDeleteUserCommand
. - All
XYZCommandParser
classes (e.g.,AddUserommandParser
,DeleteUserCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores BookFace data i.e., all
Person
objects and allBook
objects (which are contained in aUniquePersonList
object and aBookList
object respectively). - stores the currently ‘selected’
Person
andBook
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>
orObservableList<Book>
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. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - has a bidirectional association between a
Book
and aPerson
, where aBook
can only have 0 or 1 loaneePerson
, but a Person can loan 0 or moreBooks
- does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
Tag
list in the BookFace
, which Person
references. This allows BookFace
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.Storage component
API : Storage.java
The Storage
component,
- can save both BookFace data and user preference data in json format, and read them back into corresponding objects.
- inherits from both
BookFaceStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the bookface.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Command Parsing
The Logic section briefly explains how the user’s input is broken down, but the process is explained more thoroughly here.
This process works by handling the parsing of commands and arguments separately. The first word in the user input is taken to be the command, and the rest of the input to be arguments. A Command
object is then generated.
One feature is that a command can recursively contain another command as a subcommand. We chose this approach as the add
, edit
, find
, list
, and delete
commands can apply to either users or books. These commands need additional subcommands and additional parsers to handle the different execution logic and command-line flags for users and books. Thus, a recursive structure allows for easy extensibility and to share code via parent classes.
Compare the command loan 1 1
with delete user 1
. loan 1 1
has two integer arguments, which cannot be broken down further. However, the arguments user 1
for delete
can be treated as a single self-complete subcommand on their own.
Design consideration:
This approach was chosen to reduce code duplication and to manage the complexity of PrimaryParser
. For example, DeleteUserCommand
(delete user
) and DeleteBookCommand
(delete book
) can share similar code through a common parent DeleteCommand
(delete
). Such commands which can contain subcommands like add
or delete
also inherit from the abstract CommandParser
, which has a shared parse()
method. This proved to be useful, as the list
command in particular has many subcommands.
These commands (and subcommands) are represented as enums to associate each possible command from the user with a Parser
specific to that command. Enums were chosen, as they use less memory (as enums are final
subclasses of java.lang.Enum
) than HashMap
for key-value storage, and are easy to modify. Furthermore, they help to ensure type-checking during compile-time, preventing bugs. They also have a semantic value; they represent to both us developers and to readers of the code the current allowed constants.
Add feature
Adding a book/user
The add
command is an important command that is commonly used in BookFace. It allows the user to add a new book or a user to the system.
Design consideration:
Since add
is used for the operations of both adding a book and adding a user, the enum AddSubCommand
is created within Parser
of the Logic
component to handle differentiating between adding a book and adding a user.
The activity diagram for adding a user or a book is as follows:
Adding a book with add book
add book
adds a new book to the model. Specifically, ModelManager
maintains a list of books and contains the method addbook()
that is invoked by AddBookCommand
to perform this adding operation.
The updating of the model is represented in the following sequence diagram:
Adding a user with add user
add user
follows the same logic and thus closely follows the sequence diagram of add book
, but uses AddUserArgumentsParser
and AddUserCommand
in place of the add book
variants.
Delete feature
Deleting a book/user
The delete
allows the user to delete a book or a user from the system.
Deleting a book with delete book
delete book
deletes a book from the model. Specifically, ModelManager
maintains a list of books and contains the method deleteBook()
that is invoked by DeleteBookCommand
to perform this deletion.
The sequence diagram below illustrates the interactions within the Logic
component for the execute("delete user 1")
API call.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Deleting a user with delete user
delete book
deletes a user from the model. Specifically, ModelManager
maintains a list of users and contains the method deletePerson()
that is invoked by DeleteUserCommand
to perform this deletion.
The sequence diagram is rather similar to that of delete book
, so in the interest of brevity, it has been omitted.
Activity Diagram
The following activity diagram summarizes what happens when the librarian executes a delete
command:
List feature
Implementation
The list mechanism is facilitated by LogicManager
. During its process of parsing the command by PrimaryParser
,
a new ListCommandParser
will be created to internally parse the argument of the command
through ListSubcommand
.
Currently, there are 5 possible Command
classes that can be returned from ListSubcommand
, and
they are created in respect to the subcommand that is parsed:
-
ListBooksCommand
forBook
upon the commandlist books
-
ListUsersCommand
forPerson
upon the commandlist users
-
ListAllCommand
for bothBook
andPerson
upon the commandlist all
-
ListLoansCommand
for bothBook
andPerson
upon the commandlist loans
-
ListOverdueCommand
for bothBook
andPerson
upon the commandlist overdue
Given below is an example usage scenario and how the list mechanism behaves at each step.
Step 1. The librarian has executed a FindUserCommand
, which filtered certain user records to display in BookFace. The librarian
then wants to return the display state to show all user records by entering the list users
command, which attempts to list all users
in BookFace.
Step 2. LogicManager
executes the command.
Step 3. PrimaryParser
then creates a new ListCommandParser
object, which internally creates a ListSubcommand
object
to parse the second part of the command (which is users
).
Step 4. ListSubcommand
parses the subcommand as an argument and creates a new ListUsersCommand
.
Step 5. LogicManager
executes ListUsersCommand
, which then calls Model#updateFilteredPersonList()
with a predicate to show all users.
The following sequence diagram shows how the list operation works (following the steps mentioned above):
ListUsersCommand
and ListUsersCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches
the end of diagram.The following activity diagram summarizes what happens when a user executes a list command:
The following activity diagram summarizes what happens during the Parse Subcommand action:
Find feature
Implementation
The find feature is facilitated by FindUserCommand
and FindUserArgumentsParser
for finding users, and FindBookCommand
and FindBookArgumentsParser
for finding books.
It implements the following operations:
-
updateFilteredPersonList(predicate)
— Display users with names matching predicate. -
updatedFilteredBookList(predicate)
— Display books with title/authors matching predicate.
Given below is an example usage scenario and how the find users mechanism behaves at each step.
Step 1. Assume that BookFace contains some users that are added through several AddUserCommand
executed by the user. The user executes find user alex
command to find any user with name ‘alex’ within the address book.
Step 2. LogicManager
executes the find user alex
command.
Step 3. PrimaryParser then creates a new FindUserArgumentsParser
after parsing find user alex
.
Step 4. FindUserArgumentsParser
parses "alex"
and creates a new FindUserCommand
.
Step 5. LogicManager
executes the FindUserCommand
.
Step 6. FindUserCommand
calls Model#updateFilteredPersonList("alex")
and find all users with names matching “alex”.
Step 7. FindUserCommand
creates new CommandResult
and returns the result to LogicManager
.
The following sequence diagram shows a visualization of the above find process:
The following activity diagram summarizes what happens when the librarian executes a find user command:
The process for finding books goes through a similar process as the process for finding users. Given below is an example usage scenario and how the find books mechanism behaves at each step.
Step 1. Assume that BookFace contains some books that are added through several AddBookCommand
executed by the user. The user executes find book moby
command to find any book with title or author with ‘moby’ within the book list.
Step 2. LogicManager
executes the find book moby
command.
Step 3. PrimaryParser then creates a new FindBookArgumentsParser
after parsing find book moby
.
Step 4. FindBookArgumentsParser
parses "moby"
and creates a new FindBookCommand
.
Step 5. LogicManager
executes the FindBookCommand
.
Step 6. FindBookCommand
calls Model#updateFilteredBookList("moby")
and find all books with titles or authors matching “moby”.
Step 7. FindBookCommand
creates new CommandResult
and returns the result to LogicManager
.
The following sequence diagram shows a visualization of the above find process:
The following activity diagram summarizes what happens when the librarian executes a find command:
Design considerations
The find command is designed such that the matches within BookList
and UniquePersonList
are easily found and listed onto the UI of BookFace.
Loan feature
Implementation
The loan mechanism is facilitated by LoanCommandParser
and LoanCommand
. It implements the following operation:
-
BookFace#loan()
— Loans to the specified user a specified book.
This operation is exposed in the Model
interface as Model#loan()
.
Given below is an example usage scenario and how the loan mechanism behaves at each step.
Step 1. Assume that FaceBook contains some users and some books that are added through several AddUserCommand
and AddBookCommand
executed by the librarian. The librarian then enters loan 2 2
command to loan to the 2nd user in the user list the 2nd book
in the book list.
Step 2. LogicManager
executes the librarian’s loan 2 2
command.
Step 3. PrimaryParser
then creates a new LoanCommandParser
after parsing loan 2 2
.
Step 4. LoanCommandParser
parses 2 2
and creates a new LoanCommand
.
Step 5. LogicManager
executes LoanCommand
.
Step 6. LoanCommand
calls Model#Loan()
and loans the 2nd user in the user list the 2nd book
in the book list.
Step 7. LoanCommand
creates a new CommandResult
and returns the result to LogicManager
.
The following sequence diagram shows how the loan operation works:
LoanCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.The following activity diagram summarizes what happens when the librarian executes a loan command:
Design considerations:
The loan command is designed such that the BookList
and UniquePersonList
are updated sequentially rather than concurrently, such that there are
separate loan commands in both BookList
and UniquePersonList
that are called
by BookFace
that updates the BookList
and UniquePersonList
respectively.
We wanted to avoid the design such that both Book
and Person
were associated with each other
directly (ie. can access details of each other) to reduce coupling. Currently, Person
contains a Set
of loaned books
while Book
contains a loanee
and a returnDate
and the loan command updates all the attributes of Person
and Book
separately.
One issue is that the UniquePersonList
and BookList
do not refresh their UI
automatically, and we resorted to getting the index of each list to set their
internal ObservableLists
to ‘refresh’ their UI.
We have chosen to use an external PrettyTimeParser
library here to allow for higher degrees of flexibility for input. One downside however is that it uses Natural Language Processing, and it may cause unintended parsing behaviours that is difficult to resolve since Natural Language Processing is beyond the scope of this module. In this case, invalid dates such as 2075-99-99
are accepted as valid dates by the library, and we have decided to check only for the two most common date formats, dd/MM/yyyy
and yyyy-MM-dd
.
Return feature
Implementation
Similar to the loan mechanism, the return mechanism is facilitated by ReturnCommandParser
and ReturnCommand
. It implements the following operation:
-
BookFace#returnLoanedBook()
— returns a loaned book.
This operation is exposed in the Model
interface as Model#returnLoanedBook()
.
Given below is an example usage scenario and how the return mechanism behaves at each step.
Step 1. Assume that FaceBook contains some users and some books that are added through several AddUserCommand
and AddBookCommand
executed by the librarian. The librarian then enters loan 2 2
command to loan to the 2nd user in the user list the 2nd book
in the book list. The librarian now wants to return the 2nd book that was previously loaned out.
The librarian enters return 2
command.
Step 2. LogicManager
executes the librarian’s return 2
command.
Step 3. PrimaryParser
then creates a new ReturnCommandParser
after parsing return 2
.
Step 4. ReturnCommandParser
parses 2
and creates a new ReturnCommand
.
Step 5. LogicManager
executes ReturnCommand
.
Step 6. ReturnCommand
calls Model#returnLoanedBook()
and returns the 2nd book in the book list.
Step 7. ReturnCommand
creates a new CommandResult
and returns the result to LogicManager
.
The following sequence diagram shows how the return operation works:
ReturnCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.The following activity diagram summarizes what happens when a user executes a return command:
Design considerations:
Similar to Design considerations for the loan command.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- librarians managing a small library
- has a need to manage a significant number of patrons
- prefer desktop apps over other types
- can type fast and is reasonably comfortable using CLI apps
- has no access to card-based systems to manage loans
Value proposition: Our app replaces a paper-based system or manual tracking of books, providing greater speed/efficiency in identifying where a book is, or when it is due. It also adds a member-tracking system to handle an increasing number of library members.
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 book records | |
* * * |
user | delete book records | |
* * * |
user | view the book records | |
* * * |
user | add new patrons to my library | |
* * * |
user | delete patrons from my library | |
* * * |
user | add loans | mark books as unavailable |
* * * |
user | mark loans as returned | mark books as available |
* * * |
user | view the overdue books | |
* * * |
person who likes to talk to others | type my commands to a CLI | so I can work while interacting with my patrons |
{More to be added as we progress into future versions}
Use cases
(For all use cases below, the System is the BookFace
and the Actor is the User
, unless specified otherwise)
Use case: UC01 - Delete a book record
MSS
- User requests to delete a book record
- BookFace shows a list of books
- User requests to delete a specific book record in the list
- BookFace deletes the book record from the list
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. BookFace shows an error message.
Use case resumes at step 2.
-
Use case: UC02 - List book records
MSS:
- User requests to list all book records
- BookFace shows a list of books
Use case ends.
Extensions:
-
1a. The list is empty.
Use case ends. -
1b. The list of books cannot be retrieved.
- 1b1. BookFace shows an error message.
Use case ends.
- 1b1. BookFace shows an error message.
Use case: UC03 - Add a book
MSS
- The librarian has a new book to add to BookFace.
- The librarian uses the
add book
command with the required fields. - BookFace checks for the correctness of the command.
-
BookFace adds the entry to the list of books.
Use case ends.
Extensions
- 3a. There is a book with the exact same details.
- 3a1. BookFace notifies the librarian of the duplicate.
- 3a2. BookFace creates this book as a separate object.
-
3a3. BookFace saves this book to the list.
Use case ends.
- 3b. The librarian did not specify all required fields.
-
3b1. BookFace notifies the librarian of the correct usage of
add book
.Use case ends.
-
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- Someone without coding background should find BookFace easy to use.
- The system should respond in 1 second.
- The system should be backward compatible with data produced by earlier versions of the system.
- BookFace is not required to handle the displaying detailed reports about users (their loan history, statistics on their membership such as frequency of loans) yet.
- BookFace should work even without an active internet connection.
- The data stored in a BookFace instance should be recoverable even if the instance crashes.
- BookFace will need at least 50 MB of disk space to work.
- BookFace does not plan to improve its accessibility for blind, deaf, or otherwise disabled users according to the Web Content Accessibility Guidelines (WCAG 2.1).
- BookFace should be extensible and sufficiently decoupled such that a separate GUI can be attached to the existing backend services and database.
Glossary
Term | Explanation |
---|---|
Mainstream OS | Windows, Linux, OS-X |
CLI | Command-Line Interface |
GUI | Graphical User Interface |
Loan | A book that has been borrowed from the library |
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Open command prompt/terminal within the folder and enter
java -jar BookFace.jar
Expected: Shows the GUI with a set of sample user records. 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 opening command prompt/terminal within the folder of where the JAR file is located and enter
java -jar BookFace.jar
Expected: The most recent window size and location is retained.
-
Adding a book
- Adding a book while all books are being shown
-
Prerequisites: List all books using the
list books
orlist all
command. -
Test case:
add book t/Moby Dick a/Herman Melville
Expected: Successful addition of the book to the bottom of the book list. -
Test case:
add book t/Moby Dick
Expected: No book is added. Error details shown in the status message. -
Other incorrect add book commands to try:
add book
,add book t/Herman Melville
,...
(where one or more compulsory parameter prefixes are missing)
Expected: Similar to previous
-
Adding a user
-
Adding a user while all users are being shown
-
Prerequisites: List all users using the
list users
orlist all
command. -
Test case:
add user n/James Bond p/96629813 e/jamesbond@gmail.com
Expected: Successful addition of the user to the bottom of the person list. -
Test case:
add user n/James Bond p/96629813
Expected: No user is added. Error details shown in the status message. -
Other incorrect add user commands to try:
add user
,add user n/James Bond
,...
(where one or more compulsory parameter prefixes are missing)
Expected: Similar to previous.
-
Deleting a book
- Deleting a book
-
Prerequisites: List all books using the
list books
orlist all
command, and there is at least one or more books in the book list. -
Test case:
delete book 1
Expected: First book is deleted from the book list. Details of the deleted book are shown in the status message. -
Test case:
delete book 0
Expected: No book is deleted. Error details shown in the status message. -
Other incorrect delete book commands to try:
delete book
,delete book x
,...
(where x is larger than the book list size)
Expected: Similar to previous
-
- Deleting a book that is loaned out
-
Prerequisites: At least one or more user and book in BookFace, and book is loaned out using the
loan 1 1
command. -
Test case:
delete book 1
Expected: No book is deleted. Error message shown in the status message.
-
Deleting a user
-
Deleting a user while all users are being shown
-
Prerequisites: List all users using the
list users
orlist all
command, and there is at least one or more users in the person list. -
Test case:
delete user 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. -
Test case:
delete user 0
Expected: No person is deleted. Error details shown in the status message. -
Other incorrect delete user commands to try:
delete user
,delete user x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Loaning a book
-
Loaning a book that is already loaned
-
Prerequisites: A book at index 1 that is loaned to a user using the
loan 1 1
command, and other books in BookFace that are not loaned out. -
Test case:
loan 2 1
Expected: Book at the first index remains loaned to the first loaner that has not returned the book. Error details shown in the status message. -
Test case:
loan 2 2
Expected: Book at index 2 loaned out to user at index 2. Details of the loan are shown in the status message.
-
Returning a book
-
Return a book that is not loaned
-
Prerequisites: A book at index 2 that is not on loan, and a book at index 1 that is loaned out using the
loan 1 1
command. -
Test case:
return 2
Expected: Book is not returned as it is not on loan. Error details shown in the status message. -
Test case:
return 1
Expected: Book is no longer on loan. Return details shown in the status message.
-
Finding a book
-
Finding a book while all books are being shown
-
Prerequisites: List all books using the
list books
orlist all
command, and there is at least one or more books in BookFace. -
Test case:
find book Moby
Expected: All books with authors and titles containing “Moby” (case insensitive) is shown. Details of the number of matching books found shown in the status message. -
Test case:
find book
Expected: No change in books displayed. Error details shown in the status message.
-
Finding a user
-
Finding a user while all users are being shown
-
Prerequisites: List all users using the
list users
orlist all
command, and there is at least one or more users in BookFace. -
Test case:
find user James
Expected: All users with names containing “James” (case insensitive) is shown. Details of the number of matching users found shown in the status message. -
Test case:
find user
Expected: No change in users displayed. Error details shown in the status message.
-
Editing a book
-
Editing a book while all books are being shown
-
Prerequisites: List all books using the
list books
orlist all
command, and there is at least one or more books in BookFace. -
Test case:
edit book 1 a/Thomas Jefferson
Expected: Book at index 1 has its author set to “Thomas Jefferson”. Edited book details shown in the status message. -
Test case:
edit book 1
Expected: No change in details for book at index 1. Error details shown in the status message.
-
Editing a user
-
Editing a user while all users are being shown
-
Prerequisites: List all users using the
list users
orlist all
command, and there is at least one or more users in BookFace. -
Test case:
edit user 1 n/Leonard Chong
Expected: User at index 1 has their name set to “Leonard Chong”. Edited user details shown in the status message. -
Test case:
edit user 1
Expected: No change in details for user at index 1. Error details shown in the status message.
-
Listing all books
-
Listing all books from a narrowed down list of books
-
Prerequisites: A narrowed down list of books is shown after using the
find book KEYWORD
,list loans
orlist overdue
commands. -
Test case:
list books
Expected: All books are shown. Message shown in the status message.
-
Listing all users
-
Listing all users from a narrowed down list of users
-
Prerequisites: A narrowed down list of users is shown after using the
find user KEYWORD
,list loans
orlist overdue
commands. -
Test case:
list users
Expected: All users are shown. Success message shown in the status message.
-
Listing all books and user
-
Listing all books and users from a narrowed down list of users and books
-
Prerequisites: Books and users shown are a narrowed down list of books and users after using the
find book KEYWORD
,find user KEYWORD
,list loans
orlist overdue
commands. -
Test case:
list all
Expected: All users and books shown. Success message shown in the status message.
-
Listing all loans
-
Listing all loans when all users and books are being shown
-
Prerequisites: List all users and books using the
list all
command. -
Test case:
list loans
Expected: All books that are loaned out and users who have ongoing loans are shown.
-
Listing all overdue loans
-
Listing all overdue loans when all loans are being shown
-
Prerequisites: List all loans using the
list loans
command. -
Test case:
list overdue
Expected: All books that are overdue and users who owe overdue books are shown.
-
Saving data
-
Dealing with corrupted data files
- Prerequisites: have the data file
bookface.json
(if the app has not been launched at least once, this file may be missing) - Test case: change one of the JSON key fields to be incorrect, such as by replacing
name
withnme
.
Expected: Upon launching the application, the application will log an error message and will load without any data at all. - Test case: an unloaned book should not have a non-empty
returnDate
field. Expected: Upon launching the application, the application will log an error message and will load without any data at all.
- Prerequisites: have the data file
-
Dealing with missing data files
- Prerequisite: the data file
bookface.json
is missing.
Expected: Upon launching the application, the application will be loaded with sample data.
- Prerequisite: the data file
Appendix: Effort
-
Difficulty level
Creating theBook
entity alone was somewhat viable for us to do. However, it became quite difficult when multiple variables come into play withBook
. For instance, integratingLoan
intoBook
andPerson
meant that we had to ensure any data that is to be created or modified are performed correctly and synchronized with one another (E.g. APerson
’s loaned book status should reflect allBook
records that were loaned specifically to thatPerson
). Parsing the various commands was the most difficult part of the project since the main commands likeAdd
andEdit
now involved more than 1 entity (unlike in AddressBook), and thus made the product more prone to errors and unexpected bugs from a multitude of possible inputs. -
Challenges faced
- Changing of features due to multiple implementations;
Some features are related to one another (E.g.Book
andLoan
), and that made implementations difficult to synchronise, especially when multiple people are modifying them to suit their specific tasks. For instance, ifBook
were to have a quantity variable,Loan
needs to be modified such that it can keep track of theBook
quantity and the record is synchronised correctly withPerson
. However, ifLoan
andBook
are in the middle of an enhancement, it becomes extremely tough to ensure our implementations work with these enhancements.
- Changing of features due to multiple implementations;