diff --git a/src/main/java/seedu/address/logic/commands/AbstractFindCommand.java b/src/main/java/seedu/address/logic/commands/AbstractFindCommand.java index 9c9b7f1fb76..d94bf2b8731 100644 --- a/src/main/java/seedu/address/logic/commands/AbstractFindCommand.java +++ b/src/main/java/seedu/address/logic/commands/AbstractFindCommand.java @@ -26,6 +26,10 @@ public AbstractFindCommand(ContainsKeywordsPredicate predicate) { this.predicate = predicate; } + protected ContainsKeywordsPredicate getPredicate() { + return this.predicate; + } + @Override public CommandResult execute(Model model) { requireNonNull(model); @@ -34,21 +38,6 @@ public CommandResult execute(Model model) { String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size())); } - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - - // instanceof handles nulls - if (!(other instanceof AbstractFindCommand)) { - return false; - } - - AbstractFindCommand otherFindCommand = (AbstractFindCommand) other; - return this.predicate.equals(otherFindCommand.predicate); - } - @Override public String toString() { return new ToStringBuilder(this) diff --git a/src/main/java/seedu/address/logic/commands/FindByNameCommand.java b/src/main/java/seedu/address/logic/commands/FindByNameCommand.java new file mode 100644 index 00000000000..5f3593b2e10 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/FindByNameCommand.java @@ -0,0 +1,28 @@ +package seedu.address.logic.commands; + +import seedu.address.model.person.NameContainsKeywordsPredicate; + +/** + * Finds and lists all persons in address book whose name contains any of the argument keywords. + * Keyword matching is case-insensitive. + */ +public class FindByNameCommand extends AbstractFindCommand { + public FindByNameCommand(NameContainsKeywordsPredicate predicate) { + super(predicate); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof FindByNameCommand)) { + return false; + } + + FindByNameCommand otherFindCommand = (FindByNameCommand) other; + return this.getPredicate().equals(otherFindCommand.getPredicate()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 3149ee07e0b..95ceec836c1 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -8,13 +8,13 @@ import java.util.regex.Pattern; import seedu.address.commons.core.LogsCenter; +import seedu.address.logic.commands.AbstractFindCommand; import seedu.address.logic.commands.AddCommand; import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteCommand; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.ExitCommand; -import seedu.address.logic.commands.FindCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; import seedu.address.logic.parser.exceptions.ParseException; @@ -65,7 +65,7 @@ public Command parseCommand(String userInput) throws ParseException { case ClearCommand.COMMAND_WORD: return new ClearCommand(); - case FindCommand.COMMAND_WORD: + case AbstractFindCommand.COMMAND_WORD: return new FindCommandParser().parse(arguments); case ListCommand.COMMAND_WORD: diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java index 2867bde857b..9205b470b90 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java @@ -3,7 +3,11 @@ import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import seedu.address.logic.commands.AbstractFindCommand; +import seedu.address.logic.commands.FindByNameCommand; import seedu.address.logic.commands.FindCommand; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.person.NameContainsKeywordsPredicate; @@ -11,23 +15,38 @@ /** * Parses input arguments and creates a new FindCommand object */ -public class FindCommandParser implements Parser { +public class FindCommandParser implements Parser { + + public static final Pattern KEYWORD_EXTRACTOR = + Pattern.compile("^(?/[cen])\\s*(?[\\S\\s]+)$"); /** * Parses the given {@code String} of arguments in the context of the FindCommand * and returns a FindCommand object for execution. * @throws ParseException if the user input does not conform the expected format */ - public FindCommand parse(String args) throws ParseException { - String trimmedArgs = args.trim(); - if (trimmedArgs.isEmpty()) { + public AbstractFindCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); // trim space + Matcher m = KEYWORD_EXTRACTOR.matcher(trimmedArgs); // find tag and search words + + // will throw exception if no args/command format not correct + if (trimmedArgs.isEmpty() || !m.matches()) { throw new ParseException( String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); } - String[] nameKeywords = trimmedArgs.split("\\s+"); - - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); + // extract tag and search argument + String tag = m.group("tag"); + String searchTerms = m.group("arguments"); + String[] searchTermArray = searchTerms.split("\\s+"); + + // return approppriate FindCommand class depending on tag + switch (tag) { + case "/n": + return new FindByNameCommand( + new NameContainsKeywordsPredicate(Arrays.asList(searchTermArray))); + default: + return null; // temporary value, this should not occur due to regex + } } - } diff --git a/src/test/java/seedu/address/logic/commands/FindByNameCommandTest.java b/src/test/java/seedu/address/logic/commands/FindByNameCommandTest.java new file mode 100644 index 00000000000..62e37b55f06 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/FindByNameCommandTest.java @@ -0,0 +1,91 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalPersons.CARL; +import static seedu.address.testutil.TypicalPersons.ELLE; +import static seedu.address.testutil.TypicalPersons.FIONA; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.Arrays; +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.NameContainsKeywordsPredicate; + +/** + * Contains integration tests (interaction with the Model) for {@code FindCommand}. + */ +public class FindByNameCommandTest { + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void equals() { + NameContainsKeywordsPredicate firstPredicate = + new NameContainsKeywordsPredicate(Collections.singletonList("first")); + NameContainsKeywordsPredicate secondPredicate = + new NameContainsKeywordsPredicate(Collections.singletonList("second")); + + FindByNameCommand findFirstCommand = new FindByNameCommand(firstPredicate); + FindByNameCommand findSecondCommand = new FindByNameCommand(secondPredicate); + + // same object -> returns true + assertTrue(findFirstCommand.equals(findFirstCommand)); + + // same values -> returns true + FindByNameCommand findFirstCommandCopy = new FindByNameCommand(firstPredicate); + assertTrue(findFirstCommand.equals(findFirstCommandCopy)); + + // different types -> returns false + assertFalse(findFirstCommand.equals(1)); + + // null -> returns false + assertFalse(findFirstCommand.equals(null)); + + // different person -> returns false + assertFalse(findFirstCommand.equals(findSecondCommand)); + } + + @Test + public void execute_zeroKeywords_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + NameContainsKeywordsPredicate predicate = preparePredicate(" "); + FindByNameCommand command = new FindByNameCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getFilteredPersonList()); + } + + @Test + public void execute_multipleKeywords_multiplePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); + NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz"); + FindByNameCommand command = new FindByNameCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList()); + } + + @Test + public void toStringMethod() { + NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword")); + FindByNameCommand findCommand = new FindByNameCommand(predicate); + String expected = FindByNameCommand.class.getCanonicalName() + "{predicate=" + predicate + "}"; + assertEquals(expected, findCommand.toString()); + } + + /** + * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}. + */ + private NameContainsKeywordsPredicate preparePredicate(String userInput) { + return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + } +} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 5a1ab3dbc0c..08ae9a62fab 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -19,7 +19,7 @@ import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; import seedu.address.logic.commands.ExitCommand; -import seedu.address.logic.commands.FindCommand; +import seedu.address.logic.commands.FindByNameCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; import seedu.address.logic.parser.exceptions.ParseException; @@ -68,12 +68,21 @@ public void parseCommand_exit() throws Exception { assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand); } + // @Test + // public void parseCommand_find() throws Exception { + // List keywords = Arrays.asList("foo", "bar", "baz"); + // FindCommand command = (FindCommand) parser.parseCommand( + // FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); + // assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command); + // } + @Test - public void parseCommand_find() throws Exception { + public void parseCommand_findByName() throws Exception { List keywords = Arrays.asList("foo", "bar", "baz"); - FindCommand command = (FindCommand) parser.parseCommand( - FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); - assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command); + FindByNameCommand command = (FindByNameCommand) parser.parseCommand( + FindByNameCommand.COMMAND_WORD + " /n " + + keywords.stream().collect(Collectors.joining(" "))); + assertEquals(new FindByNameCommand(new NameContainsKeywordsPredicate(keywords)), command); } @Test diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java index d92e64d12f9..35b0de1c36b 100644 --- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; +import seedu.address.logic.commands.FindByNameCommand; import seedu.address.logic.commands.FindCommand; import seedu.address.model.person.NameContainsKeywordsPredicate; @@ -21,14 +22,15 @@ public void parse_emptyArg_throwsParseException() { } @Test - public void parse_validArgs_returnsFindCommand() { + public void parse_validArgs_returnsFindByNameCommand() { + FindByNameCommand expectedFindCommand = + new FindByNameCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); + // no leading and trailing whitespaces - FindCommand expectedFindCommand = - new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); - assertParseSuccess(parser, "Alice Bob", expectedFindCommand); + assertParseSuccess(parser, "/n Alice Bob", expectedFindCommand); // multiple whitespaces between keywords - assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand); + assertParseSuccess(parser, "/n \n Alice \n \t Bob \t", expectedFindCommand); } }