Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement search feature for help command #81

Merged
merged 7 commits into from Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 8 additions & 2 deletions docs/UserGuide.adoc
Expand Up @@ -30,7 +30,7 @@ AlgoBase (AB) is for those who prefer to use a desktop app for managing algorith
image::Ui.png[width="790"]
+
. Type the command in the command box and press kbd:[Enter] to execute it. +
e.g. typing *`help`* and pressing kbd:[Enter] will open the help window.
e.g. typing *`help`* and pressing kbd:[Enter] will list all possible commands in the result window and open the help window.
. Some example commands you can try:

* *`list`* : lists all problems
Expand Down Expand Up @@ -297,7 +297,13 @@ Switches to the tab at index 1.

==== Viewing help : `help`

Format: `help`
List all possible commands or find command usage using the command word. +
Format: `help [COMMAND_WORD]`

* `help`
Shows all possible commands.
* `help add`
Shows command usage for `add` command.

==== Clearing all entries : `clear`

Expand Down
1 change: 1 addition & 0 deletions src/main/java/seedu/algobase/commons/core/Messages.java
Expand Up @@ -14,4 +14,5 @@ public class Messages {
public static final String MESSAGE_INVALID_TAG_FORMAT = "Invalid tag format! \n";
public static final String MESSAGE_INVALID_TAG_DISPLAYED_INDEX = "The Tag index provided is invalid";
public static final String MESSAGE_PLANS_LISTED_OVERVIEW = "%1$d plans listed!";
public static final String MESSAGE_INVALID_COMMAND_NAME = "Command %1$s not found!";
}
13 changes: 13 additions & 0 deletions src/main/java/seedu/algobase/commons/util/AppUtil.java
Expand Up @@ -36,4 +36,17 @@ public static void checkArgument(Boolean condition, String errorMessage) {
throw new IllegalArgumentException(errorMessage);
}
}

