Skip to content

Commit

Permalink
Add set command functionality (nus-cs2103-AY1718S2#50)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
yuhongherald authored Mar 17, 2018
1 parent 4b549da commit 7395cda
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 52 deletions.
20 changes: 0 additions & 20 deletions src/main/java/seedu/address/logic/commands/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
109 changes: 84 additions & 25 deletions src/main/java/seedu/address/logic/commands/CommandWords.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String> 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);
}
}
Expand All @@ -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<String, String> 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<String, String> 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;
}

/**
Expand All @@ -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;
}
Expand All @@ -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));
}

/**
Expand All @@ -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<Map.Entry<String, String>> commandList = commands.entrySet().iterator();
Map.Entry<String, String> currentCommand;
Expand All @@ -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<String, String> 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<String, String> 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}.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/seedu/address/logic/commands/SetCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
57 changes: 53 additions & 4 deletions src/test/java/seedu/address/logic/commands/SetCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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);
Expand All @@ -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)) {
Expand All @@ -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);
}
Expand Down
40 changes: 40 additions & 0 deletions src/test/java/seedu/address/logic/parser/SetCommandParserTest.java
Original file line number Diff line number Diff line change
@@ -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";
}
}

0 comments on commit 7395cda

Please sign in to comment.