From 7395cda973c1103798eee71a6e29664672107758 Mon Sep 17 00:00:00 2001 From: yuhongherald Date: Sun, 18 Mar 2018 00:39:46 +0800 Subject: [PATCH] Add set command functionality (#50) Set command can now keep a set of custom command words on top of default command words. Test cases written for set command and parser. --- .../seedu/address/logic/commands/Command.java | 20 ---- .../address/logic/commands/CommandWords.java | 109 ++++++++++++++---- .../address/logic/commands/SetCommand.java | 4 +- .../logic/parser/AddressBookParser.java | 3 +- .../logic/commands/SetCommandTest.java | 57 ++++++++- .../logic/parser/SetCommandParserTest.java | 40 +++++++ 6 files changed, 181 insertions(+), 52 deletions(-) create mode 100644 src/test/java/seedu/address/logic/parser/SetCommandParserTest.java diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/address/logic/commands/Command.java index b3371288a6fe..831593af88de 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/seedu/address/logic/commands/Command.java @@ -10,26 +10,6 @@ * Represents a command with hidden internal logic and the ability to be executed. */ public abstract class Command { - /** - * Stores a list of COMMANDS by their command word - */ - public static final String[] COMMANDS = { - AddCommand.COMMAND_WORD, - ClearCommand.COMMAND_WORD, - DeleteCommand.COMMAND_WORD, - EditCommand.COMMAND_WORD, - ExitCommand.COMMAND_WORD, - FindCommand.COMMAND_WORD, - HelpCommand.COMMAND_WORD, - HistoryCommand.COMMAND_WORD, - ListCommand.COMMAND_WORD, - RedoCommand.COMMAND_WORD, - SelectCommand.COMMAND_WORD, - SetCommand.COMMAND_WORD, - UndoCommand.COMMAND_WORD, - ThemeCommand.COMMAND_WORD, - SortCommand.COMMAND_WORD - }; protected Model model; protected CommandHistory history; diff --git a/src/main/java/seedu/address/logic/commands/CommandWords.java b/src/main/java/seedu/address/logic/commands/CommandWords.java index cc91649e6899..0897f81d08ac 100644 --- a/src/main/java/seedu/address/logic/commands/CommandWords.java +++ b/src/main/java/seedu/address/logic/commands/CommandWords.java @@ -14,16 +14,38 @@ * A serializable data structure used to contain the mappings of a command to a word */ public class CommandWords implements Serializable { - public static final String MESSAGE_INACTIVE = "%s is not an active command."; - public static final String MESSAGE_DUPLICATE = "%s is already used."; + public static final String MESSAGE_UNUSED = "%s is not an active command."; + public static final String MESSAGE_USED = "%s is already used."; public static final String MESSAGE_NO_CHANGE = "Old and new command word is the same."; + public static final String MESSAGE_OVERWRITE_DEFAULT = "%s is a default command."; + /** + * Stores a list of COMMANDS by their command word + */ + public static final String[] COMMANDS = { + AddCommand.COMMAND_WORD, + ClearCommand.COMMAND_WORD, + DeleteCommand.COMMAND_WORD, + EditCommand.COMMAND_WORD, + ExitCommand.COMMAND_WORD, + FindCommand.COMMAND_WORD, + HelpCommand.COMMAND_WORD, + HistoryCommand.COMMAND_WORD, + ListCommand.COMMAND_WORD, + RedoCommand.COMMAND_WORD, + SelectCommand.COMMAND_WORD, + SetCommand.COMMAND_WORD, + UndoCommand.COMMAND_WORD, + ThemeCommand.COMMAND_WORD, + SortCommand.COMMAND_WORD + }; + public final HashMap commands; /** * Creates a data structure to maintain used command words. */ public CommandWords() { commands = new HashMap<>(); - for (String command : Command.COMMANDS) { + for (String command : COMMANDS) { commands.put(command, command); } } @@ -35,25 +57,31 @@ public CommandWords(CommandWords commandWords) { } /** - * Copies key and value of (@code command) from (@code commands) - * to (@code verifiedCommands). Creates a new entry with default - * key = value if missing. + * Returns whether (@code commandWord) is in (@code COMMANDS) */ - private void moveVerifiedWord(String command, HashMap verifiedCommands) { - verifiedCommands.put(command, commands.getOrDefault(command, command)); + public static boolean isDefaultCommandWord(String commandWord) { + for (String command: COMMANDS) { + if (command.equals(commandWord)) { + return true; + } + } + return false; } - /** - * Checks if hashmap contains invalid command keys and adds any missing - * command keys - */ - public void checkIntegrity() { - HashMap verifiedCommands = new HashMap<>(); - for (String command : Command.COMMANDS) { - moveVerifiedWord(command, verifiedCommands); - } - commands.clear(); - commands.putAll(verifiedCommands); + public static String getMessageUnused(String commandWord) { + return String.format(MESSAGE_UNUSED, commandWord); + } + + public static String getMessageOverwriteDefault(String commandWord) { + return String.format(MESSAGE_OVERWRITE_DEFAULT, commandWord); + } + + public static String getMessageUsed(String commandWord) { + return String.format(MESSAGE_USED, commandWord); + } + + public static String getMessageNoChange() { + return MESSAGE_NO_CHANGE; } /** @@ -65,7 +93,7 @@ public void checkIntegrity() { public String getCommandWord(String key) throws CommandWordException { String commandWord = commands.get(key); if (commandWord == null) { - throw new CommandWordException(String.format(MESSAGE_INACTIVE, key)); + throw new CommandWordException(getMessageUnused(key)); } return commandWord; } @@ -85,7 +113,7 @@ public String getCommandKey(String value) throws CommandWordException { return currentCommand.getKey(); } } - throw new CommandWordException(String.format(MESSAGE_INACTIVE, value)); + throw new CommandWordException(getMessageUnused(value)); } /** @@ -97,10 +125,19 @@ public String getCommandKey(String value) throws CommandWordException { public void setCommandWord(String currentWord, String newWord) throws CommandWordException { requireNonNull(currentWord, newWord); if (currentWord.equals(newWord)) { - throw new CommandWordException(MESSAGE_NO_CHANGE); + throw new CommandWordException(getMessageNoChange()); + } + if (isDefaultCommandWord(newWord) + && !commands.get(newWord).equals(currentWord)) { + throw new CommandWordException(getMessageOverwriteDefault(newWord)); } if (commands.containsValue(newWord)) { - throw new CommandWordException(String.format(MESSAGE_DUPLICATE, newWord)); + throw new CommandWordException(getMessageUsed(newWord)); + } + if (isDefaultCommandWord(currentWord)) { + commands.remove(currentWord); + commands.put(currentWord, newWord); + return; } Iterator> commandList = commands.entrySet().iterator(); Map.Entry currentCommand; @@ -112,10 +149,32 @@ public void setCommandWord(String currentWord, String newWord) throws CommandWor return; } } - StringBuilder builder = new StringBuilder(); - throw new CommandWordException(String.format(MESSAGE_INACTIVE, currentWord)); + throw new CommandWordException(getMessageUnused(currentWord)); } + /** + * Copies key and value of (@code command) from (@code commands) + * to (@code verifiedCommands). Creates a new entry with default + * key = value if missing. + */ + private void moveVerifiedWord(String command, HashMap verifiedCommands) { + verifiedCommands.put(command, commands.getOrDefault(command, command)); + } + + /** + * Checks if hashmap contains invalid command keys and adds any missing + * command keys + */ + public void checkIntegrity() { + HashMap verifiedCommands = new HashMap<>(); + for (String command : COMMANDS) { + moveVerifiedWord(command, verifiedCommands); + } + commands.clear(); + commands.putAll(verifiedCommands); + } + + /** * Resets the existing data of this {@code CommandWords} with {@code newCommandWords}. */ diff --git a/src/main/java/seedu/address/logic/commands/SetCommand.java b/src/main/java/seedu/address/logic/commands/SetCommand.java index 615b85a9a927..537e926edfee 100644 --- a/src/main/java/seedu/address/logic/commands/SetCommand.java +++ b/src/main/java/seedu/address/logic/commands/SetCommand.java @@ -36,11 +36,11 @@ public String getMessageSuccess() { } public String getMessageUsed() { - return String.format(CommandWords.MESSAGE_DUPLICATE, newWord); + return CommandWords.getMessageUsed(newWord); } public String getMessageUnused() { - return String.format(CommandWords.MESSAGE_INACTIVE, currentWord); + return CommandWords.getMessageUnused(currentWord); } @Override diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index fbd8dd6eff71..0f4188cbed6b 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -68,10 +68,11 @@ public Command parseCommand(String userInput) throws ParseException { String commandWord = matcher.group("commandWord"); final String arguments = matcher.group("arguments"); + try { commandWord = commandWords.getCommandKey(commandWord); } catch (CommandWordException e) { - throw new ParseException(MESSAGE_UNKNOWN_COMMAND); + // do nothing, default throws parseException } switch (commandWord) { diff --git a/src/test/java/seedu/address/logic/commands/SetCommandTest.java b/src/test/java/seedu/address/logic/commands/SetCommandTest.java index bd86ee1db8c7..f269788c461e 100644 --- a/src/test/java/seedu/address/logic/commands/SetCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/SetCommandTest.java @@ -28,6 +28,33 @@ public void execute_changeAdd_success() throws CommandWordException { assertCommandSuccess(newCommand, actualModel, newCommand.getMessageSuccess(), expectedModel); } + @Test + public void execute_changeAddUsingDefault_success() throws CommandWordException { + Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + String currentWord = AddCommand.COMMAND_WORD; + String newWord = getUnusedCommandWord(actualModel); + + setCommandWord(actualModel, currentWord, newWord); + newWord = getUnusedCommandWord(actualModel); + setCommandWord(expectedModel, currentWord, newWord); + SetCommand newCommand = prepareCommand(actualModel, currentWord, newWord); + assertCommandSuccess(newCommand, actualModel, newCommand.getMessageSuccess(), expectedModel); + } + + @Test + public void execute_changeAddBackToDefault_success() throws CommandWordException { + Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + String currentWord = AddCommand.COMMAND_WORD; + String newWord = getUnusedCommandWord(actualModel); + + setCommandWord(actualModel, currentWord, newWord); + SetCommand newCommand = prepareCommand(actualModel, newWord, currentWord); + assertCommandSuccess(newCommand, actualModel, newCommand.getMessageSuccess(), expectedModel); + } + + @Test public void execute_changeSet_success() throws CommandWordException { Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); @@ -48,14 +75,26 @@ public void execute_changeSet_success() throws CommandWordException { public void execute_changeCommand_failureUsed() throws CommandWordException { Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); String currentWord = AddCommand.COMMAND_WORD; - String newWord = SetCommand.COMMAND_WORD; + String newWord = getUnusedCommandWord(actualModel); + setCommandWord(actualModel, SetCommand.COMMAND_WORD, newWord); SetCommand newCommand = prepareCommand(actualModel, currentWord, newWord); assertCommandFailure(newCommand, actualModel, newCommand.getMessageUsed()); } @Test - public void execute_changeCommand_failureUnused() throws CommandWordException { + public void execute_changeCommand_failureDefault() throws CommandWordException { + Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + String currentWord = AddCommand.COMMAND_WORD; + String newWord = SetCommand.COMMAND_WORD; + + SetCommand newCommand = prepareCommand(actualModel, currentWord, newWord); + assertCommandFailure(newCommand, actualModel, CommandWords.getMessageOverwriteDefault(newWord)); + } + + + @Test + public void execute_changeCommand_failureUnused() { Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); Model testModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); String currentWord = getUnusedCommandWord(actualModel); @@ -65,11 +104,21 @@ public void execute_changeCommand_failureUnused() throws CommandWordException { assertCommandFailure(newCommand, actualModel, newCommand.getMessageUnused()); } + @Test + public void execute_changeCommand_failureNoChange() throws CommandWordException { + Model actualModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + String currentWord = AddCommand.COMMAND_WORD; + String newWord = currentWord; + + SetCommand newCommand = prepareCommand(actualModel, currentWord, newWord); + assertCommandFailure(newCommand, actualModel, CommandWords.getMessageNoChange()); + } + private void setCommandWord(Model expectedModel, String currentWord, String newWord) throws CommandWordException { expectedModel.getCommandWords().setCommandWord(currentWord, newWord); } - private String getUnusedCommandWord(Model actualModel) { + public static String getUnusedCommandWord(Model actualModel) { String newWord = "a"; for (int i = 0; i < actualModel.getCommandWords().commands.size(); i++) { if (!actualModel.getCommandWords().commands.containsValue(newWord)) { @@ -80,7 +129,7 @@ private String getUnusedCommandWord(Model actualModel) { return newWord; } - private String getUnusedCommandWord(Model actualModel, String otherWord) { + public static String getUnusedCommandWord(Model actualModel, String otherWord) { if (otherWord == null || otherWord.equals("")) { return getUnusedCommandWord(actualModel); } diff --git a/src/test/java/seedu/address/logic/parser/SetCommandParserTest.java b/src/test/java/seedu/address/logic/parser/SetCommandParserTest.java new file mode 100644 index 000000000000..49d7cba704bb --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/SetCommandParserTest.java @@ -0,0 +1,40 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +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.AddCommand; +import seedu.address.logic.commands.SetCommand; + +public class SetCommandParserTest { + private SetCommandParser parser = new SetCommandParser(); + + @Test + public void parse_twoCommandWords_success() { + String currentWord = AddCommand.COMMAND_WORD; + String newWord = getWord(); + String args = String.join(" ", currentWord, newWord); + assertParseSuccess(parser, args, new SetCommand(currentWord, newWord)); + } + + @Test + public void parse_noCommandWord_failure() { + String currentWord = ""; + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SetCommand.MESSAGE_USAGE); + assertParseFailure(parser, currentWord, expectedMessage); + } + + @Test + public void parse_oneCommandWord_failure() { + String currentWord = AddCommand.COMMAND_WORD; + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SetCommand.MESSAGE_USAGE); + assertParseFailure(parser, currentWord, expectedMessage); + } + + public static String getWord() { + return "a"; + } +}