public static String getClassStringField(Class targetClass, String fieldName) {
try {
String result = (String) targetClass.getField(fieldName).get("");
return result;
} catch (NoSuchFieldException e) {
throw new AssertionError("Class " + targetClass.getName()
+ "doesn't have " + fieldName + " field.");
} catch (IllegalAccessException e) {
throw new AssertionError("Class " + targetClass.getName()
+ "has non-public " + fieldName + ".");
}
}
}
25 changes: 25 additions & 0 deletions src/main/java/seedu/algobase/logic/commands/Command.java
Expand Up @@ -8,6 +8,31 @@
*/
public abstract class Command {

public static final Class[] COMMAND_LIST = {
AddCommand.class,
AddPlanCommand.class,
AddTagCommand.class,
ClearCommand.class,
DeleteCommand.class,
DeletePlanCommand.class,
DeleteTagCommand.class,
DeleteTaskCommand.class,
DoneTaskCommand.class,
EditCommand.class,
EditPlanCommand.class,
EditTagCommand.class,
ExitCommand.class,
FindCommand.class,
FindPlanCommand.class,
HelpCommand.class,
ListCommand.class,
ListPlanCommand.class,
ListTagCommand.class,
SortCommand.class,
SwitchCommand.class,
UndoneTaskCommand.class
};

/**
* Executes the command and returns the result message.
*
Expand Down
Expand Up @@ -68,4 +68,8 @@ public int hashCode() {
return Objects.hash(feedbackToUser, showHelp, exit);
}

@Override
public String toString() {
return "[CommandResult]: " + feedbackToUser;
}
}
65 changes: 60 additions & 5 deletions src/main/java/seedu/algobase/logic/commands/HelpCommand.java
@@ -1,5 +1,11 @@
package seedu.algobase.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.algobase.commons.util.AppUtil.getClassStringField;

import java.util.ArrayList;
import java.util.List;

import seedu.algobase.model.Model;

/**
Expand All @@ -8,15 +14,64 @@
public class HelpCommand extends Command {

public static final String COMMAND_WORD = "help";

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Shows program usage instructions.\n"
+ "Example: " + COMMAND_WORD;
+ ": Shows program usage instructions.\n"
+ "Parameter:\n"
+ "COMMAND_NAME (can be empty if you want a list of possible commands)\n"
+ "Example: " + COMMAND_WORD + " find";

private final boolean isListAllCommands;
private final Class commandClass;

public HelpCommand(Class commandClass, boolean isListAllCommands) {
this.isListAllCommands = isListAllCommands;
if (!isListAllCommands) {
requireNonNull(commandClass);
this.commandClass = commandClass;
} else {
this.commandClass = commandClass;
}
}

public boolean isListAllCommands() {
return isListAllCommands;
}

public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
public Class getCommandClass() {
return commandClass;
}

@Override
public CommandResult execute(Model model) {
return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
if (isListAllCommands) {
List<String> commandWords = new ArrayList<>();
for (Class command : Command.COMMAND_LIST) {
commandWords.add(getClassStringField(command, "COMMAND_WORD"));
}
String commandPrompt = "Available commands are: " + commandWords.toString() + "\n"
+ "More information can be found in the popup window.";
return new CommandResult(commandPrompt, true, false);
} else {
String commandUsage = getClassStringField(commandClass, "MESSAGE_USAGE");
return new CommandResult(commandUsage, false, false);
}
}

@Override
public boolean equals(Object other) {
// short circuit if same object
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof HelpCommand)) {
return false;
}

// state check
HelpCommand h = (HelpCommand) other;
return isListAllCommands == h.isListAllCommands()
&& commandClass.equals(h.getCommandClass());
}
}
Expand Up @@ -115,7 +115,7 @@ public Command parseCommand(String userInput) throws ParseException {
return new ExitCommand();

case HelpCommand.COMMAND_WORD:
return new HelpCommand();
return new HelpCommandParser().parse(arguments);

case AddTagCommand.COMMAND_WORD:
return new AddTagCommandParser().parse(arguments);
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/seedu/algobase/logic/parser/HelpCommandParser.java
@@ -0,0 +1,30 @@
package seedu.algobase.logic.parser;

import static seedu.algobase.commons.core.Messages.MESSAGE_INVALID_COMMAND_NAME;
import static seedu.algobase.commons.util.AppUtil.getClassStringField;

import seedu.algobase.logic.commands.Command;
import seedu.algobase.logic.commands.HelpCommand;
import seedu.algobase.logic.parser.exceptions.ParseException;

/**
* Parses input arguments and creates a new HelpCommand object
*/
public class HelpCommandParser implements Parser<HelpCommand> {

@Override
public HelpCommand parse(String userInput) throws ParseException {
String trimmedArgs = userInput.trim();
if (trimmedArgs.isEmpty()) {
return new HelpCommand(null, true);
} else {
for (Class command : Command.COMMAND_LIST) {
String commandWord = getClassStringField(command, "COMMAND_WORD");
if (commandWord.equals(trimmedArgs)) {
return new HelpCommand(command, false);
}
}
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_NAME, trimmedArgs));
}
}
}
5 changes: 2 additions & 3 deletions src/main/resources/view/ResultDisplay.fxml
Expand Up @@ -2,7 +2,6 @@

<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="placeHolder" styleClass="pane-with-border" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1">
<TextArea fx:id="resultDisplay" editable="false" styleClass="result-display"/>
<StackPane fx:id="placeHolder" styleClass="pane-with-border" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<TextArea fx:id="resultDisplay" editable="false" styleClass="result-display" wrapText="true" />
</StackPane>
Expand Up @@ -23,7 +23,7 @@ public void constructor_nullProblem_throwsNullPointerException() {
}

@Test
public void execute_problemAcceptedByModel_addSuccessful() throws Exception {
public void execute_problemAcceptedByModel_addsSuccessful() throws Exception {
ModelStubAcceptingProblemAdded modelStub = new ModelStubAcceptingProblemAdded();
Problem validProblem = new ProblemBuilder().build();

Expand Down
39 changes: 39 additions & 0 deletions src/test/java/seedu/algobase/logic/commands/HelpCommandTest.java
@@ -0,0 +1,39 @@
package seedu.algobase.logic.commands;

import static seedu.algobase.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.algobase.testutil.Assert.assertThrows;
import static seedu.algobase.testutil.TypicalProblems.getTypicalAlgoBase;

import org.junit.jupiter.api.Test;

import seedu.algobase.model.Model;
import seedu.algobase.model.ModelManager;
import seedu.algobase.model.UserPrefs;

class HelpCommandTest {

private static final String EXPECTED_COMMAND_LIST = "Available commands are: [add, addplan, addtag, "
+ "clear, delete, deleteplan, deletetag, deletetask, donetask, edit, editplan, edittag, exit, "
+ "find, findplan, help, list, listplan, listtag, sort, switch, undonetask]\n"
+ "More information can be found in the popup window.";
private Model model = new ModelManager(getTypicalAlgoBase(), new UserPrefs());
private Model expectedModel = new ModelManager(getTypicalAlgoBase(), new UserPrefs());

@Test
void constructor_nullCommandClassWithoutListingAllCommands_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> new HelpCommand(null, false));
}

@Test
void constructor_nullCommandClassWithListingAllCommands_success() {
HelpCommand command = new HelpCommand(null, true);
assertCommandSuccess(command, model,
new CommandResult(EXPECTED_COMMAND_LIST, true, false), expectedModel);
}

@Test
void execute_correctCommandWord_showsMessageUsage() {
HelpCommand command = new HelpCommand(AddCommand.class, false);
assertCommandSuccess(command, model, AddCommand.MESSAGE_USAGE, expectedModel);
}
}
@@ -0,0 +1,38 @@
package seedu.algobase.logic.parser;

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

