This project is based on the AddressBook-Level3 project created by the SE-EDU initiative.
Libraries used in this project:
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.Database
parses data from within the App on startup. This data is used to support user input validation according to the business logic.
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 CS2030S
.
Each of the four main components (also shown in the diagram above), as well as the Database
component,
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
, ModulePlanPanel
, 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 ModulePlanSemester
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 CS2030S")
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 reaches the end of diagram.
How the Logic
component works:
Logic
is called upon to execute a command, it is passed to a ModulePlanParser
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).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:
ModulePlanParser
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 ModulePlanParser
returns back as a Command
object.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,
Module
objects (which are contained in UniqueModuleList
objects).UserPref
object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref
object.ModuleData
object that represents the information on all modules. This is exposed to the outside as a ReadOnlyModuleData
object.Model
represents data entities of the domain, they should make sense on their own without depending on other components)Note: The module plan data is split into different semesters (e.g. Year 1 S1, Year 1 S2, Year 2 S1, etc). Instead of one UniqueModuleList
storing all of the user's modules across multiple semesters, each semester's modules are stored in their own UniqueModuleList
object. Nevertheless, modules are required to be unique across semesters, meaning that the same module will be prevented from being added to multiple semesters. The implementation of this check can be found in ModulePlanSemesterList
.
API : Storage.java
The Storage
component,
AddressBookStorage
and UserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed).Model
component (because the Storage
component's job is to save/retrieve modifiable objects that belong to the Model
)API : Database.java
The Database
component,
ModuleData
object.Model
component (because the Database
component's job is to retrieve read-only objects that belong to the Model
)Note: The module data is stored within the resource folder. In the case where the data cannot be read successfully, a RuntimeException
is deliberately triggered to forcefully halt the application's execution. This is necessary because all features are reliant on the module data.
Classes used by multiple components are in the seedu.address.commons
package.
This section describes some noteworthy details on how certain features and commands are implemented.
ModulePlan is a collection of classes that wraps all the information regarding the user's timetable and houses all the Module
in the user's study plan. It has a facade class ModulePlan
that handles all calls into the ModulePlan Component. The internal lists can only be modified through calls to the facade class as it is only exposed as a unmodifiableObservableList
.
The ModulePlan implementation consists of 4 levels of classes in the following order:
ModulePlan
ModulePlanSemesterList
ModulePlanSemester
UniqueModuleList
The class diagram below shows the OOP structure of the ModulePlan component:
ModulePlan:
ModulePlan
is the facade class of the ModulePlan component. It contains exactly 1 ModulePlanSemesterList
that is initialised whenever a new instance of ModulePlan
is created. There isn't any logic implemented in this class, it just passes down information to the lower level classes and relays back the response to the caller.
ModulePlanSemesterList:
ModulePlanSemesterList
is where the main logic regarding modules that belong in different semesters is implemented. ModulePlanSemesterList
contains a internalList
of ModulePlanSemester
and when a instance of ModulePlanSemesterList
is created, its constructor populates the internalList
with copies of a list of default ModulePlanSemester
called DEFAULT_SEMESTER
. DEFAULT_SEMESTER
is a class level immutable list of ModulePlanSemester
of both Semester 1 and 2 from Year 1 to 4.
ModulePlanSemesterList
implements the check for duplicate modules with the function containsModule
.findSemester
is used to figure out which ModulePlanSemester
to pass the module to while also acting as a check for whether the module in question is in the ModulePlan.getCAP
and modularCredit
is also where the CAP and MC respectively are collated across all the semesters.ModulePlanSemesterList
also contains the logic for adding ModulePlanSemester
outside of the default ones and removing them when they are empty. These are implemented in the addModule
and removeModule
functions respectively with the assistance of some helper functions like checkIfSemesterEmpty
and inDefaultSemesters
.ModulePlanSemester:
ModulePlanSemester
is modeled after a semester in the timetable. It is identified by the fields Year
and Semester
and contains 1 UniqueModuleList
. Like ModulePlan
, there is not much logic implemented here and it mainly passes the input down and relays the result back up the hierarchy.
However, the logic for checking and grouping all Year 0 modules is implemented here, in the checkModuleBelongToSemester
and checkIfSameSemester
functions.
UniqueModuleList:
UniqueModuleList
is where the Module
objects are housed, in the ObservableList
called internalList
. It is also where logic for modules in the same semester are implemented.
contains
and modulesAreUnique
ensures that there is no duplicates within this semester.modularCredits
, findGradePointsWithUnits
and findMcsForCap
calculates the CAP/MC for this particular semester only.
The following diagrams shows the flow for the main uses of ModulePlan, adding and removing modules.
Add Module:
Delete Module:
Changes in the ModulePlan are displayed to the user through an observer pattern where the listview
in the UI class ModulePlanPane
listens to the ObservableList
in ModulePlanSemesterList
and the listview
in ModulePlanCard
listens to the the ObservableList
in UniqueModuleList
.
The individual modules are then displayed in ModuleCard
.
However, as changes in the UniqueModuleList
will not propagate to the ObservableList
in ModulePlanSemesterList
, there is a need for the function refreshList
to update the ObservableList
in ModulePlanSemesterList
whenever changes in the UniqueModuleList
occurs.
Aspect: Data Structure to Store Module
Alternative 1 is ultimately chosen as it helps abstracts out the logic for different semester to the Model component where it is meant to be and having a OOP structure makes it easier to visualise and thus test/maintain code. Which is important as this is a team-based project.
Modcraft stores two types of information on the hard drive, ModulePlan and UserPrefs(User Preferences). ModulePlan stores the user's last saved module plan when using Modcraft allowing the user to access their module plan across sessions. UserPrefs contains the last known user interface settings when using Modcraft allowing the user to return to their preferred interface across sessions.
ModulePlan is stored as moduleplan.json
and UserPrefs is stored as preferences.json
. Both files will be created if
they do not already exist in the same folder in which the Modcraft jar file is stored. While users are free to access
and modify the files as they wish it is recommended that they make a backup before any modifications. If Modcraft
cannot access a file, it will be deleted and replaced with a new empty file.
moduleplan.json
or preferences.json
file detected in the
same folder as Modcraft or they are corrupted, Modcraft will create them and populate them with the default moduleplan
and preferences respectively.moduleplan.json
and preferences.json
files with appropriate data, Modcraft will read the
module plan from moduleplan.json
and user preferences from preferences.json
, loading the application with the
information obtained from the files.moduleplan.json
.preferences.json
.MainApp
calls MainApp#initPrefs
to attempt to parse the preferences.json
file.MainApp#initPrefs
calls Storage#readUserPrefs
to obtain the user preferences as a UserPrefs
object.
2a. If DataLoadingException
is thrown, a new preferences.json
file will be created with default preferences.JsonUserPrefsStorage
deserializes the JSON file by calling JsonUtil#readJsonFile
into a UserPrefs
object.MainApp
creates a StorageManager
object with the file paths of preferences.json
and moduleplan.json
.MainApp#initModelManager
is then called which calls Storage#readModulePlan
attempting to parse the
moduleplan.json
file and create a modulePlan
object.
4a. If DataLoadingException
is thrown, a new moduleplan.json
file will be created with the default module plan.JsonModulePlanStorage
deserializes the JSON file into a JsonSerializableModulePlan
object by calling
JsonUtil#readJsonFile
.
5a. The JsonSerializableModulePlan
object represents a list of JsonAdaptedModule
objects, created during
deserialization.JsonModulePlanStorage
then calls JsonSerizaliableModulePlan#toModelType
to create the ReadOnlyModulePlan
object.
6a. JsonAdaptedModule
then calls JsonAdapedModule#toModelType
for the creation of each module
.ModulePlan
is returned to MainApp
where it is used to initialize ModelManager
, which is used during command
execution.DataLoadingException
is thrown when any of the following occus.
This can be seen in the sequence diagram below
The ModuleData
object represents an internal list of all possible modules, which forms the base of the application. It allows for validation of the module codes in user input, and provides the required identity fields for the creation of modules to be saved to the user's study plan.
Though the internal list utlizes the same class as ModulePlan
, here the UniqueModulesList modules
field models the full list of all NUS modules instead of the list of a user's modules in a given semester. It maintains the same property of protecting against duplicate modules, which are identified based on their similar module codes.
The checkDbValidModuleCode(ModuleCode)
method fufills one of the two motivations of ModuleData
: validation. It simply iterates through the internal list and checks if a module with a matching module code exists. It allows Modcraft to distinguish between valid and invalid modules codes during command execution.
Another purpose of ModuleData
is to provide information about a module (e.g. its name, description and number of modular credits), if it is a valid NUS module. This is fufilled by the getModule(ModuleCode)
method, which returns the desired module as an immutable Module
object. This immutability is vital to preserve the correctness of the module information, so that future references to ModuleData
return the same results.
The module information (of over 15000 modules!) is stored as moduleinfo.json
in the src/main/resources/database
folder. Upon launching ModCraft, the module information is deserialized (with the help of the Jackson library) from JSON format to the ModuleData
object through a series of conversions. The Module
fields are parsed into Strings and combined into a JsonAdaptedDbModule
object, which is then further collated into a JsonSerializableModuleData
object. When the JsonSerializableModuleData#toModelType
method is called, an empty ModuleData
object is created before the conversion of all JsonAdaptedDbModule
objects into Module
objects, which are then added into ModuleData
.
This initialization process can be shown through following sequence diagrams:
Note: Initialization failure
A DataLoadingException
is thrown if:
In such cases where the data cannot be read successfully, a RuntimeException
is deliberately triggered to forcefully abort the application's launch. This is necessary as most features are reliant on the validation and information provided by the ModuleData
object.
Aspect: Location of moduleinfo.json
The add
command is used to add a module to the module plan with the information fields Module Code
, Year Taken
,
Semester Taken
, and Grade
.
The format for the add
command can be found here
add
command.Module
is then searched in the model
to see if it is an existing module that NUS offers. If the module is not
offered, an error message will be displayed.Module
is then checked with ModulePlan
to see if it has already been added to the module plan previously.
If the module has already been added the User's module plan, an error message will be displayed.Module
will be added to the ModulePlan
The activity diagram for adding a Module
into the module plan
The sequence of the add
command is as follows:
add
command.add CS2040S y/1 s/1 g/A
LogicManager
calls the ModulePlanParser#parseCommand
to parse the command.ModulePlanParser
then creates a new AddCommandParser
to parse the fields provided by the user and
a new AddCommand
is created.AddCommand
checks if the ModuleCode
is valid bt calling Model#getModuleFromDb
and retrieves
the module if it exists from the database.AddCommand
then fills the user inputs into the module using the Module#fillUserInputs
function.AddCommand
then attempts to add the module into the Model via Model#addModule
.ModuleCode
, the user inputs are valid, and the Model does not contain the module, AddCommand
will
successfully add the new Module
into the module plan.The following two Sequence Diagrams shows how the add
command works:
Here is the Sequence Diagram showing how the parser works:
And here is the Sequence Diagram showing the command being executed:
The edit
command is used to change the information fields (e.g. year, semester and grade) for modules in the study plan.
The format for the edit
command can be found here.
The edit mechanism uses EditModuleDescriptor
to abstract out the fields to edit. It can be found as a publicly accessible class within EditCommand
. Currently, it only contains fields for Year
, Semester
and Grade
, which are the only attributes of Module
that can be edited for now. Besides this, it largely follows the parser and command structure as described in Logic.
We shall now illustrate how EditModuleDescriptor
is used.
Here is a Sequence Diagram showing the parser in action:
And here is a Sequence Diagram showing the command being executed:
As can be seen, this is a helpful class to store fields that need to be edited.
The delete
command is used to delete a module from the module plan. The module can only be deleted if it is already present in one of the semesters in the module plan.
The format of the delete
command can be found here.
delete
command.Module
does not exist in database, an error message informing user that the Module
does not exist will be shown.Module
is then cross-referenced in the Model
to check if a module with the same ModuleCode
exists in the module plan.Module
has not added to the module plan will be shown.Module
will be successfully deleted from the module plan.The following activity diagram shows the logic of deleting a Module
from the module plan:
The sequence of the delete
command is as follows:
delete
command.delete CS3230
LogicManager
calls the ModulePlanParser#parseCommand
to parse the command.ModulePlanParser
then creates a new DeleteCommandParser
to parse the fields provided by the user and a new DeleteCommand
is created.DeleteCommand
checks if the ModuleCode
is valid by calling Model#checkDbValidModuleCode
.DeleteCommand
then checks if the Model
contains a module with the same ModuleCode
by calling Model#getModule
.ModuleCode
is valid and Model
contains the module, the DeleteCommand
calls Model#deleteModule
to delete the module from to the module plan.The following sequence diagram shows how the delete
command works:
The info
command is used to display information about a selected module, which is specified by the user by its module code.
The format of the info
command can be found here.
info
command.InfoCommandParser
checks that only a single argument is provided, and that the argument follows the valid module code format.ParseException
is thrown if either of the above checks fail. Otherwise, an InfoCommand
object will be created and executed.InfoCommand
verifies that the module code exists in ModuleData
. Otherwise, ModuleNotFoundException
will be thrown.Module
is retrieved from the database and the information is displayed to the user.This is shown through the following activity diagram:
During command execution, the info
command calls Module#toInfoString
, as shown in the sequence diagram below:
The calculateCAP
command is used to calculate the Cumulative Average Point (CAP) of all valid modules in the module plan, using their grade points and modular credits.
The format of the calculateCAP
command can be found here.
calculateCAP
command.The sequence of the calculateCAP
command is as follows:
calculateCAP
command.LogicManager
calls the ModulePlanParser#parseCommand
to parse the command.ModulePlanParser
then creates a new CalculateCapCommand
.CalculateCapCommand
calculates the CAP by calling Model#getCap
.The following sequence diagram shows how the calculateCAP
command works:
The calculateMC
command is used to calculate the total sum of Modular Credits (MCs) of all modules in the module plan, regardless of their grades.
The format of the calculateMC
command can be found here.
calculateMC
command.The sequence of the calculateMC
command is as follows:
calculateMC
command.LogicManager
calls the ModulePlanParser#parseCommand
to parse the command.ModulePlanParser
then creates a new CalculateMcCommand
.CalculateMcCommand
calculates the CAP by calling Model#totalModularCredits
.The following sequence diagram shows how the calculateMC
command works:
The proposed pre-requisite checking mechanism is facilitated by Prerequisite
. Every Module
will have a Prerequisite
field. Prerequisite
contains a list of other Prerequisite
objects, of which Module
is a subclass. It also contains a number that represents the number of Prerequisite
s in the list that need to be fulfilled before this Prerequisite
can be considered fulfilled. Additionally, it implements the following operation:
Prerequisite#isFulfilled(List<Module> list)
: Checks whether the current Prerequisite
is fulfilled by the Module
s in list
.This operation is accessed in Module
as Module#checkPrerequisitesFulfilled(List<Module> list)
.
Here is the class diagram:
Given below is an example usage scenario and how the prerequisite mechanism behaves at each step.
Step 1. The user executes add CS2103T y/2 s/1 g/IP
command to add the module CS2103T
in the module plan.
Step 2. When executing the add
command, Module#checkPrerequisitesFulfilled(List<Module> list)
is called to check if the prerequisites have been fulfilled in previous semesters. In this case, these are the Advanced Placement and Year 1 semesters, and the Module
s in these semesters populate list
.
Step 3. ModCraft lets the user know if the prerequisites have not been fulfilled, and which prerequisites. Otherwise, it adds the module CS2103T
to Year 2 Semester 1.
Note: If the module is in the Advanced Placement, there are no other semesters to check.
Step 4. The user now decides to move the module to an earlier semester, and decides to make the appropriate changes by executing the command edit CS2103T y/1 s/2
. The edit
command calls Module#checkPrerequisitesFulfilled(List<Module> list)
again to check if the prerequisites have been fulfilled in previous semesters. In this case, they are the Advanced Placement and Year 1 Semester 1 semesters, and the Module
s in these semesters populate list
.
Step 5. ModCraft lets the user know if the prerequisites have not been fulfilled, and which prerequisites. Otherwise, it moves the module CS2103T
to Year 1 Semester 2.
The following sequence diagram shows how the prerequisite checking works:
The following activity diagram summarizes what happens when a user executes a command that changes the ModulePlan:
For our next steps, we plan to add the following features:
Target user profile:
Value proposition: Provide a fast and easy way for students to track courses to take to meet graduation requirements and plan courses to take, optimized for users who prefer typing in CLI.
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | fast typer | use the typing interface | I save time from interacting with the GUI |
* * * | current student | add modules to "taken" / "taking" / "plan to take" lists | |
* * * | current student | search for modules by module code or module name | |
* * * | current student | remove modules from the lists | |
* * * | current student | access data entered in a previous session | |
* * * | forgetful student | view which year and semester I have taken certain modules | |
* * * | incoming freshman | see the modules I might need to take for my course | I can make an informed decision about what I am applying for |
* * * | current student | check how many MCs I haven taken | I know how many more I need to take to graduate |
* * * | overworked student | just check what modules I have taken | I don't have to remember them myself |
* * | current student | set my major | |
* * | current student | see the modules I need to take to graduate | I can apply for and take those modules to graduate |
* * | current student | see how the modules I plan to take affect what modules I will be able to take in the future | I can plan my future semesters |
* * | current student | check what prerequisite modules I need to take | I can take this specific module |
* * | struggling student | see what modules I can use my remaining S/Us on | I can plan my modules accordingly |
* * | current student | set the grade for taken mods and expected grade for future mods | the app can calculate my CAP for me |
* * | current student | see my current calculated CAP / predicted graduation CAP | I do not have to calculate it myself |
* * | graduated student | check what modules I have taken to revise the skills I have learnt in university | I can use my skills at my job |
* * | graduated student | check the modules I have taken for completing my resume and answering interview questions | I can get the job |
* * | student with many friends in different majors | check whether I can also take the modules they are taking | we can help each other with the module |
* * | double major/degree student | check what modules I can double count | I can lower my workload |
* * | student looking to take a second major or minor | see if I can take the modules required | I can obtain the second major or minor |
* * | student staying in RC/NUSC or taking other special programs (like SPM) | check for modules that fulfill requirements | I can replace the general education modules |
* * | student that wants to take niche modules | search for it | I know what are the options |
* * | current student | see if certain modules are available in the current semester | I can plan my study plan or take it this semester |
* * | student taking credit-bearing internships | see how my internships fulfill my graduation requirement and MCs | |
* * | student taking a focus area | see if the module I have taken satisfy my focus area | |
* * | failing student | see if I can drop certain modules | I can graduate through an alternate path |
* * | student looking for work | see which modules give me skills I need | I can apply for certain jobs/internships |
* * | student who wants to switch courses | check which modules I can carry over and still take | I can graduate |
* | student who likes a certain professor | see which semester that professor will be teaching the module | I can take their module |
* | student who dislikes a certain professor | see which modules they will be teaching | I can avoid them |
* | student going on exchange | see which modules can be mapped over | |
* | advanced user | manually edit the data file | I can manipulate the data as I wish |
* | student that hates a specific module | check for other alternative modules so that I can avoid that module | I can prevent excessive stress |
* | ambitious student | find the fastest way to graduate | |
* | kiasu student | see which modules are popular/oversubscribed | I can adjust my academic plan |
* | JC/Poly student | see what modules I am exempted from | |
* | foreign student | see the bridging modules I am required to take | |
* | current student | check if I am exempted from the bridging modules | I can take them to skip the mod |
* | Advanced Placement student | add what modules I have taken before | |
* | current student | see which modules have a diagnostic test | I can skip the mod |
* | tryhard student | see what modules are available in the special term |
(For all use cases below, the System is ModCraft
and the Actor is the user
, unless specified otherwise)
MSS
Steps 1-4 are repeated for each module the User is interested in.
Use case ends.
Extensions
Steps 1a1 to 1a2 are repeated until the module is available. Use case resumes from step 2.
MSS
Steps 1-2 are repeated for each grade the user would like to update for.
Use case ends.
Extensions
Steps 1a1 and 1a2 are repeated until the user inputs the correct grade. Use case resumes from step 2.
MSS
Use case ends.
MSS
Steps 4-6 are repeated for each combination of modules the user tries.
Use case ends.
MSS
EXE
as the grade for a module that they have taken.EXE
, in the timetable.Steps 1-2 are repeated for each module that the user would like to indicate as exempted.
Use case ends.
Extensions
Steps 1a1 and 1a2 are repeated until the user inputs the correct module code. Use case resumes from step 2.
MSS
S
or U
as the grade for a module that they have taken.S
or U
, in the timetable.
Steps 1-2 are repeated for each module that the user would like to indicate as Satisfactory (S) or Unsatisfactory (U).Use case ends.
Extensions
Steps 1a1 and 1a2 are repeated until the user inputs the correct module code. Use case resumes from step 2.
MSS
Use case ends.
Extensions
Steps 1a1 to 1a2 are repeated until the module is available. Use case resumes from step 2.
MSS
Use case ends.
Extensions
Steps 1a1 to 1a2 are repeated until the module is available. Use case resumes from step 2.
s/ST1
for Special Term 1 or s/ST2
for Special Term 2.Use case resumes from step 4.
MSS
W
or F
.Use case ends.
Extensions
Steps 1a1 and 1a2 are repeated until the user inputs the correct module code. Use case resumes from step 2.
Steps 1b1 and 1b2 are repeated until the user inputs the correct module code. Use case resumes from step 2.
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
Open command terminal and cd
into the folder where the jar file is in. Use the java -jar ModCraft.jar
command to run the application.
Expected: Shows the GUI with a set of sample modules. 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.
Adding a module into a semester
Prerequisites: No new modules are being added except for those default modules present in ModCraft.
Test case: add CS2030S y/1 s/1 g/IP
.
Expected: The module CS2030S
is added to the list Year 1 S1
, with its grade as IP
in a grey box. Details of the added module shown in the status message. The modules shown in the semester list is updated.
Test case: add CS3230 y/0 s/1 g/A
.
Expected: A new column of semester named Adv Placement
appears. The module CS3230
is added to the list Adv Placement
, with its grade as A
in a green box. Details of the added module shown in the status message. The modules shown in the semester list is updated.
Test case: add CS1010 y/1 s/ST1 g/F
.
Expected: A new column of semester named Year 1 ST1
appears. The module CS1010
is added to the list Year 1 ST1
, with its grade as F
in a red box. Details of the added module shown in the status message. The modules shown in the semester list is updated.
Test case: add CS1231S ...
when it is already in the semester list.
Expected: No module is added. Error details shown in the status message. Status bar remains the same.
Test case: add CS1010 y/1 s/ST1 g/a
.
Expected: No module is added. Error details of wrong format of grade shown in the status message. Status bar remains the same.
Other incorrect add commands to try: add
, add 1234
, add CS1010 y/1
, ...
(when the format of the module code to be added is incorrect)
Expected: Similar to previous.
Deleting a module from a semester
Prerequisites: Multiple modules in the list.
Test case: delete CS2030S
.
Expected: The module CS2030S
is deleted from the list. Details of the deleted module shown in the status message. The modules shown in the semester list is updated.
Test case: delete CS1231S
when it is not in the semester list.
Expected: No module is deleted. Error details shown in the status message. Status bar remains the same.
Other incorrect delete commands to try: delete
, delete 1234
, ...
(when the format of the module code to be deleted is incorrect).
Expected: Similar to previous.
Editing a module already present in a semester
Prerequisites: The module to be edited is already present in ModCraft.
Test case: edit CS2030S g/IP
.
Expected: The grade of CS2030S
is updated to IP
in a grey box. Details of the edited module shown in the status message. The module shown in the semester list is updated.
Test case: edit CS3230 y/0
.
Expected: A new column of semester named Adv Placement
appears. The module CS3230
is moved to the list Adv Placement
, while its grade remain unchanged. Details of the edited module shown in the status message. The modules shown in the semester list is updated.
Test case: edit CS1010 s/ST1
.
Expected: A new column of semester named ST1
appears. The module CS1010
is moved to the list ST1
, while its grade and semester remain unchanged. Details of the added module shown in the status message. The modules shown in the semester list is updated.
Test case: edit CS1010 g/a
.
Expected: No module is edited. Error details of wrong format of grade shown in the status message. Status bar remains the same.
Test case: edit CS1101S ...
when it is not already present in the semester list.
Expected: No module is edited. Error details shown in the status message. Status bar remains the same.
Other incorrect edit commands to try: edit
, edit 1234
, ...
(when the format of the module code to be edited is incorrect)
Expected: Similar to previous.
Finding information about a module from the database
Test case: info CS2030S
.
Expected: The module code, module title, modular credit and module description of CS2030S
is displayed.
Other incorrect info commands to try: info
, info 1234
, ...
(when the format of the module code to be searched is incorrect).
No information about module is displayed. Error details shown in the status message. Status bar remains the same.
Calculating the current CAP from all modules
Test case: calculateCAP
when there are no modules in the semester list.
Expected: The CAP output is 0.0
.
Prerequisites: Multiple module in the list.
Test case: calculateCAP
.
Expected: The CAP output is a float
of 0.0
5.0
with a status message.
Test case: calculateCAP
when grades of all modules are marked as IP
, EXE
, W
, IC
, S
, U
, CS
or CU
.
Expected: The CAP output is 0.0
.
Calculating the current Modular Credits (MCs) from all modules
Test case: calculateMC
when there are no modules in all the semester lists.
Expected: The Modular Credits output is 0.0
.
Prerequisites: Multiple modules in the list.
Test case: calculateMC
.
Expected: The Modular Credits output is a float
of Modular Credits 0.0
with a status message.
Dealing with missing/corrupted data files
Prerequisites: There are existing module and module plan files with existing stored modules.
Test Case: Close the application and delete moduleplan.json
.
Expected: Upon the next application start, a new moduleplan.json
is created.
Test Case: Close the application and edit moduleplan.json
by changing the name of the first Module to CS3230
.
Expected: Upon the next application start, the name of the first Module in chronological order in the list of years and semesters will appear as CS3230
.
Test Case: Close the application and edit moduleplan.json
by changing the year of the first Module to 2
.
Expected: Upon the next application start, the name of the first Module will appear in Year 2
, with its semester and grade unchanged.
Test Case: Close the application and edit moduleplan.json
by changing the semester of the first Module to ST2
.
Expected: Upon the next application start, the name of the first Module will appear in ST2
, with its year and grade unchanged.
Test Case: Close the application and edit moduleplan.json
by changing the grade of the first Module to IP
.
Expected: Upon the next application start, the grade of the first Module in chronological order in the list of years and semesters will appear as IP
, which should be grey in colour. Its name should remain unchanged.