From ef571852cf79af8c473ed647a006c281125b0c84 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Thu, 5 Apr 2018 03:21:03 +0800 Subject: [PATCH 01/19] Add import command --- build.gradle | 2 +- src/main/java/seedu/address/MainApp.java | 8 +-- .../address/logic/commands/ImportCommand.java | 72 +++++++++++++++++++ .../seedu/address/logic/parser/CliSyntax.java | 1 + .../address/logic/parser/DeskBoardParser.java | 5 ++ .../logic/parser/ImportCommandParser.java | 44 ++++++++++++ .../java/seedu/address/model/tag/Tag.java | 2 +- .../address/storage/DeskBoardStorage.java | 7 -- .../seedu/address/storage/StorageManager.java | 6 -- .../address/storage/XmlDeskBoardStorage.java | 5 -- 10 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 src/main/java/seedu/address/logic/commands/ImportCommand.java create mode 100644 src/main/java/seedu/address/logic/parser/ImportCommandParser.java diff --git a/build.gradle b/build.gradle index 50cd2ae52efc..c1105ad3861c 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ dependencies { } shadowJar { - archiveName = "addressbook.jar" + archiveName = "CLIndar.jar" destinationDir = file("${buildDir}/jar/") } diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index cdf94ba964fc..aa16586f3591 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -86,14 +86,14 @@ private String getApplicationParameter(String parameterName) { * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book. */ private Model initModelManager(Storage storage, UserPrefs userPrefs) { - Optional addressBookOptional; + Optional deskBoardOptional; ReadOnlyDeskBoard initialData; try { - addressBookOptional = storage.readDeskBoard(); - if (!addressBookOptional.isPresent()) { + deskBoardOptional = storage.readDeskBoard(); + if (!deskBoardOptional.isPresent()) { logger.info("Data file not found. Will be starting with a sample DeskBoard"); } - initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleDeskBoard); + initialData = deskBoardOptional.orElseGet(SampleDataUtil::getSampleDeskBoard); } catch (DataConversionException e) { logger.warning("Data file not in the correct format. Will be starting with an empty DeskBoard"); initialData = new DeskBoard(); diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java new file mode 100644 index 000000000000..2289f4c92c87 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -0,0 +1,72 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; + +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.DeskBoard; +import seedu.address.model.ReadOnlyDeskBoard; +import seedu.address.model.activity.Activity; +import seedu.address.model.activity.exceptions.DuplicateActivityException; +import seedu.address.storage.XmlDeskBoardStorage; + +import java.io.IOException; + +//@@author karenfrilya97 +/** + * Imports desk board data from a given xml file. + */ +public class ImportCommand extends UndoableCommand { + + public static final String COMMAND_WORD = "import"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Imports desk board data from a given xml file. " + + "Parameters: " + + PREFIX_FILE_PATH + "FILE PATH\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_FILE_PATH + "C:\\Users\\Karen\\IdeaProjects\\main\\data\\deskboard.xml"; + + public static final String MESSAGE_DUPLICATE_ACTIVITY = "The following entry already exists in the desk board: %s"; + public static final String MESSAGE_FILE_NOT_FOUND = "Desk board file not found"; + public static final String MESSAGE_ILLEGAL_VALUES_IN_FILE = "Illegal values found in file: %s"; + public static final String MESSAGE_SUCCESS = "Data imported from: %1$s"; + + private final String filePath; + private ReadOnlyDeskBoard importedDeskBoard; + + /** + * Creates an ImportCommand to import data from the specified {@code filePath}. + */ + public ImportCommand(String filePath) { + requireNonNull(filePath); + this.filePath = filePath; + } + + @Override + public CommandResult executeUndoableCommand() throws CommandException { + requireNonNull(model); + try { + importedDeskBoard = new XmlDeskBoardStorage(filePath).readDeskBoard().orElse(new DeskBoard()); + } catch (IOException ioe) { + throw new CommandException(MESSAGE_FILE_NOT_FOUND); + } catch (DataConversionException dce) { + throw new CommandException(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, dce.getMessage())); + } + for (Activity activity : importedDeskBoard.getActivityList()) { + try { + model.addActivity(activity); + } catch (DuplicateActivityException dae) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_ACTIVITY, activity)); + } + } + return new CommandResult(String.format(MESSAGE_SUCCESS, filePath)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ImportCommand // instanceof handles nulls + && filePath.equals(((ImportCommand) other).filePath)); + } +} diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index f16b6c6e9123..47bb85b15787 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -9,6 +9,7 @@ public class CliSyntax { /* Prefix definitions */ public static final Prefix PREFIX_NAME = new Prefix("n/"); public static final Prefix PREFIX_DATE_TIME = new Prefix("d/"); + public static final Prefix PREFIX_FILE_PATH = new Prefix("f/"); public static final Prefix PREFIX_REMARK = new Prefix("r/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); public static final Prefix PREFIX_START_DATETIME = new Prefix("s/"); diff --git a/src/main/java/seedu/address/logic/parser/DeskBoardParser.java b/src/main/java/seedu/address/logic/parser/DeskBoardParser.java index 69dcd4520101..a6b4056367ff 100644 --- a/src/main/java/seedu/address/logic/parser/DeskBoardParser.java +++ b/src/main/java/seedu/address/logic/parser/DeskBoardParser.java @@ -11,6 +11,7 @@ import seedu.address.logic.commands.CompleteCommand; import seedu.address.logic.commands.EventCommand; import seedu.address.logic.commands.HelpCommand; +import seedu.address.logic.commands.ImportCommand; import seedu.address.logic.commands.ListCommand; import seedu.address.logic.commands.RemoveCommand; import seedu.address.logic.commands.TaskCommand; @@ -95,6 +96,10 @@ public Command parseCommand(String userInput) throws ParseException { //case RedoCommand.COMMAND_WORD: //return new RedoCommand(); + //@@author karenfrilya97 + case ImportCommand.COMMAND_WORD: + return new ImportCommandParser().parse(arguments); + default: throw new ParseException(MESSAGE_UNKNOWN_COMMAND); } diff --git a/src/main/java/seedu/address/logic/parser/ImportCommandParser.java b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java new file mode 100644 index 000000000000..619d3353d282 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java @@ -0,0 +1,44 @@ +package seedu.address.logic.parser; + +import seedu.address.logic.commands.ImportCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +import java.util.stream.Stream; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; + +//@@author karenfrilya97 +/** + * Parses input arguments and creates a new ImportCommand object + */ +public class ImportCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the ImportCommand + * and returns an ImportCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public ImportCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_FILE_PATH); + + if (!arePrefixesPresent(argMultimap, PREFIX_FILE_PATH) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE)); + } + + String filePath = argMultimap.getValue(PREFIX_FILE_PATH).orElse(""); + return new ImportCommand(filePath); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } + +} + diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java index c5e8a7ba1427..2a612afb7109 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/seedu/address/model/tag/Tag.java @@ -9,7 +9,7 @@ */ public class Tag { - public static final String MESSAGE_TAG_CONSTRAINTS = "Tags names should be alphanumeric"; + public static final String MESSAGE_TAG_CONSTRAINTS = "Tag names should be alphanumeric"; public static final String TAG_VALIDATION_REGEX = "\\p{Alnum}+"; public final String tagName; diff --git a/src/main/java/seedu/address/storage/DeskBoardStorage.java b/src/main/java/seedu/address/storage/DeskBoardStorage.java index 4405136ab059..95e9da78d28b 100644 --- a/src/main/java/seedu/address/storage/DeskBoardStorage.java +++ b/src/main/java/seedu/address/storage/DeskBoardStorage.java @@ -41,11 +41,4 @@ public interface DeskBoardStorage { * @see #saveDeskBoard(ReadOnlyDeskBoard) */ void saveDeskBoard(ReadOnlyDeskBoard deskBoard, String filePath) throws IOException; - - /** - * Saves the given {@link ReadOnlyDeskBoard} to the fixed temporary location. - * @param deskBoard cannot be null. - * @throws IOException if there was any problem writing to the file. - */ - void backupDeskBoard(ReadOnlyDeskBoard deskBoard) throws IOException; } diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java index 5effff5e2f62..729408313ec4 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/seedu/address/storage/StorageManager.java @@ -77,11 +77,6 @@ public void saveDeskBoard(ReadOnlyDeskBoard deskBoard, String filePath) throws I deskBoardStorage.saveDeskBoard(deskBoard, filePath); } - @Override - public void backupDeskBoard(ReadOnlyDeskBoard deskBoard) throws IOException { - deskBoardStorage.backupDeskBoard(deskBoard); - } - @Override @Subscribe public void handleDeskBoardChangedEvent(DeskBoardChangedEvent dbce) { @@ -92,5 +87,4 @@ public void handleDeskBoardChangedEvent(DeskBoardChangedEvent dbce) { raise(new DataSavingExceptionEvent(e)); } } - } diff --git a/src/main/java/seedu/address/storage/XmlDeskBoardStorage.java b/src/main/java/seedu/address/storage/XmlDeskBoardStorage.java index af11caa395be..a045a640c48f 100644 --- a/src/main/java/seedu/address/storage/XmlDeskBoardStorage.java +++ b/src/main/java/seedu/address/storage/XmlDeskBoardStorage.java @@ -78,9 +78,4 @@ public void saveDeskBoard(ReadOnlyDeskBoard deskBoard, String filePath) throws I FileUtil.createIfMissing(file); XmlFileStorage.saveDataToFile(file, new XmlSerializableDeskBoard(deskBoard)); } - - @Override - public void backupDeskBoard(ReadOnlyDeskBoard deskBoard) throws IOException { - saveDeskBoard(deskBoard, filePath + ".backup"); - } } From 9ce862e80ab052f3338094b10a456e03a2acaedf Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Thu, 5 Apr 2018 03:22:38 +0800 Subject: [PATCH 02/19] Uncomment exit command in DeskBoardParser --- .../java/seedu/address/logic/parser/DeskBoardParser.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/address/logic/parser/DeskBoardParser.java b/src/main/java/seedu/address/logic/parser/DeskBoardParser.java index a6b4056367ff..227a33006fd4 100644 --- a/src/main/java/seedu/address/logic/parser/DeskBoardParser.java +++ b/src/main/java/seedu/address/logic/parser/DeskBoardParser.java @@ -10,6 +10,7 @@ import seedu.address.logic.commands.Command; import seedu.address.logic.commands.CompleteCommand; import seedu.address.logic.commands.EventCommand; +import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ImportCommand; import seedu.address.logic.commands.ListCommand; @@ -81,8 +82,8 @@ public Command parseCommand(String userInput) throws ParseException { //case HistoryCommand.COMMAND_WORD: //return new HistoryCommand(); - //case ExitCommand.COMMAND_WORD: - //return new ExitCommand(); + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); case HelpCommand.COMMAND_WORD: return new HelpCommandParser().parse(arguments); From 276818722d1fcb7383fc1129c278196686251ca0 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Thu, 5 Apr 2018 22:15:34 +0800 Subject: [PATCH 03/19] Update UG to include import command --- docs/UserGuide.adoc | 50 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 9a1cdb54f5d4..711964759737 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -135,8 +135,7 @@ Removes a task or event from the desk board according to the following condition * `rm task INDEX`: removes a task. * `rm event INDEX`: removes an event. -*Examples:* - +*Example:* * `ls task` + `rm task 2` + @@ -235,7 +234,17 @@ Clears all entries from the desk board. *Format:* `clear` or `c` -=== Exiting the program : `exit` `[Coming Soon in v1.5]` +=== Importing data : `import` `[As of v1.4.1]` + +Import all entries from another desk board file in the specified file path. + +*Format:* `import f/FILE_PATH` + +*Example:* + +* `import f/C:\data\deskboard.xml` + +=== Exiting the program : `exit` `[As of v1.4.1]` Exits the program. @@ -260,46 +269,49 @@ There is no need to save manually. == Command Summary * *Add task*: `task n/NAME d/DUE_DATE_TIME [r/REMARK] [t/TAGS]` + -eg. `task n/Software Engineering Milestone 1 d/16/03/2018 17:00 r/urgent` +e.g. `task n/Software Engineering Milestone 1 d/16/03/2018 17:00 r/urgent` * *Add event*: `event n/NAME s/START_TIME e/END_TIME [l/LOCATION] [r/REMARK]` + -eg. `event n/Software Project s/1/5/2018 8:00 e/01/08/2018 8:00 l/School of Computing r/remember to bring laptop charger` +e.g. `event n/Software Project s/1/5/2018 8:00 e/01/08/2018 8:00 l/School of Computing r/remember to bring laptop charger` * *List uncompleted tasks and upcoming events*: `ls` + -eg. `ls` or `ls task` or `ls event` +e.g. `ls` or `ls task` or `ls event` * *Remove task or event*: `rm` + -eg. `rm task 1` or `rm event 2` +e.g. `rm task 1` or `rm event 2` * *Complete a task*: `complete task` or `com task` + -eg. `complete task 1` or `com task 2` +e.g. `complete task 1` or `com task 2` * *List completed tasks*: `ls complete task` or `ls com task` + -eg. `ls complete task` or `ls com task` +e.g. `ls complete task` or `ls com task` -* *Show overdue tasks*: `overdue` + -eg. `overdue` +* *List overdue tasks*: `overdue` + +e.g. `overdue` * *List entered commands*: `history` + -eg. `history` +e.g. `history` * *Undo previous command*: `undo` or `u` + -eg. `undo` or `u` +e.g. `undo` or `u` * *Redo previously undone command*: `redo` or `r` + -eg. `redo` or `r` +e.g. `redo` or `r` * *Clear all entries*: `clear` or `c` + -eg. `clear` or `c` +e.g. `clear` or `c` + +* *Import data*: `import f\FILE_PATH` + +e.g. `import f/C:\data\deskboard.xml` * *Exit the program*: `exit` + -eg. `exit` +e.g. `exit` * *Edit a task*: `edit task` + -eg. `edit task 1` +e.g. `edit task 1` * *Locate a task by name*: `find task` + -eg. `find task CS2106 Assignment` +e.g. `find task CS2106 Assignment` * *List all past events*: `ls past event` + -eg. `ls past event` +e.g. `ls past event` From 6e250d3bcf96213a3f747bc92227f82e440a9e0a Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Thu, 5 Apr 2018 22:19:15 +0800 Subject: [PATCH 04/19] Update DG user stories --- docs/DeveloperGuide.adoc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index e5d7cc275861..ed5e25e9b37d 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -1125,6 +1125,8 @@ Priorities: High (must have) - `* * \*`, Medium (nice to have) - `* \*`, Low (un |`* * *` |student |view completed tasks |be assured I have completed a task +|`* * *` |student |import entries from another file |easily add entries previously saved in another file + |`* * *` |forgetful student |view overdue tasks |be assured I did not miss any deadline |`* * *` |forgetful student |get notification for upcoming tasks |never forget to complete my tasks @@ -1143,10 +1145,7 @@ Priorities: High (must have) - `* * \*`, Medium (nice to have) - `* \*`, Low (un |`* *` |procrastinating student |add estimated time needed to complete a task |estimate when to start on a task to complete it on time -|`* *` |procrastinating student |view contact details of activity in-charge for a deadline extension |have enough time to complete my assignments despite my tight schedule -======= -|`* *` |procrastinating student |view contact details of person in-charge for a deadline extension |have enough time to complete my task despite my tight schedule - +|`* *` |procrastinating student |view contact details of person in-charge for a deadline extension |have enough time to complete my assignments despite my tight schedule |`* *` |busy student |view free time slots before a deadline |know how much time I have when I'm actually free to finish my tasks @@ -1159,7 +1158,6 @@ Priorities: High (must have) - `* * \*`, Medium (nice to have) - `* \*`, Low (un |`*` |student |be rewarded for completing a task |feel a sense of achievement |`*` |student |hide private events |minimize chance of someone else seeing them by accident -|======================================================================= [appendix] == Use Cases From 4eb4098a187cc758805d98b89881d39e2c8fbc8a Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Thu, 5 Apr 2018 22:29:52 +0800 Subject: [PATCH 05/19] Fix checkstyle errors --- .../java/seedu/address/logic/commands/ImportCommand.java | 4 ++-- .../seedu/address/logic/parser/ImportCommandParser.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index 2289f4c92c87..575a84d36a57 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -3,6 +3,8 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; +import java.io.IOException; + import seedu.address.commons.exceptions.DataConversionException; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.DeskBoard; @@ -11,8 +13,6 @@ import seedu.address.model.activity.exceptions.DuplicateActivityException; import seedu.address.storage.XmlDeskBoardStorage; -import java.io.IOException; - //@@author karenfrilya97 /** * Imports desk board data from a given xml file. diff --git a/src/main/java/seedu/address/logic/parser/ImportCommandParser.java b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java index 619d3353d282..fa6b78bd1e97 100644 --- a/src/main/java/seedu/address/logic/parser/ImportCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java @@ -1,12 +1,12 @@ package seedu.address.logic.parser; -import seedu.address.logic.commands.ImportCommand; -import seedu.address.logic.parser.exceptions.ParseException; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; import java.util.stream.Stream; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; +import seedu.address.logic.commands.ImportCommand; +import seedu.address.logic.parser.exceptions.ParseException; //@@author karenfrilya97 /** From b99ebe6dce29bdc67bfad4faa9d95dc0bb7dd676 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Fri, 6 Apr 2018 17:17:38 +0800 Subject: [PATCH 06/19] Add ImportCommandTest --- .../address/logic/commands/ImportCommand.java | 21 ++-- .../java/seedu/address/model/DeskBoard.java | 22 ++++ src/main/java/seedu/address/model/Model.java | 5 + .../seedu/address/model/ModelManager.java | 19 ++- .../model/activity/UniqueActivityList.java | 19 ++- .../ImportCommandTest/duplicateActivity.xml | 32 +++++ .../data/ImportCommandTest/illegalValues.xml | 1 + .../ImportCommandTest/validImportFile.xml | 18 +++ ...eskBoard.xml => notXmlFormatDeskBoard.xml} | 0 .../address/commons/util/XmlUtilTest.java | 3 +- .../logic/commands/EventCommandTest.java | 7 +- .../logic/commands/ImportCommandTest.java | 118 ++++++++++++++++++ .../logic/commands/TaskCommandTest.java | 7 +- .../storage/XmlDeskBoardStorageTest.java | 2 +- .../address/testutil/TypicalActivities.java | 7 +- 15 files changed, 255 insertions(+), 26 deletions(-) create mode 100644 src/test/data/ImportCommandTest/duplicateActivity.xml create mode 100644 src/test/data/ImportCommandTest/illegalValues.xml create mode 100644 src/test/data/ImportCommandTest/validImportFile.xml rename src/test/data/XmlDeskBoardStorageTest/{NotXmlFormatDeskBoard.xml => notXmlFormatDeskBoard.xml} (100%) create mode 100644 src/test/java/seedu/address/logic/commands/ImportCommandTest.java diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index 575a84d36a57..06058362ea5e 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -3,11 +3,13 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; +import java.io.File; import java.io.IOException; import seedu.address.commons.exceptions.DataConversionException; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.DeskBoard; +import seedu.address.model.ModelManager; import seedu.address.model.ReadOnlyDeskBoard; import seedu.address.model.activity.Activity; import seedu.address.model.activity.exceptions.DuplicateActivityException; @@ -28,12 +30,12 @@ public class ImportCommand extends UndoableCommand { + PREFIX_FILE_PATH + "C:\\Users\\Karen\\IdeaProjects\\main\\data\\deskboard.xml"; public static final String MESSAGE_DUPLICATE_ACTIVITY = "The following entry already exists in the desk board: %s"; - public static final String MESSAGE_FILE_NOT_FOUND = "Desk board file not found"; + public static final String MESSAGE_FILE_NOT_FOUND = "Desk board file %s not found"; public static final String MESSAGE_ILLEGAL_VALUES_IN_FILE = "Illegal values found in file: %s"; public static final String MESSAGE_SUCCESS = "Data imported from: %1$s"; private final String filePath; - private ReadOnlyDeskBoard importedDeskBoard; + private ReadOnlyDeskBoard toImport; /** * Creates an ImportCommand to import data from the specified {@code filePath}. @@ -45,21 +47,16 @@ public ImportCommand(String filePath) { @Override public CommandResult executeUndoableCommand() throws CommandException { - requireNonNull(model); try { - importedDeskBoard = new XmlDeskBoardStorage(filePath).readDeskBoard().orElse(new DeskBoard()); + toImport = new XmlDeskBoardStorage(filePath).readDeskBoard() + .orElseThrow(() -> new CommandException(String.format(MESSAGE_FILE_NOT_FOUND, filePath))); } catch (IOException ioe) { - throw new CommandException(MESSAGE_FILE_NOT_FOUND); + throw new CommandException(String.format(MESSAGE_FILE_NOT_FOUND, filePath)); } catch (DataConversionException dce) { throw new CommandException(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, dce.getMessage())); } - for (Activity activity : importedDeskBoard.getActivityList()) { - try { - model.addActivity(activity); - } catch (DuplicateActivityException dae) { - throw new CommandException(String.format(MESSAGE_DUPLICATE_ACTIVITY, activity)); - } - } + requireNonNull(model); + model.addActivities(toImport); return new CommandResult(String.format(MESSAGE_SUCCESS, filePath)); } diff --git a/src/main/java/seedu/address/model/DeskBoard.java b/src/main/java/seedu/address/model/DeskBoard.java index 5624e061262e..3eba5559b2bd 100644 --- a/src/main/java/seedu/address/model/DeskBoard.java +++ b/src/main/java/seedu/address/model/DeskBoard.java @@ -94,6 +94,28 @@ public void addActivity(Activity p) throws DuplicateActivityException { activities.add(activity); } + //@@author karenfrilya97 + /** + * Adds all activities from UniqueActivityList {@code activities} to the desk board. + * Also checks each new activity's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the activity to point to those in {@link #tags}. + * + * If an equivalent activity already exists, that activity will be ignored. + */ + public void addActivities(List toAdd) { + for (Activity activity : toAdd) { + activity = syncWithMasterTagList(activity); + // TODO: the tags master list will be updated even though the below line fails. + // This can cause the tags master list to have additional tags that are not tagged to any activity + // in the activity list. + try { + activities.add(activity); + } catch (DuplicateActivityException e) { + // Ignore duplicate activity. + } + } + } + /** * Replaces the given activity {@code target} in the list with {@code editedActivity}. * {@code DeskBoard}'s tag list will be updated with the tags of {@code editedActivity}. diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index a9f907c526e9..affc850132be 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -1,5 +1,6 @@ package seedu.address.model; +import java.util.List; import java.util.function.Predicate; import javafx.collections.ObservableList; @@ -27,6 +28,10 @@ public interface Model { /** Adds the given activity */ void addActivity(Activity activity) throws DuplicateActivityException; + //@@author karenfrilya97 + void addActivities(ReadOnlyDeskBoard deskBoard); + + //@@author YuanQQLer /** * Replaces the given activity {@code target} with {@code editedActivity}. * diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 3d1c25f000cb..b0eb4866e757 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -48,7 +48,7 @@ public ModelManager() { @Override public void resetData(ReadOnlyDeskBoard newData) { deskBoard.resetData(newData); - indicateAddressBookChanged(); + indicateDeskBoardChanged(); } @Override @@ -57,30 +57,39 @@ public ReadOnlyDeskBoard getDeskBoard() { } /** Raises an event to indicate the model has changed */ - private void indicateAddressBookChanged() { + private void indicateDeskBoardChanged() { raise(new DeskBoardChangedEvent(deskBoard)); } @Override public synchronized void deleteActivity(Activity target) throws ActivityNotFoundException { deskBoard.removeActivity(target); - indicateAddressBookChanged(); + indicateDeskBoardChanged(); } @Override public synchronized void addActivity(Activity activity) throws DuplicateActivityException { deskBoard.addActivity(activity); updateFilteredActivityList(PREDICATE_SHOW_ALL_ACTIVITY); - indicateAddressBookChanged(); + indicateDeskBoardChanged(); } + //@@author karenfrilya97 + /** Adds all activities in the given desk board, except for those already found in the existing desk board*/ + public synchronized void addActivities(ReadOnlyDeskBoard otherDeskBoard) { + deskBoard.addActivities(otherDeskBoard.getActivityList()); + updateFilteredActivityList(PREDICATE_SHOW_ALL_ACTIVITY); + indicateDeskBoardChanged(); + } + + //@@author YuanQQLer @Override public synchronized void updateActivity(Activity target, Activity editedActivity) throws DuplicateActivityException, ActivityNotFoundException { requireAllNonNull(target, editedActivity); deskBoard.updateActivity(target, editedActivity); - indicateAddressBookChanged(); + indicateDeskBoardChanged(); } //=========== Filtered Activity List Accessors ============================================================= diff --git a/src/main/java/seedu/address/model/activity/UniqueActivityList.java b/src/main/java/seedu/address/model/activity/UniqueActivityList.java index 6e6156de9b20..c51436bf3998 100644 --- a/src/main/java/seedu/address/model/activity/UniqueActivityList.java +++ b/src/main/java/seedu/address/model/activity/UniqueActivityList.java @@ -26,7 +26,6 @@ */ public class UniqueActivityList implements Iterable { - //@@author karenfrilya97 private static DateTimeComparator dateTimeComparator = new DateTimeComparator(); private final ObservableList internalList = FXCollections.observableArrayList(); @@ -41,7 +40,7 @@ public boolean contains(Activity toCheck) { /** - * Adds a activity to the list. + * Adds an activity to the list. * If activity is a task or an event, is added to its respective list. * * @throws DuplicateActivityException if the activity to add is a duplicate of an existing activity in the list. @@ -56,6 +55,22 @@ public void add(Activity toAdd) throws DuplicateActivityException { Collections.sort(internalList, dateTimeComparator); } + //@@author karenfrilya97 + /** + * Adds all activities from another UniqueActivityList {@code activities} to the list. + * If an activity in {@code activities} is already in the {@code internalList}, + * then that particular activity will not be added, but other activities will still be added to the list. + */ + public void addAll(UniqueActivityList activities) { + requireNonNull(activities); + for (Activity activity : activities) { + if (!contains(activity)) { + internalList.add(activity); + } + } + Collections.sort(internalList, dateTimeComparator); + } + /** * Replaces the activity {@code target} in the list with {@code editedActivity}. * If activity is a task or an event, edited in its respective list. diff --git a/src/test/data/ImportCommandTest/duplicateActivity.xml b/src/test/data/ImportCommandTest/duplicateActivity.xml new file mode 100644 index 000000000000..d317ffb587aa --- /dev/null +++ b/src/test/data/ImportCommandTest/duplicateActivity.xml @@ -0,0 +1,32 @@ + + + + CS2102Assignment + 01/04/2018 20:00 + nil + CS2102 + + + CS2102ProjectDemo + 04/04/2018 09:00 + 04/04/2018 10:00 + COM1 + FinalDemo + CS2102 + + + CS2101Assignment + 04/03/2018 23:59 + + CS2101 + + + CCA + 01/04/2018 20:00 + 01/04/2018 21:00 + Campus + nil + + CS2101 + CS2102 + diff --git a/src/test/data/ImportCommandTest/illegalValues.xml b/src/test/data/ImportCommandTest/illegalValues.xml new file mode 100644 index 000000000000..be0e189135f9 --- /dev/null +++ b/src/test/data/ImportCommandTest/illegalValues.xml @@ -0,0 +1 @@ +illegal values \ No newline at end of file diff --git a/src/test/data/ImportCommandTest/validImportFile.xml b/src/test/data/ImportCommandTest/validImportFile.xml new file mode 100644 index 000000000000..6aad2ddac003 --- /dev/null +++ b/src/test/data/ImportCommandTest/validImportFile.xml @@ -0,0 +1,18 @@ + + + + CS2102Assignment + 01/04/2018 20:00 + nil + CS2102 + + + CS2102ProjectDemo + 04/04/2018 09:00 + 04/04/2018 10:00 + COM1 + FinalDemo + CS2102 + + CS2102 + diff --git a/src/test/data/XmlDeskBoardStorageTest/NotXmlFormatDeskBoard.xml b/src/test/data/XmlDeskBoardStorageTest/notXmlFormatDeskBoard.xml similarity index 100% rename from src/test/data/XmlDeskBoardStorageTest/NotXmlFormatDeskBoard.xml rename to src/test/data/XmlDeskBoardStorageTest/notXmlFormatDeskBoard.xml diff --git a/src/test/java/seedu/address/commons/util/XmlUtilTest.java b/src/test/java/seedu/address/commons/util/XmlUtilTest.java index 922cb586131d..3a99cc20e4ce 100644 --- a/src/test/java/seedu/address/commons/util/XmlUtilTest.java +++ b/src/test/java/seedu/address/commons/util/XmlUtilTest.java @@ -83,8 +83,7 @@ public void getDataFromFile_emptyFile_dataFormatMismatchException() throws Excep XmlUtil.getDataFromFile(EMPTY_FILE, DeskBoard.class); } - //TODO: TEST - //@Test + @Test public void getDataFromFile_validFile_validResult() throws Exception { DeskBoard dataFromFile = XmlUtil.getDataFromFile(VALID_FILE, XmlSerializableDeskBoard.class).toModelType(); assertEquals(7, dataFromFile.getActivityList().size()); diff --git a/src/test/java/seedu/address/logic/commands/EventCommandTest.java b/src/test/java/seedu/address/logic/commands/EventCommandTest.java index 5a46d1229766..18351b16efe5 100644 --- a/src/test/java/seedu/address/logic/commands/EventCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/EventCommandTest.java @@ -88,7 +88,7 @@ public void equals() { /** * Generates a new EventCommand with the details of the given event. */ - private EventCommand getEventCommandForGivenEvent(Event event, Model model) { + EventCommand getEventCommandForGivenEvent(Event event, Model model) { EventCommand command = new EventCommand(event); command.setData(model, new CommandHistory(), new UndoRedoStack()); return command; @@ -103,6 +103,11 @@ public void addActivity(Activity activity) throws DuplicateActivityException { fail("This method should not be called."); } + @Override + public void addActivities(ReadOnlyDeskBoard deskBoard) { + fail("This method should not be called."); + } + @Override public void resetData(ReadOnlyDeskBoard newData) { fail("This method should not be called."); diff --git a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java new file mode 100644 index 000000000000..3484124c4ed3 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java @@ -0,0 +1,118 @@ +package seedu.address.logic.commands; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static seedu.address.logic.commands.ImportCommand.MESSAGE_FILE_NOT_FOUND; +import static seedu.address.logic.commands.ImportCommand.MESSAGE_ILLEGAL_VALUES_IN_FILE; +import static seedu.address.testutil.TypicalActivities.ASSIGNMENT3; +import static seedu.address.testutil.TypicalActivities.DEMO1; +import static seedu.address.testutil.TypicalActivities.getTypicalDeskBoard; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import seedu.address.commons.util.FileUtil; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.UndoRedoStack; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; + +//@@author karenfrilya97 +public class ImportCommandTest { + + private static final String TEST_DATA_FOLDER = FileUtil.getPath("src/test/data/ImportCommandTest/"); + private static final String ASSIGNMENT3_DEMO1_FILE_PATH = TEST_DATA_FOLDER + "validImportFile.xml"; + private static final String MISSING_FILE_PATH = TEST_DATA_FOLDER + "missing.xml"; + private static final String ILLEGAL_VALUES_FILE_PATH = TEST_DATA_FOLDER + "illegalValues.xml"; + private static final String DUPLICATE_ACTIVITY_FILE_PATH = TEST_DATA_FOLDER + "duplicateActivity.xml"; + + private Model validModel = new ModelManager(getTypicalDeskBoard(), new UserPrefs()); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void constructor_nullFilePath_throwsNullPointerException() { + thrown.expect(NullPointerException.class); + new ImportCommand(null); + } + + @Test + public void execute_validFilePathValidModel_success() throws CommandException { + TaskCommand taskCommand = new TaskCommandTest().getTaskCommandForGivenTask(ASSIGNMENT3, validModel); + taskCommand.executeUndoableCommand(); + EventCommand eventCommand = new EventCommandTest().getEventCommandForGivenEvent(DEMO1, taskCommand.model); + eventCommand.executeUndoableCommand(); + + ImportCommand importCommand = getImportCommandForGivenFilePath(ASSIGNMENT3_DEMO1_FILE_PATH, validModel); + importCommand.executeUndoableCommand(); + + assertEquals(eventCommand.model.getDeskBoard(), importCommand.model.getDeskBoard()); + } + + @Test + public void execute_nonexistentFilePath_throwsCommandException() throws CommandException { + thrown.expect(CommandException.class); + thrown.expectMessage(String.format(MESSAGE_FILE_NOT_FOUND, MISSING_FILE_PATH)); + ImportCommand importCommand = getImportCommandForGivenFilePath(MISSING_FILE_PATH, validModel); + importCommand.executeUndoableCommand(); + } + + @Test + public void execute_illegalValuesInFile_throwsCommandException() throws CommandException { + thrown.expect(CommandException.class); + thrown.expectMessage(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, "javax.xml.bind.UnmarshalException\n" + + " - with linked exception")); + ImportCommand importCommand = getImportCommandForGivenFilePath(ILLEGAL_VALUES_FILE_PATH, validModel); + importCommand.executeUndoableCommand(); + } + + @Test + // The file to import contains one existing activity and a few new activities. + // The existing activity should be ignored while the rest added into existing desk board. + public void execute_fileContainsExistingActivity_ignoresDuplicateActivity() throws CommandException { + ImportCommand withDuplicate = getImportCommandForGivenFilePath(DUPLICATE_ACTIVITY_FILE_PATH, validModel); + withDuplicate.executeUndoableCommand(); + ImportCommand withoutDuplicate = getImportCommandForGivenFilePath(ASSIGNMENT3_DEMO1_FILE_PATH, validModel); + withoutDuplicate.executeUndoableCommand(); + assertEquals(withDuplicate.model.getDeskBoard(), withoutDuplicate.model.getDeskBoard()); + } + + @Test + public void equals() { + String filePath = TEST_DATA_FOLDER + "deskBoard.xml"; + String differentFilePath = TEST_DATA_FOLDER + "differentDeskBoard.xml"; + + ImportCommand importCommand = new ImportCommand(filePath); + ImportCommand differentImportCommand = new ImportCommand(differentFilePath); + + // same object -> returns true + assertTrue(importCommand.equals(importCommand)); + + // same values -> returns true + ImportCommand importAssignmentCommandCopy = new ImportCommand(filePath); + assertTrue(importCommand.equals(importAssignmentCommandCopy)); + + // null -> returns false + assertFalse(importCommand.equals(null)); + + // different types -> returns false + assertFalse(importCommand.equals(1)); + + // different file path -> returns false + assertFalse(importCommand.equals(differentImportCommand)); + } + + /** + * Generates a new ImportCommand with the given file path. + */ + private ImportCommand getImportCommandForGivenFilePath(String filePath, Model model) { + ImportCommand command = new ImportCommand(filePath); + command.setData(model, new CommandHistory(), new UndoRedoStack()); + return command; + } +} diff --git a/src/test/java/seedu/address/logic/commands/TaskCommandTest.java b/src/test/java/seedu/address/logic/commands/TaskCommandTest.java index 61f90ef81d28..e4507da055ed 100644 --- a/src/test/java/seedu/address/logic/commands/TaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/TaskCommandTest.java @@ -88,7 +88,7 @@ public void equals() { /** * Generates a new TaskCommand with the details of the given task. */ - private TaskCommand getTaskCommandForGivenTask(Task task, Model model) { + TaskCommand getTaskCommandForGivenTask(Task task, Model model) { TaskCommand command = new TaskCommand(task); command.setData(model, new CommandHistory(), new UndoRedoStack()); return command; @@ -103,6 +103,11 @@ public void addActivity(Activity activity) throws DuplicateActivityException { fail("This method should not be called."); } + @Override + public void addActivities(ReadOnlyDeskBoard deskBoard) { + fail("This method should not be called."); + } + @Override public void resetData(ReadOnlyDeskBoard newData) { fail("This method should not be called."); diff --git a/src/test/java/seedu/address/storage/XmlDeskBoardStorageTest.java b/src/test/java/seedu/address/storage/XmlDeskBoardStorageTest.java index a8e14c48e534..1c9f60f9f3c5 100644 --- a/src/test/java/seedu/address/storage/XmlDeskBoardStorageTest.java +++ b/src/test/java/seedu/address/storage/XmlDeskBoardStorageTest.java @@ -52,7 +52,7 @@ public void read_missingFile_emptyResult() throws Exception { public void read_notXmlFormat_exceptionThrown() throws Exception { thrown.expect(DataConversionException.class); - readDeskBoard("NotXmlFormatDeskBoard.xml"); + readDeskBoard("notXmlFormatDeskBoard.xml"); /* IMPORTANT: Any code below an exception-throwing line (like the one above) will be ignored. * That means you should not have more than one exception test in one method diff --git a/src/test/java/seedu/address/testutil/TypicalActivities.java b/src/test/java/seedu/address/testutil/TypicalActivities.java index bf87765393cd..3e6424b49ce6 100644 --- a/src/test/java/seedu/address/testutil/TypicalActivities.java +++ b/src/test/java/seedu/address/testutil/TypicalActivities.java @@ -53,11 +53,14 @@ public class TypicalActivities { // Manually added public static final Task ASSIGNMENT3 = new TaskBuilder().withName("CS2102Assignment") .withDateTime("01/04/2018 20:00") - .withRemark("nil").build(); + .withRemark("nil") + .withTags("CS2102").build(); public static final Event DEMO1 = new EventBuilder().withName("CS2102ProjectDemo") .withStartDateTime("04/04/2018 09:00") .withEndDateTime("04/04/2018 10:00") - .withRemark("FinalDemo").build(); + .withLocation("COM1") + .withRemark("FinalDemo") + .withTags("CS2102").build(); public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER From a0f74d93ed419f8acefd30929a91a674bfecd03f Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Sat, 7 Apr 2018 17:08:51 +0800 Subject: [PATCH 07/19] Resolve merge conflict --- docs/UserGuide.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 51d7c018a8e2..c313a3bd544d 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -274,8 +274,8 @@ e.g. `task n/Software Engineering Milestone 1 d/16/03/2018 17:00 r/urgent` * *Add event*: `event n/NAME s/START_TIME e/END_TIME [l/LOCATION] [r/REMARK]` + e.g. `event n/Software Project s/1/5/2018 8:00 e/01/08/2018 8:00 l/School of Computing r/remember to bring laptop charger` -* *List uncompleted tasks and upcoming events*: `ls` + -e.g. `ls` or `ls task` or `ls event` +* *List uncompleted tasks and upcoming events*: `list` or `ls` + +e.g. `list` or `ls` or `list task` or `ls event` * *Remove task or event*: `rm` + e.g. `rm task 1` or `rm event 2` From a41487c30cbf9810069910668fa63a377c0f4fdf Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 15:14:09 +0800 Subject: [PATCH 08/19] Fix unused import --- .../java/seedu/address/logic/commands/ImportCommand.java | 5 ----- src/main/java/seedu/address/model/Model.java | 1 - 2 files changed, 6 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index 06058362ea5e..34a7317e7f53 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -3,16 +3,11 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; -import java.io.File; import java.io.IOException; import seedu.address.commons.exceptions.DataConversionException; import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.DeskBoard; -import seedu.address.model.ModelManager; import seedu.address.model.ReadOnlyDeskBoard; -import seedu.address.model.activity.Activity; -import seedu.address.model.activity.exceptions.DuplicateActivityException; import seedu.address.storage.XmlDeskBoardStorage; //@@author karenfrilya97 diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 153d3aadc6b2..94cda2067852 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -1,6 +1,5 @@ package seedu.address.model; -import java.util.List; import java.util.function.Predicate; import javafx.collections.ObservableList; From 364b69a818b701de4e8e4956850ff145b6c35a84 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 15:44:48 +0800 Subject: [PATCH 09/19] Fix checkstyle error --- .../address/logic/commands/ImportCommandTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java index 3484124c4ed3..526f15756e45 100644 --- a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java @@ -24,6 +24,9 @@ //@@author karenfrilya97 public class ImportCommandTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + private static final String TEST_DATA_FOLDER = FileUtil.getPath("src/test/data/ImportCommandTest/"); private static final String ASSIGNMENT3_DEMO1_FILE_PATH = TEST_DATA_FOLDER + "validImportFile.xml"; private static final String MISSING_FILE_PATH = TEST_DATA_FOLDER + "missing.xml"; @@ -32,9 +35,6 @@ public class ImportCommandTest { private Model validModel = new ModelManager(getTypicalDeskBoard(), new UserPrefs()); - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void constructor_nullFilePath_throwsNullPointerException() { thrown.expect(NullPointerException.class); @@ -65,8 +65,8 @@ public void execute_nonexistentFilePath_throwsCommandException() throws CommandE @Test public void execute_illegalValuesInFile_throwsCommandException() throws CommandException { thrown.expect(CommandException.class); - thrown.expectMessage(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, "javax.xml.bind.UnmarshalException\n" + - " - with linked exception")); + thrown.expectMessage(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, "javax.xml.bind.UnmarshalException\n" + + " - with linked exception")); ImportCommand importCommand = getImportCommandForGivenFilePath(ILLEGAL_VALUES_FILE_PATH, validModel); importCommand.executeUndoableCommand(); } From d2c2229ebb4fc6b674ad706c7a1da1cbe27d6011 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 15:51:39 +0800 Subject: [PATCH 10/19] Add newline at end of file --- src/test/data/ImportCommandTest/illegalValues.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/data/ImportCommandTest/illegalValues.xml b/src/test/data/ImportCommandTest/illegalValues.xml index be0e189135f9..79ec28f42fd5 100644 --- a/src/test/data/ImportCommandTest/illegalValues.xml +++ b/src/test/data/ImportCommandTest/illegalValues.xml @@ -1 +1 @@ -illegal values \ No newline at end of file +illegal values From 103c126b033a567ff93d649f33442855cf0dc3c4 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 15:56:33 +0800 Subject: [PATCH 11/19] Fix checkstyle error --- .../seedu/address/logic/commands/ImportCommandTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java index 526f15756e45..ded868da4664 100644 --- a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java @@ -24,15 +24,15 @@ //@@author karenfrilya97 public class ImportCommandTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - private static final String TEST_DATA_FOLDER = FileUtil.getPath("src/test/data/ImportCommandTest/"); private static final String ASSIGNMENT3_DEMO1_FILE_PATH = TEST_DATA_FOLDER + "validImportFile.xml"; private static final String MISSING_FILE_PATH = TEST_DATA_FOLDER + "missing.xml"; private static final String ILLEGAL_VALUES_FILE_PATH = TEST_DATA_FOLDER + "illegalValues.xml"; private static final String DUPLICATE_ACTIVITY_FILE_PATH = TEST_DATA_FOLDER + "duplicateActivity.xml"; + @Rule + public ExpectedException thrown = ExpectedException.none(); + private Model validModel = new ModelManager(getTypicalDeskBoard(), new UserPrefs()); @Test From 83b995fba0574649108ba9ba0562f0cefcf10c4f Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 18:57:02 +0800 Subject: [PATCH 12/19] Add ImportCommandParserTest and use FilePath as import parameter instead of String --- .../address/logic/commands/ImportCommand.java | 17 +++--- .../logic/parser/ImportCommandParser.java | 14 +++-- .../address/logic/parser/ParserUtil.java | 25 ++++++++ .../java/seedu/address/model/FilePath.java | 54 ++++++++++++++++++ .../logic/commands/CommandTestUtil.java | 12 ++++ .../logic/commands/ImportCommandTest.java | 21 ++++--- .../logic/parser/ImportCommandParserTest.java | 57 +++++++++++++++++++ 7 files changed, 177 insertions(+), 23 deletions(-) create mode 100644 src/main/java/seedu/address/model/FilePath.java create mode 100644 src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index 34a7317e7f53..31af1d6de60d 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -7,6 +7,8 @@ import seedu.address.commons.exceptions.DataConversionException; import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.DeskBoard; +import seedu.address.model.FilePath; import seedu.address.model.ReadOnlyDeskBoard; import seedu.address.storage.XmlDeskBoardStorage; @@ -24,35 +26,34 @@ public class ImportCommand extends UndoableCommand { + "Example: " + COMMAND_WORD + " " + PREFIX_FILE_PATH + "C:\\Users\\Karen\\IdeaProjects\\main\\data\\deskboard.xml"; - public static final String MESSAGE_DUPLICATE_ACTIVITY = "The following entry already exists in the desk board: %s"; public static final String MESSAGE_FILE_NOT_FOUND = "Desk board file %s not found"; public static final String MESSAGE_ILLEGAL_VALUES_IN_FILE = "Illegal values found in file: %s"; public static final String MESSAGE_SUCCESS = "Data imported from: %1$s"; - private final String filePath; - private ReadOnlyDeskBoard toImport; + private final FilePath filePath; /** * Creates an ImportCommand to import data from the specified {@code filePath}. */ - public ImportCommand(String filePath) { + public ImportCommand(FilePath filePath) { requireNonNull(filePath); this.filePath = filePath; } @Override public CommandResult executeUndoableCommand() throws CommandException { + requireNonNull(model); try { - toImport = new XmlDeskBoardStorage(filePath).readDeskBoard() + ReadOnlyDeskBoard toImport = new XmlDeskBoardStorage(filePath.value).readDeskBoard() .orElseThrow(() -> new CommandException(String.format(MESSAGE_FILE_NOT_FOUND, filePath))); + + model.addActivities(toImport); + return new CommandResult(String.format(MESSAGE_SUCCESS, filePath)); } catch (IOException ioe) { throw new CommandException(String.format(MESSAGE_FILE_NOT_FOUND, filePath)); } catch (DataConversionException dce) { throw new CommandException(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, dce.getMessage())); } - requireNonNull(model); - model.addActivities(toImport); - return new CommandResult(String.format(MESSAGE_SUCCESS, filePath)); } @Override diff --git a/src/main/java/seedu/address/logic/parser/ImportCommandParser.java b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java index fa6b78bd1e97..2aeb18dbbefe 100644 --- a/src/main/java/seedu/address/logic/parser/ImportCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java @@ -5,8 +5,10 @@ import java.util.stream.Stream; +import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.logic.commands.ImportCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.FilePath; //@@author karenfrilya97 /** @@ -17,8 +19,9 @@ public class ImportCommandParser implements Parser { /** * Parses the given {@code String} of arguments in the context of the ImportCommand * and returns an ImportCommand object for execution. - * @throws ParseException if the user input does not conform the expected format + * @throws ParseException if the user input does not conform the expected format. */ + public ImportCommand parse(String args) throws ParseException { ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_FILE_PATH); @@ -28,8 +31,12 @@ public ImportCommand parse(String args) throws ParseException { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE)); } - String filePath = argMultimap.getValue(PREFIX_FILE_PATH).orElse(""); - return new ImportCommand(filePath); + try { + FilePath filePath = ParserUtil.parseFilePath(argMultimap.getValue(PREFIX_FILE_PATH)).get(); + return new ImportCommand(filePath); + } catch (IllegalValueException ive) { + throw new ParseException(ive.getMessage(), ive); + } } /** @@ -41,4 +48,3 @@ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Pre } } - diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 707c897cc129..a6eadcfdeb4a 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -10,6 +10,7 @@ import seedu.address.commons.core.index.Index; import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.commons.util.StringUtil; +import seedu.address.model.FilePath; import seedu.address.model.activity.DateTime; import seedu.address.model.activity.Location; import seedu.address.model.activity.Name; @@ -170,4 +171,28 @@ public static Set parseTags(Collection tags) throws IllegalValueExc return tagSet; } + //@@author karenfrilya97 + /** + * Parses a {@code String filePath} into a {@code FilePath}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws IllegalValueException if the given {@code filePath} is invalid. + */ + public static FilePath parseFilePath(String filePath) throws IllegalValueException { + requireNonNull(filePath); + String trimmedFilePath = filePath.trim(); + if (!FilePath.isValidFilePath(trimmedFilePath)) { + throw new IllegalValueException(FilePath.MESSAGE_FILE_PATH_CONSTRAINTS); + } + return new FilePath(trimmedFilePath); + } + + /** + * Parses an {@code Optional filePath} into an {@code Optional} if {@code filePath} is present. + * See header comment of this class regarding the use of {@code Optional} parameters. + */ + public static Optional parseFilePath(Optional filePath) throws IllegalValueException { + requireNonNull(filePath); + return filePath.isPresent() ? Optional.of(parseFilePath(filePath.get())) : Optional.empty(); + } } diff --git a/src/main/java/seedu/address/model/FilePath.java b/src/main/java/seedu/address/model/FilePath.java new file mode 100644 index 000000000000..2316673a92fc --- /dev/null +++ b/src/main/java/seedu/address/model/FilePath.java @@ -0,0 +1,54 @@ +package seedu.address.model; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +//@@author karenfrilya97 +/** + * Represents a Desk Board's file path. + * Guarantees: immutable; is valid as declared in {@link #isValidFilePath(String)} + */ +public class FilePath { + + public static final String MESSAGE_FILE_PATH_CONSTRAINTS = + "Desk Board file path should not be blank."; + + public static final String FILE_PATH_VALIDATION_REGEX = ".+" + ".xml"; + + public final String value; + + /** + * Constructs a {@code FilePath}. + * + * @param filePath A valid file path. + */ + public FilePath (String filePath) { + requireNonNull(filePath); + checkArgument(isValidFilePath(filePath), MESSAGE_FILE_PATH_CONSTRAINTS); + this.value = filePath; + } + + /** + * Returns true if a given string is a valid Desk Board file path. + */ + public static boolean isValidFilePath(String filePath) { + return filePath.matches(FILE_PATH_VALIDATION_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof FilePath // instanceof handles nulls + && this.value.equals(((FilePath) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index a0fdff35f9ec..786778a1164b 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_FILE_PATH; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_REMARK; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; @@ -61,6 +62,17 @@ public class CommandTestUtil { // ============================= EVENT ============================================= //TODO: Tedious + //@@author karenfrilya97 + // ============================= IMPORT ============================================ + public static final String TEST_DATA_FOLDER = "src\\test\\data\\ImportCommandTest\\"; + public static final String ASSIGNMENT3_DEMO1_FILE_PATH = TEST_DATA_FOLDER + "validImportFile.xml"; + public static final String MISSING_FILE_PATH = TEST_DATA_FOLDER + "missing.xml"; + public static final String ILLEGAL_VALUES_FILE_PATH = TEST_DATA_FOLDER + "illegalValues.xml"; + public static final String DUPLICATE_ACTIVITY_FILE_PATH = TEST_DATA_FOLDER + "duplicateActivity.xml"; + public static final String FILE_PATH_DESC_VALID = " " + PREFIX_FILE_PATH + ASSIGNMENT3_DEMO1_FILE_PATH; + public static final String FILE_PATH_DESC_DUPLICATE = " " + PREFIX_FILE_PATH + DUPLICATE_ACTIVITY_FILE_PATH; + public static final String INVALID_FILE_PATH_DESC = " " + PREFIX_FILE_PATH + "no.xmlAtTheEnd"; + //@@author public static final String PREAMBLE_WHITESPACE = "\t \r \n"; public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble"; diff --git a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java index ded868da4664..f836c202e230 100644 --- a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java @@ -3,6 +3,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.ASSIGNMENT3_DEMO1_FILE_PATH; +import static seedu.address.logic.commands.CommandTestUtil.DUPLICATE_ACTIVITY_FILE_PATH; +import static seedu.address.logic.commands.CommandTestUtil.ILLEGAL_VALUES_FILE_PATH; +import static seedu.address.logic.commands.CommandTestUtil.MISSING_FILE_PATH; +import static seedu.address.logic.commands.CommandTestUtil.TEST_DATA_FOLDER; import static seedu.address.logic.commands.ImportCommand.MESSAGE_FILE_NOT_FOUND; import static seedu.address.logic.commands.ImportCommand.MESSAGE_ILLEGAL_VALUES_IN_FILE; import static seedu.address.testutil.TypicalActivities.ASSIGNMENT3; @@ -13,10 +18,10 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.commons.util.FileUtil; import seedu.address.logic.CommandHistory; import seedu.address.logic.UndoRedoStack; import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.FilePath; import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; @@ -24,12 +29,6 @@ //@@author karenfrilya97 public class ImportCommandTest { - private static final String TEST_DATA_FOLDER = FileUtil.getPath("src/test/data/ImportCommandTest/"); - private static final String ASSIGNMENT3_DEMO1_FILE_PATH = TEST_DATA_FOLDER + "validImportFile.xml"; - private static final String MISSING_FILE_PATH = TEST_DATA_FOLDER + "missing.xml"; - private static final String ILLEGAL_VALUES_FILE_PATH = TEST_DATA_FOLDER + "illegalValues.xml"; - private static final String DUPLICATE_ACTIVITY_FILE_PATH = TEST_DATA_FOLDER + "duplicateActivity.xml"; - @Rule public ExpectedException thrown = ExpectedException.none(); @@ -84,8 +83,8 @@ public void execute_fileContainsExistingActivity_ignoresDuplicateActivity() thro @Test public void equals() { - String filePath = TEST_DATA_FOLDER + "deskBoard.xml"; - String differentFilePath = TEST_DATA_FOLDER + "differentDeskBoard.xml"; + FilePath filePath = new FilePath(TEST_DATA_FOLDER + "deskBoard.xml"); + FilePath differentFilePath = new FilePath(TEST_DATA_FOLDER + "differentDeskBoard.xml"); ImportCommand importCommand = new ImportCommand(filePath); ImportCommand differentImportCommand = new ImportCommand(differentFilePath); @@ -110,8 +109,8 @@ public void equals() { /** * Generates a new ImportCommand with the given file path. */ - private ImportCommand getImportCommandForGivenFilePath(String filePath, Model model) { - ImportCommand command = new ImportCommand(filePath); + private ImportCommand getImportCommandForGivenFilePath(String filePathString, Model model) { + ImportCommand command = new ImportCommand(new FilePath(filePathString)); command.setData(model, new CommandHistory(), new UndoRedoStack()); return command; } diff --git a/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java b/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java new file mode 100644 index 000000000000..c8d4248c19ad --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java @@ -0,0 +1,57 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.commands.CommandTestUtil.ASSIGNMENT3_DEMO1_FILE_PATH; +import static seedu.address.logic.commands.CommandTestUtil.FILE_PATH_DESC_DUPLICATE; +import static seedu.address.logic.commands.CommandTestUtil.FILE_PATH_DESC_VALID; +import static seedu.address.logic.commands.CommandTestUtil.INVALID_FILE_PATH_DESC; +import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY; +import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import org.junit.Test; + +import seedu.address.logic.commands.ImportCommand; +import seedu.address.model.FilePath; + +//@@author karenfrilya97 +public class ImportCommandParserTest { + + private ImportCommandParser parser = new ImportCommandParser(); + + @Test + public void parse_filePathPresent_success() { + FilePath filePath = new FilePath(ASSIGNMENT3_DEMO1_FILE_PATH); + + // whitespace only preamble + assertParseSuccess(parser, PREAMBLE_WHITESPACE + FILE_PATH_DESC_VALID, new ImportCommand(filePath)); + + // multiple file paths - last file path accepted + assertParseSuccess(parser, FILE_PATH_DESC_DUPLICATE + FILE_PATH_DESC_VALID, new ImportCommand(filePath)); + + // multiple file paths, the first one being invalid - last file path accepted with no exception thrown + assertParseSuccess(parser, INVALID_FILE_PATH_DESC + FILE_PATH_DESC_VALID, new ImportCommand(filePath)); + } + + @Test + public void parse_filePathMissing_failure() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE); + + // missing file path prefix + assertParseFailure(parser, ASSIGNMENT3_DEMO1_FILE_PATH, expectedMessage); + } + + @Test + public void parse_invalidValue_failure() { + // invalid file path + assertParseFailure(parser, INVALID_FILE_PATH_DESC, FilePath.MESSAGE_FILE_PATH_CONSTRAINTS); + + // multiple file paths, the last one being invalid + assertParseFailure(parser, FILE_PATH_DESC_VALID + INVALID_FILE_PATH_DESC, FilePath.MESSAGE_FILE_PATH_CONSTRAINTS); + + // non-empty preamble + assertParseFailure(parser, PREAMBLE_NON_EMPTY + FILE_PATH_DESC_VALID, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE)); + } +} From 942f5634d00d70a8f22bb575e7a35ce492bc5a1e Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 23:36:47 +0800 Subject: [PATCH 13/19] Fix unused imports --- src/main/java/seedu/address/logic/commands/ImportCommand.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index 31af1d6de60d..c255882f5c6e 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -7,7 +7,6 @@ import seedu.address.commons.exceptions.DataConversionException; import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.DeskBoard; import seedu.address.model.FilePath; import seedu.address.model.ReadOnlyDeskBoard; import seedu.address.storage.XmlDeskBoardStorage; From a0eacc8caf71d5882281a8f924b6978efbd7ceb6 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Tue, 10 Apr 2018 23:41:16 +0800 Subject: [PATCH 14/19] Fix LineLength error --- .../seedu/address/logic/parser/ImportCommandParserTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java b/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java index c8d4248c19ad..ac4e302777ae 100644 --- a/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/ImportCommandParserTest.java @@ -48,7 +48,8 @@ public void parse_invalidValue_failure() { assertParseFailure(parser, INVALID_FILE_PATH_DESC, FilePath.MESSAGE_FILE_PATH_CONSTRAINTS); // multiple file paths, the last one being invalid - assertParseFailure(parser, FILE_PATH_DESC_VALID + INVALID_FILE_PATH_DESC, FilePath.MESSAGE_FILE_PATH_CONSTRAINTS); + assertParseFailure(parser, FILE_PATH_DESC_VALID + INVALID_FILE_PATH_DESC, + FilePath.MESSAGE_FILE_PATH_CONSTRAINTS); // non-empty preamble assertParseFailure(parser, PREAMBLE_NON_EMPTY + FILE_PATH_DESC_VALID, From 268217881066980e37d55336a001bcd770cb8726 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Wed, 11 Apr 2018 00:10:26 +0800 Subject: [PATCH 15/19] Edit ImportCommandTest data --- src/test/data/ImportCommandTest/duplicateActivity.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/data/ImportCommandTest/duplicateActivity.xml b/src/test/data/ImportCommandTest/duplicateActivity.xml index d317ffb587aa..1322d1ab13ca 100644 --- a/src/test/data/ImportCommandTest/duplicateActivity.xml +++ b/src/test/data/ImportCommandTest/duplicateActivity.xml @@ -17,7 +17,7 @@ CS2101Assignment 04/03/2018 23:59 - + nil CS2101 From 0ac9bc5d3a8402670bf4465b78e656acfc0805ec Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Wed, 11 Apr 2018 01:03:54 +0800 Subject: [PATCH 16/19] Comment test error --- .../seedu/address/logic/commands/ImportCommand.java | 2 +- .../address/logic/commands/ImportCommandTest.java | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java index c255882f5c6e..b207021e2125 100644 --- a/src/main/java/seedu/address/logic/commands/ImportCommand.java +++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java @@ -25,9 +25,9 @@ public class ImportCommand extends UndoableCommand { + "Example: " + COMMAND_WORD + " " + PREFIX_FILE_PATH + "C:\\Users\\Karen\\IdeaProjects\\main\\data\\deskboard.xml"; + public static final String MESSAGE_SUCCESS = "Data imported from: %1$s"; public static final String MESSAGE_FILE_NOT_FOUND = "Desk board file %s not found"; public static final String MESSAGE_ILLEGAL_VALUES_IN_FILE = "Illegal values found in file: %s"; - public static final String MESSAGE_SUCCESS = "Data imported from: %1$s"; private final FilePath filePath; diff --git a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java index f836c202e230..29d5dd1a2da4 100644 --- a/src/test/java/seedu/address/logic/commands/ImportCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ImportCommandTest.java @@ -40,7 +40,9 @@ public void constructor_nullFilePath_throwsNullPointerException() { new ImportCommand(null); } - @Test + /** + * Test + */ public void execute_validFilePathValidModel_success() throws CommandException { TaskCommand taskCommand = new TaskCommandTest().getTaskCommandForGivenTask(ASSIGNMENT3, validModel); taskCommand.executeUndoableCommand(); @@ -61,7 +63,9 @@ public void execute_nonexistentFilePath_throwsCommandException() throws CommandE importCommand.executeUndoableCommand(); } - @Test + /** + * Test + */ public void execute_illegalValuesInFile_throwsCommandException() throws CommandException { thrown.expect(CommandException.class); thrown.expectMessage(String.format(MESSAGE_ILLEGAL_VALUES_IN_FILE, "javax.xml.bind.UnmarshalException\n" @@ -70,7 +74,9 @@ public void execute_illegalValuesInFile_throwsCommandException() throws CommandE importCommand.executeUndoableCommand(); } - @Test + /** + * Test + */ // The file to import contains one existing activity and a few new activities. // The existing activity should be ignored while the rest added into existing desk board. public void execute_fileContainsExistingActivity_ignoresDuplicateActivity() throws CommandException { From 24d575f682bc82b6358135378299147d1cf7a725 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Wed, 11 Apr 2018 01:33:09 +0800 Subject: [PATCH 17/19] Add Junit tests in DeskBoardTest, DeskBoardParserTest and ModelManagerTest --- src/main/java/seedu/address/model/DeskBoard.java | 1 + .../model/activity/UniqueActivityList.java | 16 ---------------- .../logic/parser/DeskBoardParserTest.java | 14 ++++++++++++++ .../java/seedu/address/model/DeskBoardTest.java | 10 ++++++++++ .../seedu/address/model/ModelManagerTest.java | 15 +++++++++++++++ 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/main/java/seedu/address/model/DeskBoard.java b/src/main/java/seedu/address/model/DeskBoard.java index c8e6fe9214bd..15579bf28470 100644 --- a/src/main/java/seedu/address/model/DeskBoard.java +++ b/src/main/java/seedu/address/model/DeskBoard.java @@ -116,6 +116,7 @@ public void addActivities(List toAdd) { } } + //@@author YuanQLLer /** * Replaces the given activity {@code target} in the list with {@code editedActivity}. * {@code DeskBoard}'s tag list will be updated with the tags of {@code editedActivity}. diff --git a/src/main/java/seedu/address/model/activity/UniqueActivityList.java b/src/main/java/seedu/address/model/activity/UniqueActivityList.java index a0a4f57cfd37..0e7bd3d9dd4d 100644 --- a/src/main/java/seedu/address/model/activity/UniqueActivityList.java +++ b/src/main/java/seedu/address/model/activity/UniqueActivityList.java @@ -55,22 +55,6 @@ public void add(Activity toAdd) throws DuplicateActivityException { Collections.sort(internalList, dateTimeComparator); } - //@@author karenfrilya97 - /** - * Adds all activities from another UniqueActivityList {@code activities} to the list. - * If an activity in {@code activities} is already in the {@code internalList}, - * then that particular activity will not be added, but other activities will still be added to the list. - */ - public void addAll(UniqueActivityList activities) { - requireNonNull(activities); - for (Activity activity : activities) { - if (!contains(activity)) { - internalList.add(activity); - } - } - Collections.sort(internalList, dateTimeComparator); - } - /** * Replaces the activity {@code target} in the list with {@code editedActivity}. * If activity is a task or an event, edited in its respective list. diff --git a/src/test/java/seedu/address/logic/parser/DeskBoardParserTest.java b/src/test/java/seedu/address/logic/parser/DeskBoardParserTest.java index ef6231c079f5..0fa91141717a 100644 --- a/src/test/java/seedu/address/logic/parser/DeskBoardParserTest.java +++ b/src/test/java/seedu/address/logic/parser/DeskBoardParserTest.java @@ -5,6 +5,8 @@ import static org.junit.Assert.assertEquals; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static seedu.address.logic.commands.CommandTestUtil.ASSIGNMENT3_DEMO1_FILE_PATH; +import static seedu.address.logic.commands.CommandTestUtil.FILE_PATH_DESC_VALID; import org.junit.Rule; import org.junit.Test; @@ -14,9 +16,11 @@ import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.EventCommand; import seedu.address.logic.commands.HelpCommand; +import seedu.address.logic.commands.ImportCommand; import seedu.address.logic.commands.ListCommand; import seedu.address.logic.commands.TaskCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.FilePath; import seedu.address.model.activity.Event; import seedu.address.model.activity.Task; import seedu.address.testutil.EventBuilder; @@ -136,6 +140,16 @@ public void parseCommandPlusAlias_list() throws Exception { // assertTrue(parser.parseCommand("undo 3") instanceof UndoCommand); // } // + + //@@author karenfrilya97 + @Test + public void parseCommand_import() throws Exception { + FilePath filePath = new FilePath(ASSIGNMENT3_DEMO1_FILE_PATH); + ImportCommand command = (ImportCommand) parser.parseCommand(ImportCommand.COMMAND_WORD + FILE_PATH_DESC_VALID); + assertEquals(new ImportCommand(filePath), command); + } + + //@@author @Test public void parseCommand_unrecognisedInput_throwsParseException() throws Exception { thrown.expect(ParseException.class); diff --git a/src/test/java/seedu/address/model/DeskBoardTest.java b/src/test/java/seedu/address/model/DeskBoardTest.java index 392e9d4cff3d..66dcf7f48394 100644 --- a/src/test/java/seedu/address/model/DeskBoardTest.java +++ b/src/test/java/seedu/address/model/DeskBoardTest.java @@ -17,6 +17,7 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import seedu.address.model.activity.Activity; +import seedu.address.model.activity.Task; import seedu.address.model.tag.Tag; public class DeskBoardTest { @@ -68,6 +69,15 @@ public void getTagList_modifyList_throwsUnsupportedOperationException() { addressBook.getTagList().remove(0); } + //@@author karenfrilya97 + @Test + public void addActivities_withDuplicateActivities_ignoresDuplicate() { + DeskBoard modifiedDeskBoard = getTypicalDeskBoard(); + modifiedDeskBoard.addActivities(Collections.singletonList(ASSIGNMENT1)); + assertEquals(getTypicalDeskBoard(), modifiedDeskBoard); + } + + //@@author /** * A stub ReadOnlyDeskBoard whose activities and tags lists can violate interface constraints. */ diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index 101d3fa04895..4f4e9bdd3a46 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -1,10 +1,13 @@ package seedu.address.model; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static seedu.address.model.Model.PREDICATE_SHOW_ALL_ACTIVITY; import static seedu.address.testutil.TypicalActivities.ASSIGNMENT1; import static seedu.address.testutil.TypicalActivities.ASSIGNMENT2; +import static seedu.address.testutil.TypicalActivities.ASSIGNMENT3; +import static seedu.address.testutil.TypicalActivities.DEMO1; import java.util.Arrays; @@ -13,6 +16,7 @@ import org.junit.rules.ExpectedException; import seedu.address.model.activity.NameContainsKeywordsPredicate; +import seedu.address.model.activity.exceptions.DuplicateActivityException; import seedu.address.testutil.DeskBoardBuilder; public class ModelManagerTest { @@ -26,6 +30,17 @@ public void getFilteredActivitiesList_modifyList_throwsUnsupportedOperationExcep modelManager.getFilteredActivityList().remove(0); } + @Test + public void addActivities_validDeskBoard_success() throws DuplicateActivityException { + ModelManager modelManager = new ModelManager(); + DeskBoard deskBoard = new DeskBoard(); + deskBoard.addActivity(ASSIGNMENT3); + deskBoard.addActivity(DEMO1); + modelManager.addActivities(deskBoard); + assertEquals(deskBoard, modelManager.getDeskBoard()); + } + + @Test public void equals() { DeskBoard addressBook = new DeskBoardBuilder().withActivity(ASSIGNMENT1).withActivity(ASSIGNMENT2).build(); From 8991967129c656e68b77e4782b232f3d0b8202f9 Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Wed, 11 Apr 2018 01:38:57 +0800 Subject: [PATCH 18/19] Fix unused imports --- src/test/java/seedu/address/model/DeskBoardTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/seedu/address/model/DeskBoardTest.java b/src/test/java/seedu/address/model/DeskBoardTest.java index 66dcf7f48394..8e2cdad75266 100644 --- a/src/test/java/seedu/address/model/DeskBoardTest.java +++ b/src/test/java/seedu/address/model/DeskBoardTest.java @@ -17,7 +17,6 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import seedu.address.model.activity.Activity; -import seedu.address.model.activity.Task; import seedu.address.model.tag.Tag; public class DeskBoardTest { From 3ab9a0826369e8358917619ea47eb0eca60cd47b Mon Sep 17 00:00:00 2001 From: karenfrilya97 Date: Wed, 11 Apr 2018 02:14:52 +0800 Subject: [PATCH 19/19] Add Project Portfolio --- docs/DeveloperGuide.adoc | 2 ++ docs/UserGuide.adoc | 2 ++ docs/team/karenfrilya97.adoc | 54 ++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 docs/team/karenfrilya97.adoc diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index 07195fb4e2ab..86803d248a32 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -796,6 +796,7 @@ This section describes various design considerations related to the implementati {empty} + +// tag::storage[] === Storage for Task and Event This section describes the implementation and design considerations for the storage of Task and Event. @@ -824,6 +825,7 @@ specialized. The inconvenience of creating 2 separate lists will be counterbalan the long run. {empty} + {empty} + +// end::storage[] === Logging diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index c313a3bd544d..940c1985b13c 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -234,6 +234,7 @@ Clears all entries from the desk board. *Format:* `clear` or `c` +// tag::import[] === Importing data : `import` `[As of v1.4.1]` Import all entries from another desk board file in the specified file path. @@ -243,6 +244,7 @@ Import all entries from another desk board file in the specified file path. *Example:* * `import f/C:\data\deskboard.xml` +// end::import[] === Exiting the program : `exit` `[As of v1.4.1]` diff --git a/docs/team/karenfrilya97.adoc b/docs/team/karenfrilya97.adoc new file mode 100644 index 000000000000..36c6a97cc54f --- /dev/null +++ b/docs/team/karenfrilya97.adoc @@ -0,0 +1,54 @@ += Karen Frilya Celine - Project Portfolio +:imagesDir: ../images +:stylesDir: ../stylesheets + +== PROJECT: CLIndar + +--- + +== Overview + +CLIndar is a desktop application for managing schedules catered specially to university computing students. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. + +== Summary of contributions + +* *Major enhancement*: added *the ability to import data from an xml file.* +** What it does: allows the user to add all entries from application data previously saved in an xml file. +** Justification: This feature improves the product significantly because it spares users the trouble of adding each entry one by one from data previously saved in a different file. This file could have been transferred from another computer. +** Highlights: This enhancement requires new classes to be created that are different from existing classes. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing classes. +** Credits: This enhancement makes uses and enhances existing code for reading data from an xml file written by previous developers. + +* *Minor enhancement*: added an autosorting feature that allows the entries to be sorted by date/time every time a new entry is added. + +* *Code contributed*: [https://github.com/CS2103JAN2018-W13-B3/main/blob/master/collated/functional/karenfrilya97.md[Functional code]] [https://github.com/CS2103JAN2018-W13-B3/main/blob/master/collated/test/karenfrilya97.md[Test code]] + +* *Other contributions*: + +** Project management: +*** Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub +** Enhancements to existing features: +*** Refactored the Storage component for the purpose of morphing Address Book - Level 4 into CLIndar (Pull requests https://github.com/CS2103JAN2018-W13-B3/main/pull/40[#40], https://github.com/CS2103JAN2018-W13-B3/main/pull/53[#53], +https://github.com/CS2103JAN2018-W13-B3/main/pull/64[#64], https://github.com/CS2103JAN2018-W13-B3/main/pull/93[#93]) +** Documentation: +*** Edited the grammar and punctuation of the Developer Guide in general: https://github.com/CS2103JAN2018-W13-B3/main/pull/152[#152] +*** Restructured Section 4 (Implementation) of the Developer Guide: https://github.com/CS2103JAN2018-W13-B3/main/pull/152[#152] +** Community: +*** PRs reviewed (with non-trivial review comments): https://github.com/CS2103JAN2018-W13-B3/main/pull/52[#52] +*** Reported bugs and suggestions for other teams in the class (examples: https://github.com/CS2103JAN2018-F14-B2/main/issues/175[#175], https://github.com/CS2103JAN2018-F14-B2/main/issues/181[#181], https://github.com/CS2103JAN2018-F14-B2/main/issues/182[#182]) + +== Contributions to the User Guide + + +|=== +|_Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ +|=== + +include::../UserGuide.adoc[tag=import] + +== Contributions to the Developer Guide + +|=== +|_Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ +|=== + +include::../DeveloperGuide.adoc[tag=storage]