Skip to content

Commit

Permalink
Merge pull request #262 from kiatkat/master
Browse files Browse the repository at this point in the history
Update PPP, add testcases
  • Loading branch information
kiatkat committed Nov 13, 2023
2 parents b1879b4 + b19b376 commit d89e768
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 50 deletions.
75 changes: 36 additions & 39 deletions docs/team/kiatkat.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,46 @@ layout: page
title: Kiat Win's Project Portfolio Page
---

## Project: ProfPlan
### Project: ProfPlan

ProfPlan is a desktop productivity application written in Java, used for task management and organization. The user
interacts with it using a CLI, and it has a GUI created with JavaFX.

Listed below are my contributions to the project, with the relevant pull requests linked where possible.

**Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=kiatkat&breakdown=true)
Listed below are my contributions to the project, with some relevant pull requests linked where possible. ([RepoSense
link to code contributed](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=kiatkat&breakdown=true))

### New Features
* Added the ability to create recurring tasks. [#130](https://github.com/AY2324S1-CS2103T-W15-1/tp/pull/130)
* What it does: Allows the user to denote a task as a recurring task, a new type of task that is never entirely
completed. Rather, marking this type of task as done will push its due date into the future by an amount
depending on its type.
* Justification: This feature better reflects the needs of most users, as a large number of tasks are cyclical in
nature and repeat on a periodic basis. The application can then better model these tasks and provide a more
natural means for the user to manage them.
* Highlights: This enhancement directly affects the `add` command,adding directly onto its implementation. A
thorough consideration of design options was necessary to determine a solution which could seamlessly integrate
with the `add` command and which had minimal overhead, while still providing extensibility and flexibility to
its own usage.
* Credits: Code written for this feature is original.
* What it does: Allows the user to create a new type of task that postpones its due date when marked as completed.
* Justification: A large number of tasks are cyclical in nature. The application can now better model these tasks
and provide a more natural means for the user to manage them.
* Highlights: This enhancement directly affects the `add` command, adding directly onto its implementation. A
thorough consideration of design options was necessary to determine a solution which could do so with minimal
overhead, while still providing extensibility and flexibility.
* Credits: Code written is original.

* Added the ability for the user to change some defined settings to customize their experience. [#138](https://github.com/AY2324S1-CS2103T-W15-1/tp/pull/138)
* Added the ability for the user to modify settings. [#138](https://github.com/AY2324S1-CS2103T-W15-1/tp/pull/138)
* What it does: Allows the user to change certain global parameters that affect the behaviour of other commands
via the `set` command.
* Justification: Different users may desire different parameters for some commands, and wish to customize the
* Justification: Different users may desire different parameters for some commands and wish to customize the
application to suit their unique needs.
* Highlights: This feature required changes across the codebase in multiple regions of the architecture. A
`settings.json` file must be created to maintain these user configurations through sessions, and so various
infrastructure must be set up to properly store and read from this file. Furthermore, the user has to be able to
modify the values in this file, and any command must be able to read these settings. Careful thought had to be
given to the structure and design of this system to reduce dependencies across the codebase.
* Credits: The design of the `UserConfigs` system is similar to AB3's `UserPrefs` in the interest of consistency.
However, `UserConfigs` and its related classes are independent of the existing systems, and all such code
written is otherwise original.
* Note: The `set` feature initially implemented (pre-v1.3) is a different feature from the current `set` feature,
and it has since been removed. As I was responsible for both of these features, past pull requests may mention
this dated `set` feature. All further mentions of `set` in this document are meant to refer to the current
implementation (settings) as described above.
file is created to maintain user configurations between sessions, and the user must be able to modify the
values in this file, with any command also being able to read these settings. Careful thought had to be given to
the structure and design of this system to minimize dependencies.
* Credits: Code written is original.
* Note: There was a `set` feature of the same name implemented in versions pre-v1.3, which is completely different
in specification, and has since been removed. All mentions of `set` in this document refer to the implementation
described above.

* Added the ability for the user to add descriptions. [#105](https://github.com/AY2324S1-CS2103T-W15-1/tp/pull/105)
* What it does: Allows the user to add an associated description field to a task and edit it with the
`description` command.
* Justification: Users may want to store information related to the task that is not expressible by the limited
values of the other fields.
* Highlights: This feature required good planning to integrate well into the existing structure of a task, while
maintaining flexibility and keeping dependence on other classes low.
* Credits: Code written is original.

### Project management and team-based tasks
* Responsible for creating and setting deadlines for all milestones
Expand All @@ -56,22 +56,19 @@ Listed below are my contributions to the project, with the relevant pull request
### Enhancements to existing features
* Updated the `find` feature to new specifications: [#77](https://github.com/AY2324S1-CS2103T-W15-1/tp/pull/77)

### Documentation

#### User Guide
### User Guide

* Added documentation for the features `find` and `set` [#22](https://github.com/AY2324S1-CS2103T-W15-1/tp/issues/22)
* Added documentation for the `recur/` flag and all corresponding mentions of recurring tasks
* Added documentation for supported setting parameters
* Added information on the acceptable values for the parameters that the user can input
* Wrote the introductory section, "What can ProfPlan do for you?"
* Contributed to the preambles of some sections under "Advanced Features"
* Added documentation for the `find` and `set` features ([#22](https://github.com/AY2324S1-CS2103T-W15-1/tp/issues/22)),
the `recur/` flag and corresponding mentions of recurring tasks, as well as supported setting parameters
* Clarified the acceptable values for the parameters that the user can input
* Wrote the section "What can ProfPlan do for you?" and some sections under "Advanced Features"
* Made some tweaks to fix language errors

#### Developer Guide
### Developer Guide

* Modified UML diagrams to reflect the addition of the `UserConfigs` system
* Added use cases specific to `find` and `set`
* Added use cases specific to the features implemented above
* Made tweaks to the design and layout and corrected some language errors

### Community

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"settings" : {
"semesterDays" : 180,
"extra" : "some value"
},
"profPlanFilePath" : "data\\profplan.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Not a json file!
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"settings" : {
"semesterDays" : 180
},
"profPlanFilePath" : "data\\profplan.json"
}
4 changes: 3 additions & 1 deletion src/test/java/profplan/logic/commands/CommandTestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public class CommandTestUtil {
public static final String VALID_TAG_FRIEND = "friend";
public static final String VALID_LINK_EXAMPLE = "www.exmaple.com";
public static final String VALID_LINK_GOOGLE = "www.google.com";
public static final String VALID_DESCRIPTION = "gg";
public static final String VALID_DESCRIPTION = "this is a valid description";
public static final String EMPTY_DESCRIPTION = "";
public static final String UNUSUAL_VALID_DESCRIPTION = "!@#$%^&*()_ ;'d;'~~~";

public static final String DUEDATE_DESC = " " + PREFIX_DUEDATE + "10-12-2023";

Expand Down
19 changes: 9 additions & 10 deletions src/test/java/profplan/logic/parser/AddCommandParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,27 +96,26 @@ public void parse_optionalFieldsMissing_success() {
new AddCommand(expectedTask));
}

/*
@Test - <<Rewrite test once all compulsory fields for task is determined>>
@Test
public void parse_compulsoryFieldMissing_failure() {
String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE);
String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_FULL_HELP);

// missing name prefix
CommandParserTestUtil.assertParseFailure(parser, CommandTestUtil.VALID_NAME_BOB
+ CommandTestUtil.PRIORITY_DESC_BOB,
CommandParserTestUtil.assertParseFailure(parser, CommandTestUtil.PRIORITY_DESC_BOB
+ CommandTestUtil.DUEDATE_DESC,
expectedMessage);

// missing priority prefix
CommandParserTestUtil.assertParseFailure(parser, CommandTestUtil.NAME_DESC_BOB
+ CommandTestUtil.VALID_PRIORITY_BOB,
CommandParserTestUtil.assertParseFailure(parser, CommandTestUtil.VALID_NAME_BOB
+ CommandTestUtil.DUEDATE_DESC,
expectedMessage);

// all prefixes missing
// missing due date prefix
CommandParserTestUtil.assertParseFailure(parser, CommandTestUtil.VALID_NAME_BOB
+ CommandTestUtil.VALID_PRIORITY_BOB,
+ CommandTestUtil.PRIORITY_DESC_BOB,
expectedMessage);
}
*/


@Test
public void parse_invalidValue_failure() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package profplan.logic.parser;

import static profplan.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import org.junit.jupiter.api.Test;

import profplan.logic.commands.DescriptionCommand;
import profplan.model.task.Description;
import profplan.testutil.TypicalIndexes;

public class DescriptionCommandParserTest {

private DescriptionCommandParser parser = new DescriptionCommandParser();

@Test
public void parse_emptyArg_throwsParseException() {
CommandParserTestUtil.assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
DescriptionCommand.MESSAGE_FULL_HELP));
}

@Test
public void parse_validArgs_returnsDescriptionCommand() {
DescriptionCommand expectedDescriptionCommand =
new DescriptionCommand(TypicalIndexes.INDEX_FIRST_TASK, new Description("test description"));

CommandParserTestUtil.assertParseSuccess(parser, " 1 des/ test description ",
expectedDescriptionCommand);
}

@Test
public void parse_invalidIndex_throwsParseException() {
CommandParserTestUtil.assertParseFailure(parser, " abc des/def ",
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DescriptionCommand.MESSAGE_FULL_HELP));
}

@Test
public void parse_emptyDescription_returnsDescriptionCommand() {
DescriptionCommand expectedDescriptionCommand =
new DescriptionCommand(TypicalIndexes.INDEX_FIRST_TASK, new Description(""));

CommandParserTestUtil.assertParseSuccess(parser, " 1 des/ ",
expectedDescriptionCommand);
}

@Test
public void parse_specialCharactersDescription_returnsDescriptionCommand() {
DescriptionCommand expectedDescriptionCommand =
new DescriptionCommand(TypicalIndexes.INDEX_FIRST_TASK, new Description("!@#$%^&*()_"));

CommandParserTestUtil.assertParseSuccess(parser, " 1 des/ !@#$%^&*()_ ",
expectedDescriptionCommand);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package profplan.logic.parser;

import static profplan.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import org.junit.jupiter.api.Test;

import profplan.logic.commands.EditSettingsCommand;

public class EditSettingsCommandParserTest {

private EditSettingsCommandParser parser = new EditSettingsCommandParser();

@Test
public void parse_emptyArgs_throwsParseException() {
CommandParserTestUtil.assertParseFailure(parser, " ",
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditSettingsCommand.MESSAGE_FULL_HELP));
}

@Test
public void parse_invalidParameter_throwsParseException() {
CommandParserTestUtil.assertParseFailure(parser, " set aaaaaa 123 ",
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditSettingsCommand.MESSAGE_FULL_HELP));
}
}
123 changes: 123 additions & 0 deletions src/test/java/profplan/storage/JsonUserConfigsStorageTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package profplan.storage;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import profplan.commons.core.Settings;
import profplan.commons.exceptions.DataLoadingException;
import profplan.model.UserConfigs;
import profplan.testutil.Assert;

public class JsonUserConfigsStorageTest {

private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonUserConfigsStorageTest");

@TempDir
public Path testFolder;

@Test
public void readUserConfigs_nullFilePath_throwsNullPointerException() {
Assert.assertThrows(NullPointerException.class, () -> readUserConfigs(null));
}

private Optional<UserConfigs> readUserConfigs(String userConfigsFileInTestDataFolder) throws DataLoadingException {
Path configsFilePath = addToTestDataPathIfNotNull(userConfigsFileInTestDataFolder);
return new JsonUserConfigsStorage(configsFilePath).readUserConfigs(configsFilePath);
}

@Test
public void readUserConfigs_missingFile_emptyResult() throws DataLoadingException {
assertFalse(readUserConfigs("NonExistentFile.json").isPresent());
}

@Test
public void readUserConfigs_notJsonFormat_exceptionThrown() {
Assert.assertThrows(DataLoadingException.class, () -> readUserConfigs("NotJsonFormatUserConfigs.json"));
}

private Path addToTestDataPathIfNotNull(String userConfigsFileInTestDataFolder) {
return userConfigsFileInTestDataFolder != null
? TEST_DATA_FOLDER.resolve(userConfigsFileInTestDataFolder)
: null;
}

@Test
public void readUserConfigs_fileInOrder_successfullyRead() throws DataLoadingException {
UserConfigs expected = getTypicalUserConfigs();
UserConfigs actual = readUserConfigs("TypicalUserConfig.json").get();
assertEquals(expected, actual);
}

@Test
public void readUserConfigs_valuesMissingFromFile_defaultValuesUsed() throws DataLoadingException {
UserConfigs actual = readUserConfigs("EmptyUserConfigs.json").get();
assertEquals(new UserConfigs(), actual);
}

@Test
public void readUserConfigs_extraValuesInFile_extraValuesIgnored() throws DataLoadingException {
UserConfigs expected = getTypicalUserConfigs();
UserConfigs actual = readUserConfigs("ExtraValuesUserConfig.json").get();

assertEquals(expected, actual);
}

private UserConfigs getTypicalUserConfigs() {
UserConfigs userConfigs = new UserConfigs();
userConfigs.setSettings(new Settings(180));
userConfigs.setProfPlanFilePath(Paths.get("data\\profplan.json"));
return userConfigs;
}

@Test
public void saveConfigs_nullConfigs_throwsNullPointerException() {
Assert.assertThrows(NullPointerException.class, () -> saveUserConfigs(null, "SomeFile.json"));
}

@Test
public void saveUserConfigs_nullFilePath_throwsNullPointerException() {
Assert.assertThrows(NullPointerException.class, () -> saveUserConfigs(new UserConfigs(), null));
}

/**
* Saves {@code userConfigs} at the specified {@code ConfigsFileInTestDataFolder} filepath.
*/
private void saveUserConfigs(UserConfigs userConfigs, String configsFileInTestDataFolder) {
try {
new JsonUserConfigsStorage(addToTestDataPathIfNotNull(configsFileInTestDataFolder))
.saveUserConfigs(userConfigs);
} catch (IOException ioe) {
throw new AssertionError("There should not be an error writing to the file", ioe);
}
}

@Test
public void saveUserConfigs_allInOrder_success() throws DataLoadingException, IOException {

UserConfigs original = new UserConfigs();
original.setSettings(new Settings(180));

Path pefsFilePath = testFolder.resolve("TempConfigs.json");
JsonUserConfigsStorage jsonUserConfigsStorage = new JsonUserConfigsStorage(pefsFilePath);

//Try writing when the file doesn't exist
jsonUserConfigsStorage.saveUserConfigs(original);
UserConfigs readBack = jsonUserConfigsStorage.readUserConfigs().get();
assertEquals(original, readBack);

//Try saving when the file exists
original.setSettings(new Settings(180));
jsonUserConfigsStorage.saveUserConfigs(original);
readBack = jsonUserConfigsStorage.readUserConfigs().get();
assertEquals(original, readBack);
}

}

0 comments on commit d89e768

Please sign in to comment.