diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java index d10b6d96def..356c9e5bebc 100644 --- a/src/main/java/seedu/address/logic/Messages.java +++ b/src/main/java/seedu/address/logic/Messages.java @@ -24,6 +24,7 @@ public class Messages { public static final String MESSAGE_PROPERTIES_MATCH_OVERVIEW = "%1$d customers matched with property "; public static final String MESSAGE_CUSTOMERS_LISTED_OVERVIEW = "%1$d customers listed!"; + public static final String MESSAGE_PROPERTIES_LISTED_OVERVIEW = "%1$d properties listed!"; public static final String MESSAGE_DUPLICATE_FIELDS = "Multiple values specified for the following single-valued field(s): "; diff --git a/src/main/java/seedu/address/logic/commands/FindPropertyCommand.java b/src/main/java/seedu/address/logic/commands/FindPropertyCommand.java new file mode 100644 index 00000000000..67324a915ad --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/FindPropertyCommand.java @@ -0,0 +1,59 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.Messages; +import seedu.address.model.Model; +import seedu.address.model.property.PropNameContainsKeywordsPredicate; + + +/** + * Finds and lists all properties in address book whose name contains any of the argument keywords. + * Keyword matching is case insensitive. + */ +public class FindPropertyCommand extends Command { + + public static final String COMMAND_WORD = "findprop"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all properties whose names contain any of " + + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" + + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " Aquavista Luxeloft"; + + private final PropNameContainsKeywordsPredicate predicate; + + public FindPropertyCommand(PropNameContainsKeywordsPredicate predicate) { + this.predicate = predicate; + } + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredPropertyList(predicate); + return new CommandResult( + String.format(Messages.MESSAGE_PROPERTIES_LISTED_OVERVIEW, model.getFilteredPropertyList().size())); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof FindPropertyCommand)) { + return false; + } + + FindPropertyCommand otherFindCommand = (FindPropertyCommand) other; + return predicate.equals(otherFindCommand.predicate); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("predicate", predicate) + .toString(); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 5958f209c62..1eecb64b10f 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -20,6 +20,7 @@ import seedu.address.logic.commands.FilterCustomerCommand; import seedu.address.logic.commands.FilterPropertyCommand; import seedu.address.logic.commands.FindCustomerCommand; +import seedu.address.logic.commands.FindPropertyCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCustomerCommand; import seedu.address.logic.commands.ListPropertyCommand; @@ -85,6 +86,9 @@ public Command parseCommand(String userInput) throws ParseException { case FindCustomerCommand.COMMAND_WORD: return new FindCustomerCommandParser().parse(arguments); + case FindPropertyCommand.COMMAND_WORD: + return new FindPropertyCommandParser().parse(arguments); + case FilterCustomerCommand.COMMAND_WORD: return new FilterCustomerCommandParser().parse(arguments); diff --git a/src/main/java/seedu/address/logic/parser/FindPropertyCommandParser.java b/src/main/java/seedu/address/logic/parser/FindPropertyCommandParser.java new file mode 100644 index 00000000000..dec19dc60da --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/FindPropertyCommandParser.java @@ -0,0 +1,33 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import java.util.Arrays; + +import seedu.address.logic.commands.FindPropertyCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.property.PropNameContainsKeywordsPredicate; + +/** + * Parses input arguments and creates a new FindCommand object + */ +public class FindPropertyCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the FindPropertyCommand + * and returns a FindPropertyCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public FindPropertyCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPropertyCommand.MESSAGE_USAGE)); + } + + String[] nameKeywords = trimmedArgs.split("\\s+"); + + return new FindPropertyCommand(new PropNameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); + } + +} diff --git a/src/main/java/seedu/address/model/property/PropNameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/property/PropNameContainsKeywordsPredicate.java index 7e7992bd5c4..d97c261d499 100644 --- a/src/main/java/seedu/address/model/property/PropNameContainsKeywordsPredicate.java +++ b/src/main/java/seedu/address/model/property/PropNameContainsKeywordsPredicate.java @@ -19,9 +19,9 @@ public PropNameContainsKeywordsPredicate(List keywords) { @Override public boolean test(Property property) { return keywords.stream() - .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(property.getName().fullName, keyword)); + .anyMatch(keyword -> StringUtil.startsWithWordIgnoreCaseWithoutFullMatch(property.getName().fullName, + keyword)); } - @Override public boolean equals(Object other) { if (other == this) { diff --git a/src/test/java/seedu/address/logic/commands/FindPropertyCommandTest.java b/src/test/java/seedu/address/logic/commands/FindPropertyCommandTest.java new file mode 100644 index 00000000000..c20c3d968ca --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/FindPropertyCommandTest.java @@ -0,0 +1,93 @@ +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_PROPERTIES_LISTED_OVERVIEW; +import static seedu.address.logic.commands.CommandPropertyTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalCustomers.getTypicalAddressBook; +import static seedu.address.testutil.TypicalProperties.AQUAVISTA; +import static seedu.address.testutil.TypicalProperties.HORIZONVIEW; +import static seedu.address.testutil.TypicalProperties.SKYVISTA; +import static seedu.address.testutil.TypicalProperties.getTypicalPropertyBook; + +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.property.PropNameContainsKeywordsPredicate; + + +/** + * Contains integration tests (interaction with the Model) for {@code FindPropertyCommand}. + */ +public class FindPropertyCommandTest { + private Model model = new ModelManager(getTypicalAddressBook(), getTypicalPropertyBook(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalAddressBook(), getTypicalPropertyBook(), new UserPrefs()); + + @Test + public void equals() { + PropNameContainsKeywordsPredicate firstPredicate = + new PropNameContainsKeywordsPredicate(Collections.singletonList("first")); + PropNameContainsKeywordsPredicate secondPredicate = + new PropNameContainsKeywordsPredicate(Collections.singletonList("second")); + + FindPropertyCommand findFirstCommand = new FindPropertyCommand(firstPredicate); + FindPropertyCommand findSecondCommand = new FindPropertyCommand(secondPredicate); + + // same object -> returns true + assertTrue(findFirstCommand.equals(findFirstCommand)); + + // same values -> returns true + FindPropertyCommand findFirstCommandCopy = new FindPropertyCommand(firstPredicate); + assertTrue(findFirstCommand.equals(findFirstCommandCopy)); + + // different types -> returns false + assertFalse(findFirstCommand.equals(1)); + + // null -> returns false + assertFalse(findFirstCommand.equals(null)); + + // different customer -> returns false + assertFalse(findFirstCommand.equals(findSecondCommand)); + } + + @Test + public void execute_zeroKeywords_noPropertyFound() { + String expectedMessage = String.format(MESSAGE_PROPERTIES_LISTED_OVERVIEW, 0); + PropNameContainsKeywordsPredicate predicate = preparePredicate(" "); + FindPropertyCommand command = new FindPropertyCommand(predicate); + expectedModel.updateFilteredPropertyList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getFilteredPropertyList()); + } + + @Test + public void execute_multipleKeywords_multiplePropertiesFound() { + String expectedMessage = String.format(MESSAGE_PROPERTIES_LISTED_OVERVIEW, 3); + PropNameContainsKeywordsPredicate predicate = preparePredicate("Aquavi Skyvista Horizonview"); + FindPropertyCommand command = new FindPropertyCommand(predicate); + expectedModel.updateFilteredPropertyList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(AQUAVISTA, SKYVISTA, HORIZONVIEW), model.getFilteredPropertyList()); + } + + @Test + public void toStringMethod() { + PropNameContainsKeywordsPredicate predicate = new PropNameContainsKeywordsPredicate(Arrays.asList("keyword")); + FindPropertyCommand findCommand = new FindPropertyCommand(predicate); + String expected = FindPropertyCommand.class.getCanonicalName() + "{predicate=" + predicate + "}"; + assertEquals(expected, findCommand.toString()); + } + + /** + * Parses {@code userInput} into a {@code PropNameContainsKeywordsPredicate}. + */ + private PropNameContainsKeywordsPredicate preparePredicate(String userInput) { + return new PropNameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + } +} diff --git a/src/test/java/seedu/address/testutil/TypicalProperties.java b/src/test/java/seedu/address/testutil/TypicalProperties.java index 7ba7099ef7f..fadd4fbb37c 100644 --- a/src/test/java/seedu/address/testutil/TypicalProperties.java +++ b/src/test/java/seedu/address/testutil/TypicalProperties.java @@ -72,7 +72,6 @@ public static PropertyBook getTypicalPropertyBook() { } public static List getTypicalProperties() { - return new ArrayList<>(Arrays.asList(AQUAVISTA, AQUAVIEW, SKYVISTA, HORIZONVIEW, - LUXELOFT, RIVERIA, AZURE, TRANQUILIS)); + return new ArrayList<>(Arrays.asList(AQUAVISTA, SKYVISTA, HORIZONVIEW, LUXELOFT, RIVERIA, AZURE, TRANQUILIS)); } }