import seedu.algobase.logic.commands.Command;
import seedu.algobase.logic.parser.exceptions.ParseException;

/**
* Contains helper methods for testing command parsers.
*/
public class CommandParserTestUtil {

/**
* Asserts that the parsing of {@code userInput} by {@code parser} is successful and the command created
* equals to {@code expectedCommand}.
*/
public static void assertParseSuccess(Parser parser, String userInput, Command expectedCommand) {
try {
Command command = parser.parse(userInput);
assertEquals(expectedCommand, command);
} catch (ParseException pe) {
throw new IllegalArgumentException("Invalid userInput.", pe);
}
}

/**
* Asserts that the parsing of {@code userInput} by {@code parser} is unsuccessful and the error message
* equals to {@code expectedMessage}.
*/
public static void assertParseFailure(Parser parser, String userInput, String expectedMessage) {
try {
parser.parse(userInput);
throw new AssertionError("The expected ParseException was not thrown.");
} catch (ParseException pe) {
assertEquals(expectedMessage, pe.getMessage());
}
}
}
@@ -0,0 +1,37 @@
package seedu.algobase.logic.parser;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.algobase.commons.core.Messages.MESSAGE_INVALID_COMMAND_NAME;
import static seedu.algobase.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.algobase.logic.parser.CommandParserTestUtil.assertParseSuccess;

import org.junit.jupiter.api.Test;

import seedu.algobase.logic.commands.AddCommand;
import seedu.algobase.logic.commands.HelpCommand;
import seedu.algobase.logic.parser.exceptions.ParseException;

class HelpCommandParserTest {
private static final String INVALID_COMMAND_WORD = "1nval1dC0mmand";
private static final String VALID_COMMAND_WORD = AddCommand.COMMAND_WORD;
private static final Class VALID_COMMAND_CLASS = AddCommand.class;
private HelpCommandParser helpCommandParser = new HelpCommandParser();

@Test
void parse_emptyInput_returnsListAllHelpCommand() throws ParseException {
HelpCommand helpCommand = helpCommandParser.parse("");
assertTrue(helpCommand.isListAllCommands());
}

@Test
void parse_wrongCommandWord_throwsInvalidCommandWordException() {
String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_NAME, INVALID_COMMAND_WORD);
assertParseFailure(helpCommandParser, INVALID_COMMAND_WORD, expectedMessage);
}

@Test
void parse_correctCommandWord_returnsHelpCommandForTheCommand() {
assertParseSuccess(helpCommandParser, VALID_COMMAND_WORD,
new HelpCommand(VALID_COMMAND_CLASS, false));
}
}
Expand Up @@ -9,7 +9,7 @@

class DescriptionContainsKeywordsPredicateTest {

private static String KEYWORD_NOT_IN_QUICK_SORT_DESCRIPTION = "1mP0ss1ble";
private static final String KEYWORD_NOT_IN_QUICK_SORT_DESCRIPTION = "1mP0ss1ble";

@Test
public void test_problemDescriptionContainsKeywords_returnTrue() {
Expand Down
Expand Up @@ -9,7 +9,7 @@

class NameContainsKeywordsPredicateTest {

private static String KEYWORD_NOT_IN_QUICK_SORT_NAME = "1mP0ss1ble";
private static final String KEYWORD_NOT_IN_QUICK_SORT_NAME = "1mP0ss1ble";

@Test
public void test_problemNameContainsKeywords_returnTrue() {
Expand Down