diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 8b6f44abf42..4c0fa8aab30 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -37,6 +37,7 @@ public class LogicManager implements Logic { private final EventManager eventManager; + /** * Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}. */ @@ -52,7 +53,15 @@ public CommandResult execute(String commandText) throws CommandException, ParseE logger.info("----------------[USER COMMAND][" + commandText + "]"); CommandResult commandResult; - Command contactCommand = addressBookParser.parseCommand(commandText); + Command contactCommand; + if (model.getSearchMode()) { + logger.info("Searchmode command detected"); + contactCommand = addressBookParser.parseSearchCommand(commandText); + + } else { + contactCommand = addressBookParser.parseCommand(commandText); + + } commandResult = contactCommand.execute(model, eventManager); try { diff --git a/src/main/java/seedu/address/logic/commands/contact/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/contact/commands/FindCommand.java index 0656ed63f30..c01b81591c8 100644 --- a/src/main/java/seedu/address/logic/commands/contact/commands/FindCommand.java +++ b/src/main/java/seedu/address/logic/commands/contact/commands/FindCommand.java @@ -8,7 +8,7 @@ import seedu.address.logic.commands.CommandResult; import seedu.address.model.Model; import seedu.address.model.event.EventManager; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; /** * Finds and lists all persons in address book whose name contains any of the argument keywords. diff --git a/src/main/java/seedu/address/logic/commands/contact/commands/SearchCommand.java b/src/main/java/seedu/address/logic/commands/contact/commands/SearchCommand.java index e59852738e8..d5b4f1e2041 100644 --- a/src/main/java/seedu/address/logic/commands/contact/commands/SearchCommand.java +++ b/src/main/java/seedu/address/logic/commands/contact/commands/SearchCommand.java @@ -8,7 +8,7 @@ import seedu.address.logic.commands.CommandResult; import seedu.address.model.Model; import seedu.address.model.event.EventManager; -import seedu.address.model.person.PersonIsRolePredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; /** * Finds and lists all persons in address book who has any role equal to any of the role keywords. diff --git a/src/main/java/seedu/address/logic/commands/searchmode/ExitSearchModeCommand.java b/src/main/java/seedu/address/logic/commands/searchmode/ExitSearchModeCommand.java new file mode 100644 index 00000000000..2272595f350 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/searchmode/ExitSearchModeCommand.java @@ -0,0 +1,38 @@ +package seedu.address.logic.commands.searchmode; + +import static java.util.Objects.requireNonNull; + +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.model.Model; +import seedu.address.model.event.EventManager; + + +/** + * Exits search mode. + */ +public class ExitSearchModeCommand extends Command { + public static final String COMMAND_WORD = "exitsearchmode"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Exits search mode.\n" + + "Example: " + COMMAND_WORD; + + public static final String MESSAGE_SUCCESS = "Exited search mode."; + + public ExitSearchModeCommand() { + } + @Override + public CommandResult execute(Model model, EventManager eventManager) { + requireNonNull(model); + model.setSearchMode(false); + model.updateFilteredPersonList(Model.PREDICATE_SHOW_ALL_PERSONS); + return new CommandResult(MESSAGE_SUCCESS); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || other instanceof ExitSearchModeCommand; // instanceof handles nulls + } + +} diff --git a/src/main/java/seedu/address/logic/commands/searchmode/InitSearchModeCommand.java b/src/main/java/seedu/address/logic/commands/searchmode/InitSearchModeCommand.java new file mode 100644 index 00000000000..41e8c610aef --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/searchmode/InitSearchModeCommand.java @@ -0,0 +1,33 @@ +package seedu.address.logic.commands.searchmode; + +import static java.util.Objects.requireNonNull; + +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.model.Model; +import seedu.address.model.event.EventManager; + + +/** + * Enters search mode. + */ +public class InitSearchModeCommand extends Command { + public static final String COMMAND_WORD = "searchmode"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Enters search mode.\n" + + "Example: " + COMMAND_WORD; + + public static final String MESSAGE_SUCCESS = "Entered search mode."; + + public InitSearchModeCommand() { + } + @Override + public CommandResult execute(Model model, EventManager eventManager) { + requireNonNull(model); + model.setSearchMode(true); + // empties the current displayed list + model.updateFilteredPersonList(person -> false); + return new CommandResult(MESSAGE_SUCCESS); + } + +} diff --git a/src/main/java/seedu/address/logic/commands/searchmode/SearchModeSearchCommand.java b/src/main/java/seedu/address/logic/commands/searchmode/SearchModeSearchCommand.java new file mode 100644 index 00000000000..c61c9fad09e --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/searchmode/SearchModeSearchCommand.java @@ -0,0 +1,59 @@ +package seedu.address.logic.commands.searchmode; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; + +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.model.Model; +import seedu.address.model.event.EventManager; +import seedu.address.model.person.Person; + + +/** + * Searches for all persons in the address book whose names contain all the specified keywords. + */ +public class SearchModeSearchCommand extends Command { + public static final String COMMAND_WORD = "search"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Searches for all persons whose fields contain the specified keywords (case-insensitive) " + + "and displays them as a list with index numbers.\n" + + "Parameters: [Flag] [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " n/Amy Bob Charlie"; + + public static final String MESSAGE_SUCCESS = "Added all Persons who fit search parameter"; + + //maintains a set of predicates, reducing them to get the final predicate in execute + private final Set> predicates = new HashSet<>(); + + public SearchModeSearchCommand(Predicate predicate) { + this.predicates.add(predicate); + } + + public SearchModeSearchCommand(Set> predicates) { + this.predicates.addAll(predicates); + } + + @Override + public CommandResult execute(Model model, EventManager eventManager) { + // combine the new predicates with the old ones + Predicate currPredicate = model.getLastPredicate(); + Predicate predicate = predicates.stream().reduce(Predicate::and).orElse(x -> true); + Predicate newPredicate = currPredicate.or(predicate); + model.updateFilteredPersonList(newPredicate); + return new CommandResult(MESSAGE_SUCCESS); + } + + public Set> getPredicates() { + return predicates; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof SearchModeSearchCommand // instanceof handles nulls + && predicates.equals(((SearchModeSearchCommand) other).predicates)); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 4ccd12f90a9..8386308b5bf 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -22,6 +22,9 @@ import seedu.address.logic.commands.event.commands.AddPersonToEventCommand; import seedu.address.logic.commands.event.commands.RemovePersonFromEventCommand; import seedu.address.logic.commands.event.commands.ViewEventCommand; +import seedu.address.logic.commands.searchmode.ExitSearchModeCommand; +import seedu.address.logic.commands.searchmode.InitSearchModeCommand; +import seedu.address.logic.commands.searchmode.SearchModeSearchCommand; import seedu.address.logic.parser.contact.parser.AddCommandParser; import seedu.address.logic.parser.contact.parser.DeleteCommandParser; import seedu.address.logic.parser.contact.parser.EditCommandParser; @@ -97,6 +100,9 @@ public Command parseCommand(String userInput) throws ParseException { case AddEventCommand.COMMAND_WORD: return new NewEventCommandParser().parse(arguments); + case InitSearchModeCommand.COMMAND_WORD: + return new InitSearchModeCommand(); + case ViewEventCommand.COMMAND_WORD: return new ViewEventCommandParser().parse(arguments); @@ -112,4 +118,36 @@ public Command parseCommand(String userInput) throws ParseException { } } + /** + * Parses user input into command for execution in search mode. + * + * @param userInput full user input string + * @return the command based on the user input + * @throws ParseException if the user input does not conform the expected format + */ + public Command parseSearchCommand(String userInput) throws ParseException { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + if (!matcher.matches()) { + logger.warning("This user input caused a ParseException: " + userInput); + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + final String arguments = matcher.group("arguments"); + + // Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower) + // log messages such as the one below. + // Lower level log messages are used sparingly to minimize noise in the code. + logger.fine("Using SearchCommandParser to parse user input: " + userInput); + logger.fine("Command word: " + commandWord + "; Arguments: " + arguments); + switch (commandWord) { + case ExitSearchModeCommand.COMMAND_WORD: + return new ExitSearchModeCommand(); + case SearchModeSearchCommand.COMMAND_WORD: + return new SearchModeSearchCommandParser().parse(arguments); + default: + throw new ParseException(MESSAGE_UNKNOWN_COMMAND); + } + } + } diff --git a/src/main/java/seedu/address/logic/parser/SearchModeSearchCommandParser.java b/src/main/java/seedu/address/logic/parser/SearchModeSearchCommandParser.java new file mode 100644 index 00000000000..0e9a6405e43 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/SearchModeSearchCommandParser.java @@ -0,0 +1,141 @@ +package seedu.address.logic.parser; + + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ROLE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TELEGRAM; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import seedu.address.logic.Messages; +import seedu.address.logic.commands.searchmode.SearchModeSearchCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.Person; +import seedu.address.model.person.predicates.AddressContainsKeywordsPredicate; +import seedu.address.model.person.predicates.EmailContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; +import seedu.address.model.person.predicates.PhoneNumberContainsKeywordPredicate; +import seedu.address.model.person.predicates.TelegramContainsKeywordsPredicate; +import seedu.address.model.role.Role; + +/** + * Parses input arguments and creates a new SearchModeSearchCommand object + */ +public class SearchModeSearchCommandParser implements Parser { + private static final Logger logger = Logger.getLogger(SearchModeSearchCommandParser.class.getName()); + @Override + public SearchModeSearchCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, + PREFIX_TELEGRAM, PREFIX_ROLE); + argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, + PREFIX_TELEGRAM, PREFIX_ROLE); + //for each prefix, if present, parse the value and create a predicate... + // combine the predicates using AND + // return the search command with the predicate + // original predicate just show all + Set> predicates = new HashSet<>(); + // if a field is present, AND with the predicate for that field + if (argMultimap.getValue(PREFIX_NAME).isPresent()) { + Predicate namePred = createPersonPredicate(argMultimap); + predicates.add(namePred); + } + if (argMultimap.getValue(PREFIX_PHONE).isPresent()) { + Predicate phonePred = createPhonePredicate(argMultimap); + predicates.add(phonePred); + } + if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { + Predicate emailPred = createEmailPredicate(argMultimap); + predicates.add(emailPred); + } + if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { + Predicate addressPred = createAddressPredicate(argMultimap); + + predicates.add(addressPred); + } + if (argMultimap.getValue(PREFIX_TELEGRAM).isPresent()) { + Predicate telegramPred = createTelegramPredicate(argMultimap); + predicates.add(telegramPred); + } + //role have to use separate predicate + if (argMultimap.getValue(PREFIX_ROLE).isPresent()) { + Predicate rolePred = createRolePredicate(argMultimap); + predicates.add(rolePred); + } + if (predicates.isEmpty()) { + throw new ParseException(String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, + SearchModeSearchCommand.MESSAGE_USAGE)); + } + return new SearchModeSearchCommand(predicates); + } + + private static Predicate createRolePredicate(ArgumentMultimap argMultimap) throws ParseException { + String roles = argMultimap.getValue(PREFIX_ROLE).get().trim(); + // map each word in String roles to a Role object + + + Set roleSet = ParserUtil.parseRoles(argMultimap.getAllValues(PREFIX_ROLE)); + List roleList = roleSet.stream().collect(Collectors.toList()); + + Predicate rolePred = new PersonIsRolePredicate(roleList); + return rolePred; + } + + private static Predicate createTelegramPredicate(ArgumentMultimap argMultimap) { + String telegram = argMultimap.getValue(PREFIX_TELEGRAM).get().trim(); + String[] telegramKeywords = telegram.split("\\s+"); + Predicate telegramPred = new TelegramContainsKeywordsPredicate( + Arrays.stream(telegramKeywords).toList()); + return telegramPred; + } + + private static Predicate createAddressPredicate(ArgumentMultimap argMultimap) { + String address = argMultimap.getValue(PREFIX_ADDRESS).get().trim(); + String[] addressKeywords = address.split("\\s+"); + Predicate addressPred = new AddressContainsKeywordsPredicate( + Arrays.stream(addressKeywords).toList()); + return addressPred; + } + + private static Predicate createEmailPredicate(ArgumentMultimap argMultimap) { + String email = argMultimap.getValue(PREFIX_EMAIL).get().trim(); + String[] emailKeywords = email.split("\\s+"); + + Predicate emailPred = new EmailContainsKeywordsPredicate( + Arrays.stream(emailKeywords).toList()); + return emailPred; + } + + private static Predicate createPhonePredicate(ArgumentMultimap argMultimap) { + String phone = argMultimap.getValue(PREFIX_PHONE).get().trim(); + String[] phoneKeywords = phone.split("\\s+"); + + Predicate phonePred = new PhoneNumberContainsKeywordPredicate( + Arrays.stream(phoneKeywords).toList()); + return phonePred; + } + + private static Predicate createPersonPredicate(ArgumentMultimap argMultimap) { + String name = argMultimap.getValue(PREFIX_NAME).get().trim(); + + String[] nameKeywords = name.split("\\s+"); + + Predicate namePred = new NameContainsKeywordsPredicate( + Arrays.stream(nameKeywords).toList()); + return namePred; + } + + +} diff --git a/src/main/java/seedu/address/logic/parser/contact/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/contact/parser/FindCommandParser.java index 33b906710d6..cbec95fe5cd 100644 --- a/src/main/java/seedu/address/logic/parser/contact/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/contact/parser/FindCommandParser.java @@ -7,7 +7,7 @@ import seedu.address.logic.commands.contact.commands.FindCommand; import seedu.address.logic.parser.Parser; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; /** * Parses input arguments and creates a new FindCommand object diff --git a/src/main/java/seedu/address/logic/parser/contact/parser/SearchCommandParser.java b/src/main/java/seedu/address/logic/parser/contact/parser/SearchCommandParser.java index 5460da61aa2..81b832cceb9 100644 --- a/src/main/java/seedu/address/logic/parser/contact/parser/SearchCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/contact/parser/SearchCommandParser.java @@ -10,7 +10,7 @@ import seedu.address.logic.commands.contact.commands.SearchCommand; import seedu.address.logic.parser.Parser; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.PersonIsRolePredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; import seedu.address.model.role.Role; diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index c779a98360b..4b4f121b6b0 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -105,4 +105,20 @@ public interface Model { * @throws NullPointerException if {@code predicate} is null. */ void updateFilteredPersonList(Predicate predicate); + + /** + * Sets the search mode to the given {@code searchMode}. + */ + void setSearchMode(boolean searchMode); + + /** + * Returns the search mode. + */ + boolean getSearchMode(); + + /** + * Returns the last predicate used to filter the person list. + */ + Predicate getLastPredicate(); + } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 07e359e45bc..75be888fc20 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -26,6 +26,9 @@ public class ModelManager implements Model { private final EventManager eventManager; private final FilteredList filteredPersons; + private boolean searchMode = false; + private Predicate lastPredicate = PREDICATE_SHOW_ALL_PERSONS; + /** * Initializes a ModelManager with the given addressBook and userPrefs. */ @@ -155,6 +158,25 @@ public ObservableList getFilteredPersonList() { public void updateFilteredPersonList(Predicate predicate) { requireNonNull(predicate); filteredPersons.setPredicate(predicate); + lastPredicate = predicate; + } + + public Predicate getLastPredicate() { + return lastPredicate; + } + + /** + * Checks the search mode of the model. + */ + public boolean getSearchMode() { + return searchMode; + } + + /** + * Sets the search mode of the model. + */ + public void setSearchMode(boolean searchMode) { + this.searchMode = searchMode; } @Override diff --git a/src/main/java/seedu/address/model/person/predicates/AddressContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/predicates/AddressContainsKeywordsPredicate.java new file mode 100644 index 00000000000..4d52308b3a7 --- /dev/null +++ b/src/main/java/seedu/address/model/person/predicates/AddressContainsKeywordsPredicate.java @@ -0,0 +1,57 @@ +package seedu.address.model.person.predicates; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.person.Person; + +/** + * Tests that a {@code Person}'s {@code Address} matches any of the keywords given. + */ +public class AddressContainsKeywordsPredicate implements Predicate { + private final List keywords; + + /** + * Constructor for AddressContainsKeywordsPredicate. Filters empty and trims input + * @param keywords List of keywords to search for in the address field. + */ + public AddressContainsKeywordsPredicate(List keywords) { + this.keywords = + keywords.stream() + .filter(keyword -> !keyword.isBlank()) + .map(keyword -> keyword.trim()) + .collect(Collectors.toList()); + } + + @Override + public boolean test(Person person) { + + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getAddress().value, keyword)) + || keywords.stream().allMatch(keyword -> + person.getAddress().value.toLowerCase().contains(keyword.toLowerCase())); + } + + @Override + public int hashCode() { + return keywords.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof AddressContainsKeywordsPredicate)) { + return false; + } + + AddressContainsKeywordsPredicate otherAddressContainsKeywordsPredicate = + (AddressContainsKeywordsPredicate) other; + return keywords.equals(otherAddressContainsKeywordsPredicate.keywords); + } +} diff --git a/src/main/java/seedu/address/model/person/predicates/EmailContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/predicates/EmailContainsKeywordsPredicate.java new file mode 100644 index 00000000000..ffa0c96047a --- /dev/null +++ b/src/main/java/seedu/address/model/person/predicates/EmailContainsKeywordsPredicate.java @@ -0,0 +1,56 @@ +package seedu.address.model.person.predicates; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.person.Person; + +/** + * Tests that a {@code Person}'s {@code Email} matches any of the keywords given. + */ +public class EmailContainsKeywordsPredicate implements Predicate { + + private final List keywords; + + /** + * Constructor for EmailContainsKeywordsPredicate. Filters empty and trims input + * @param keywords List of keywords to search for in the email field. + */ + public EmailContainsKeywordsPredicate(List keywords) { + this.keywords = + keywords.stream() + .filter(keyword -> !keyword.isBlank()) + .map(keyword -> keyword.trim()) + .collect(Collectors.toList()); + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getEmail().value, keyword) + || person.getEmail().value.toLowerCase().contains(keyword.toLowerCase())); + } + + @Override + public int hashCode() { + return keywords.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EmailContainsKeywordsPredicate)) { + return false; + } + + EmailContainsKeywordsPredicate otherEmailContainsKeywordsPredicate = (EmailContainsKeywordsPredicate) other; + return keywords.equals(otherEmailContainsKeywordsPredicate.keywords); + } + +} diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/predicates/NameContainsKeywordsPredicate.java similarity index 51% rename from src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java rename to src/main/java/seedu/address/model/person/predicates/NameContainsKeywordsPredicate.java index 62d19be2977..8b40a43da37 100644 --- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java +++ b/src/main/java/seedu/address/model/person/predicates/NameContainsKeywordsPredicate.java @@ -1,10 +1,12 @@ -package seedu.address.model.person; +package seedu.address.model.person.predicates; import java.util.List; import java.util.function.Predicate; +import java.util.stream.Collectors; import seedu.address.commons.util.StringUtil; import seedu.address.commons.util.ToStringBuilder; +import seedu.address.model.person.Person; /** * Tests that a {@code Person}'s {@code Name} matches any of the keywords given. @@ -12,14 +14,31 @@ public class NameContainsKeywordsPredicate implements Predicate { private final List keywords; + /** + * Constructor for NameContainsKeywordsPredicate. Filters empty and trims input + * @param keywords List of keywords to search for in the name field. + */ public NameContainsKeywordsPredicate(List keywords) { - this.keywords = keywords; + this.keywords = + keywords.stream() + .filter(keyword -> !keyword.isBlank()) + .map(keyword -> keyword.trim()) + .collect(Collectors.toList()); + } @Override public boolean test(Person person) { - return keywords.stream() - .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)); + if (keywords.isEmpty()) { + return false; + } + List filteredKeywords = keywords.stream() + .filter(keyword -> !keyword.isBlank()) + .collect(Collectors.toList()); + return filteredKeywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)) + || filteredKeywords.stream().allMatch(keyword -> person.getName().fullName.toLowerCase() + .contains(keyword.toLowerCase())); } @Override @@ -37,6 +56,11 @@ public boolean equals(Object other) { return keywords.equals(otherNameContainsKeywordsPredicate.keywords); } + @Override + public int hashCode() { + return keywords.hashCode(); + } + @Override public String toString() { return new ToStringBuilder(this).add("keywords", keywords).toString(); diff --git a/src/main/java/seedu/address/model/person/PersonIsRolePredicate.java b/src/main/java/seedu/address/model/person/predicates/PersonIsRolePredicate.java similarity index 86% rename from src/main/java/seedu/address/model/person/PersonIsRolePredicate.java rename to src/main/java/seedu/address/model/person/predicates/PersonIsRolePredicate.java index 89d6e6341da..8b3d0cfed35 100644 --- a/src/main/java/seedu/address/model/person/PersonIsRolePredicate.java +++ b/src/main/java/seedu/address/model/person/predicates/PersonIsRolePredicate.java @@ -1,9 +1,10 @@ -package seedu.address.model.person; +package seedu.address.model.person.predicates; import java.util.List; import java.util.function.Predicate; import seedu.address.commons.util.ToStringBuilder; +import seedu.address.model.person.Person; import seedu.address.model.role.Role; /** @@ -37,6 +38,11 @@ public boolean equals(Object other) { return roles.equals(otherPersonIsRolePredicate.roles); } + @Override + public int hashCode() { + return roles.hashCode(); + } + @Override public String toString() { return new ToStringBuilder(this).add("roles", roles).toString(); diff --git a/src/main/java/seedu/address/model/person/predicates/PhoneNumberContainsKeywordPredicate.java b/src/main/java/seedu/address/model/person/predicates/PhoneNumberContainsKeywordPredicate.java new file mode 100644 index 00000000000..244e6eacbe9 --- /dev/null +++ b/src/main/java/seedu/address/model/person/predicates/PhoneNumberContainsKeywordPredicate.java @@ -0,0 +1,56 @@ +package seedu.address.model.person.predicates; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.person.Person; + +/** + * Tests that a {@code Person}'s {@code Phone} matches any of the keywords given. + */ +public class PhoneNumberContainsKeywordPredicate implements Predicate { + private final List keywords; + + /** + * Constructor for PhoneNumberContainsKeywordPredicate. Filters empty and trims input + * @param keywords List of keywords to search for in the phone number field. + */ + public PhoneNumberContainsKeywordPredicate(List keywords) { + this.keywords = + keywords.stream() + .filter(keyword -> !keyword.isBlank()) + .map(keyword -> keyword.trim()) + .collect(Collectors.toList()); + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getPhone().value, keyword)) + || keywords.stream().allMatch(keyword -> person.getPhone().value.toLowerCase() + .contains(keyword.toLowerCase())); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof PhoneNumberContainsKeywordPredicate)) { + return false; + } + + PhoneNumberContainsKeywordPredicate otherPhoneNumberContainsKeywordPredicate = + (PhoneNumberContainsKeywordPredicate) other; + return keywords.equals(otherPhoneNumberContainsKeywordPredicate.keywords); + } + + @Override + public int hashCode() { + return keywords.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/person/predicates/TelegramContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/predicates/TelegramContainsKeywordsPredicate.java new file mode 100644 index 00000000000..c13fa97fee0 --- /dev/null +++ b/src/main/java/seedu/address/model/person/predicates/TelegramContainsKeywordsPredicate.java @@ -0,0 +1,56 @@ +package seedu.address.model.person.predicates; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.person.Person; + +/** + * Tests that a {@code Person}'s {@code Telegram} matches any of the keywords given. + */ +public class TelegramContainsKeywordsPredicate implements Predicate { + private final List keywords; + + /** + * Constructor for TelegramContainsKeywordsPredicate. Filters empty and trims input + * @param keywords List of keywords to search for in the telegram field. + */ + public TelegramContainsKeywordsPredicate(List keywords) { + this.keywords = + keywords.stream() + .filter(keyword -> !keyword.isBlank()) + .map(keyword -> keyword.trim()) + .collect(Collectors.toList()); + } + + @Override + public boolean test(Person person) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getTelegramUsername().toString(), keyword) + || person.getTelegramUsername().toString() + .toLowerCase().contains(keyword.toLowerCase())); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof TelegramContainsKeywordsPredicate)) { + return false; + } + + TelegramContainsKeywordsPredicate otherTelegramContainsKeywordsPredicate = + (TelegramContainsKeywordsPredicate) other; + return keywords.equals(otherTelegramContainsKeywordsPredicate.keywords); + } + + @Override + public int hashCode() { + return keywords.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/role/Role.java b/src/main/java/seedu/address/model/role/Role.java index 55d03ed1b35..a4f2f8f534a 100644 --- a/src/main/java/seedu/address/model/role/Role.java +++ b/src/main/java/seedu/address/model/role/Role.java @@ -128,4 +128,6 @@ public boolean isTagged(Person person) { public String getRoleName() { return roleName; } + + } diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java index 5c160772b9e..95e1e79fe43 100644 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ b/src/test/java/seedu/address/logic/LogicManagerTest.java @@ -88,6 +88,7 @@ public void execute_storageThrowsAdException_throwsCommandException() { LogicManager.FILE_OPS_PERMISSION_ERROR_FORMAT, DUMMY_AD_EXCEPTION.getMessage())); } + @Test public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() { assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredPersonList().remove(0)); diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 899cad086a2..e92d2f9f256 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -20,8 +20,8 @@ import seedu.address.model.AddressBook; import seedu.address.model.Model; import seedu.address.model.event.EventManager; -import seedu.address.model.person.NameContainsKeywordsPredicate; import seedu.address.model.person.Person; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; import seedu.address.testutil.EditPersonDescriptorBuilder; /** diff --git a/src/test/java/seedu/address/logic/commands/contact/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/contact/commands/AddCommandTest.java index 3794206b3ed..a3f71610c24 100644 --- a/src/test/java/seedu/address/logic/commands/contact/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/contact/commands/AddCommandTest.java @@ -177,6 +177,22 @@ public ObservableList getFilteredPersonList() { public void updateFilteredPersonList(Predicate predicate) { throw new AssertionError("This method should not be called."); } + + + @Override + public void setSearchMode(boolean searchMode) { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean getSearchMode() { + throw new AssertionError("This method should not be called."); + } + + @Override + public Predicate getLastPredicate() { + throw new AssertionError("This method should not be called."); + } } /** diff --git a/src/test/java/seedu/address/logic/commands/contact/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/contact/commands/FindCommandTest.java index 09036371b2a..9e023b78a72 100644 --- a/src/test/java/seedu/address/logic/commands/contact/commands/FindCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/contact/commands/FindCommandTest.java @@ -19,7 +19,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; /** * Contains integration tests (interaction with the Model) for {@code FindCommand}. diff --git a/src/test/java/seedu/address/logic/commands/contact/commands/SearchCommandTest.java b/src/test/java/seedu/address/logic/commands/contact/commands/SearchCommandTest.java index f814a96f5d9..eb982203c1c 100644 --- a/src/test/java/seedu/address/logic/commands/contact/commands/SearchCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/contact/commands/SearchCommandTest.java @@ -19,7 +19,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; -import seedu.address.model.person.PersonIsRolePredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; import seedu.address.model.role.Sponsor; import seedu.address.model.role.Vendor; import seedu.address.model.role.Volunteer; @@ -56,6 +56,7 @@ public void equals() { // different person -> returns false assertFalse(searchFirstCommand.equals(searchSecondCommand)); + } @Test diff --git a/src/test/java/seedu/address/logic/commands/searchmode/ExitSearchModeCommandTest.java b/src/test/java/seedu/address/logic/commands/searchmode/ExitSearchModeCommandTest.java new file mode 100644 index 00000000000..62cc3e3a158 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/searchmode/ExitSearchModeCommandTest.java @@ -0,0 +1,43 @@ +package seedu.address.logic.commands.searchmode; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.ModelManager; + + +public class ExitSearchModeCommandTest { + private ModelManager model = new ModelManager(); + + + + @Test + public void execute() { + ExitSearchModeCommand command = new ExitSearchModeCommand(); + model.setSearchMode(true); + command.execute(model, null); + assertEquals(model.getSearchMode(), false); + + + } + + @Test + public void equals() { + ExitSearchModeCommand command = new ExitSearchModeCommand(); + assertEquals(command, new ExitSearchModeCommand()); + } + + @Test + public void equals_sameObject_returnTrue() { + ExitSearchModeCommand command = new ExitSearchModeCommand(); + assertEquals(command.equals(command), true); + } + + @Test + public void equals_diffObject_returnFalse() { + ExitSearchModeCommand command = new ExitSearchModeCommand(); + assertEquals(command.equals(new Object()), false); + } + +} diff --git a/src/test/java/seedu/address/logic/commands/searchmode/SearchModeSearchCommandTest.java b/src/test/java/seedu/address/logic/commands/searchmode/SearchModeSearchCommandTest.java new file mode 100644 index 00000000000..9b39aa991e6 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/searchmode/SearchModeSearchCommandTest.java @@ -0,0 +1,147 @@ +package seedu.address.logic.commands.searchmode; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.Collections; +import java.util.function.Predicate; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.CommandResult; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.person.Person; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; +import seedu.address.model.role.RoleHandler; +import seedu.address.model.role.exceptions.InvalidRoleException; + +public class SearchModeSearchCommandTest { + + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(); + expectedModel = new ModelManager(); + } + + @Test + public void execute_validPredicate_success() { + Predicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + + SearchModeSearchCommand command = new SearchModeSearchCommand(predicate); + + model.updateFilteredPersonList(predicate); + CommandResult result = command.execute(model, null); + + assertEquals(SearchModeSearchCommand.MESSAGE_SUCCESS, result.getFeedbackToUser()); + assertEquals(model.getFilteredPersonList(), expectedModel.getFilteredPersonList()); + } + + @Test + public void equals_samePredicate_returnsTrue() { + Predicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + + SearchModeSearchCommand command1 = new SearchModeSearchCommand(predicate); + SearchModeSearchCommand command2 = new SearchModeSearchCommand(predicate); + + assertEquals(command1, command2); + } + + + + @Test + public void equals_differentPredicate_returnsFalse() { + Predicate predicate1 = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + Predicate predicate2 = new NameContainsKeywordsPredicate(Collections.singletonList("Bob")); + SearchModeSearchCommand command1 = new SearchModeSearchCommand(predicate1); + SearchModeSearchCommand command2 = new SearchModeSearchCommand(predicate2); + + assertNotEquals(command1, command2); + } + + @Test + public void equals_differentObject_returnsFalse() { + Predicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + SearchModeSearchCommand command = new SearchModeSearchCommand(predicate); + + assertNotEquals(command, new Object()); + } + + @Test + public void equals_null_returnsFalse() { + Predicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + SearchModeSearchCommand command = new SearchModeSearchCommand(predicate); + + assertNotEquals(command, null); + } + + @Test + public void execute_combinedPredicate_success() throws InvalidRoleException { + Predicate namePredicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + Predicate rolePredicate = new PersonIsRolePredicate( + Collections.singletonList(RoleHandler.getRole("vendor"))); + Predicate combinedPredicate = namePredicate.and(rolePredicate); + + SearchModeSearchCommand command = new SearchModeSearchCommand(combinedPredicate); + + model.updateFilteredPersonList(combinedPredicate); + CommandResult result = command.execute(model, null); + + assertEquals(SearchModeSearchCommand.MESSAGE_SUCCESS, result.getFeedbackToUser()); + assertEquals(model.getFilteredPersonList(), expectedModel.getFilteredPersonList()); + } + + + @Test + public void execute_chainedPredicates_success() throws InvalidRoleException { + Predicate namePredicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + Predicate rolePredicate = new PersonIsRolePredicate( + Collections.singletonList(RoleHandler.getRole("vendor"))); + Predicate combinedPredicate = namePredicate.and(rolePredicate); + + SearchModeSearchCommand command = new SearchModeSearchCommand(combinedPredicate); + + model.updateFilteredPersonList(combinedPredicate); + CommandResult result = command.execute(model, null); + + assertEquals(SearchModeSearchCommand.MESSAGE_SUCCESS, result.getFeedbackToUser()); + assertEquals(model.getFilteredPersonList(), expectedModel.getFilteredPersonList()); + } + + @Test + public void execute_orPredicates_success() throws InvalidRoleException { + Predicate namePredicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + Predicate rolePredicate = new PersonIsRolePredicate( + Collections.singletonList(RoleHandler.getRole("vendor"))); + Predicate combinedPredicate = namePredicate.or(rolePredicate); + + SearchModeSearchCommand command = new SearchModeSearchCommand(combinedPredicate); + + model.updateFilteredPersonList(combinedPredicate); + CommandResult result = command.execute(model, null); + + assertEquals(SearchModeSearchCommand.MESSAGE_SUCCESS, result.getFeedbackToUser()); + assertEquals(model.getFilteredPersonList(), expectedModel.getFilteredPersonList()); + } + + @Test + public void execute_negatedPredicate_success() { + Predicate namePredicate = new NameContainsKeywordsPredicate(Collections.singletonList("Amy")); + Predicate negatedPredicate = namePredicate.negate(); + + SearchModeSearchCommand command = new SearchModeSearchCommand(negatedPredicate); + + model.updateFilteredPersonList(negatedPredicate); + CommandResult result = command.execute(model, null); + + assertEquals(SearchModeSearchCommand.MESSAGE_SUCCESS, result.getFeedbackToUser()); + assertEquals(model.getFilteredPersonList(), expectedModel.getFilteredPersonList()); + } + + +} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 72e098dc3a1..683826d33bc 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -29,11 +29,13 @@ import seedu.address.logic.commands.event.commands.AddEventCommand; import seedu.address.logic.commands.event.commands.RemovePersonFromEventCommand; import seedu.address.logic.commands.event.commands.ViewEventCommand; +import seedu.address.logic.commands.searchmode.ExitSearchModeCommand; +import seedu.address.logic.commands.searchmode.SearchModeSearchCommand; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.event.Event; -import seedu.address.model.person.NameContainsKeywordsPredicate; import seedu.address.model.person.Person; -import seedu.address.model.person.PersonIsRolePredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; import seedu.address.model.role.Role; import seedu.address.model.role.Sponsor; import seedu.address.model.role.Volunteer; @@ -141,6 +143,25 @@ public void parseCommand_removePersonFromEvent() throws ParseException { } @Test + public void parseSearchCommand_searchModeSearchCommand() throws ParseException { + Command expected = new SearchModeSearchCommand(new NameContainsKeywordsPredicate(Arrays.asList("Amy"))); + assertEquals(expected, new AddressBookParser() + .parseSearchCommand(SearchModeSearchCommand.COMMAND_WORD + " n/Amy")); + } + + @Test + public void parseSearchCommand_exitSearchModeCommand() throws ParseException { + Command expected = new ExitSearchModeCommand(); + assertEquals(expected, new AddressBookParser() + .parseSearchCommand(ExitSearchModeCommand.COMMAND_WORD)); + } + + @Test + public void parseSearchCommand_unrecognisedInput_throwsParseException() { + assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, + HelpCommand.MESSAGE_USAGE), () -> parser.parseSearchCommand("")); + } + public void parseCommand_viewEvent() throws ParseException { Command expected = new ViewEventCommand(SPORTS_FESTIVAL); assertEquals(expected, new AddressBookParser() diff --git a/src/test/java/seedu/address/logic/parser/SearchModeSearchCommandParserTest.java b/src/test/java/seedu/address/logic/parser/SearchModeSearchCommandParserTest.java new file mode 100644 index 00000000000..8c5aeafdf92 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/SearchModeSearchCommandParserTest.java @@ -0,0 +1,81 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.searchmode.SearchModeSearchCommand; +import seedu.address.model.person.Person; +import seedu.address.model.person.predicates.AddressContainsKeywordsPredicate; +import seedu.address.model.person.predicates.EmailContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; +import seedu.address.model.person.predicates.PhoneNumberContainsKeywordPredicate; +import seedu.address.model.role.RoleHandler; +import seedu.address.model.role.exceptions.InvalidRoleException; + + +public class SearchModeSearchCommandParserTest { + + private SearchModeSearchCommandParser parser = new SearchModeSearchCommandParser(); + + @Test + public void parse_emptyInput_throwsParseException() { + assertParseFailure(parser, "", String.format(MESSAGE_INVALID_COMMAND_FORMAT, + SearchModeSearchCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_validInput_success() { + // whitespace only + SearchModeSearchCommand expectedCommand = new SearchModeSearchCommand( + new NameContainsKeywordsPredicate(Collections.singletonList("Amy"))); + + assertParseSuccess(parser, " n/Amy", expectedCommand); + + // multiple whitespaces + assertParseSuccess(parser, " n/ Amy ", expectedCommand); + + // multiple keywords + expectedCommand = new SearchModeSearchCommand(new NameContainsKeywordsPredicate(Arrays.asList("Amy", "Bob"))); + assertParseSuccess(parser, " n/Amy Bob", expectedCommand); + + // multiple keywords with leading and trailing whitespaces + assertParseSuccess(parser, " n/ Amy Bob ", expectedCommand); + } + + @Test + public void parse_allFieldsSpecified_success() { + + SearchModeSearchCommand expectedCommand = null; + try { + NameContainsKeywordsPredicate namePredicate = new NameContainsKeywordsPredicate( + Collections.singletonList("Amy")); + PhoneNumberContainsKeywordPredicate phonePredicate = new PhoneNumberContainsKeywordPredicate( + Collections.singletonList("1234567")); + EmailContainsKeywordsPredicate emailPredicate = new EmailContainsKeywordsPredicate( + Collections.singletonList("test@gmail.com")); + AddressContainsKeywordsPredicate addressPredicate = new AddressContainsKeywordsPredicate( + new ArrayList<>(Arrays.asList("123", "Road"))); + PersonIsRolePredicate rolePredicate = new PersonIsRolePredicate( + Collections.singletonList(RoleHandler.getRole("attendee"))); + Set> predicates = new HashSet<>(Arrays.asList(namePredicate, phonePredicate, + emailPredicate, addressPredicate, rolePredicate)); + expectedCommand = new SearchModeSearchCommand(predicates); + } catch (InvalidRoleException e) { + assert(false); + } + + assertParseSuccess(parser, " n/Amy p/1234567 e/test@gmail.com" + + " r/attendee a/123 Road", expectedCommand); + } +} diff --git a/src/test/java/seedu/address/logic/parser/contact/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/contact/parser/FindCommandParserTest.java index a231f04416e..f159e4de6f9 100644 --- a/src/test/java/seedu/address/logic/parser/contact/parser/FindCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/contact/parser/FindCommandParserTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.commands.contact.commands.FindCommand; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; public class FindCommandParserTest { diff --git a/src/test/java/seedu/address/logic/parser/contact/parser/SearchCommandParserTest.java b/src/test/java/seedu/address/logic/parser/contact/parser/SearchCommandParserTest.java index 6745abe6685..ab897f24111 100644 --- a/src/test/java/seedu/address/logic/parser/contact/parser/SearchCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/contact/parser/SearchCommandParserTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.commands.contact.commands.SearchCommand; -import seedu.address.model.person.PersonIsRolePredicate; +import seedu.address.model.person.predicates.PersonIsRolePredicate; import seedu.address.model.role.Sponsor; import seedu.address.model.role.Volunteer; diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index 3f91cfc9a03..c7425fcdfbc 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -17,7 +17,7 @@ import seedu.address.commons.core.GuiSettings; import seedu.address.model.event.Event; import seedu.address.model.event.EventManager; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; import seedu.address.testutil.AddressBookBuilder; public class ModelManagerTest { diff --git a/src/test/java/seedu/address/model/predicates/AddressContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/predicates/AddressContainsKeywordsPredicateTest.java new file mode 100644 index 00000000000..d718a9427a4 --- /dev/null +++ b/src/test/java/seedu/address/model/predicates/AddressContainsKeywordsPredicateTest.java @@ -0,0 +1,96 @@ +package seedu.address.model.predicates; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.person.predicates.AddressContainsKeywordsPredicate; +import seedu.address.testutil.PersonBuilder; +public class AddressContainsKeywordsPredicateTest { + + @Test + public void equals() { + List firstPredicateKeywordList = Collections.singletonList("first"); + List secondPredicateKeywordList = Arrays.asList("first", "second"); + + AddressContainsKeywordsPredicate firstPredicate = new AddressContainsKeywordsPredicate( + firstPredicateKeywordList); + AddressContainsKeywordsPredicate secondPredicate = new AddressContainsKeywordsPredicate( + secondPredicateKeywordList); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + AddressContainsKeywordsPredicate firstPredicateCopy = new AddressContainsKeywordsPredicate( + firstPredicateKeywordList); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different person -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_addressContainsKeywords_returnTrue() { + // One keyword + AddressContainsKeywordsPredicate predicate = new AddressContainsKeywordsPredicate(Collections + .singletonList("Jurong")); + assertTrue(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + + // Multiple keywords + predicate = new AddressContainsKeywordsPredicate(Arrays.asList("Jurong", "West")); + assertTrue(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + + // Only one matching keyword + predicate = new AddressContainsKeywordsPredicate(Arrays.asList("Jurong", "East")); + assertTrue(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + + // Mixed-case keywords + predicate = new AddressContainsKeywordsPredicate(Arrays.asList("jUroNg", "wEst")); + assertTrue(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + } + + @Test + public void test_addressPartialKeyword_returnTrue() { + AddressContainsKeywordsPredicate predicate = new AddressContainsKeywordsPredicate( + Collections.singletonList("Juron")); + assertTrue(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + } + + @Test + public void test_addressContainOneKeyword_returnTrue() { + AddressContainsKeywordsPredicate predicate = new AddressContainsKeywordsPredicate( + new ArrayList<>(Arrays.asList("Jurong", "East"))); + assertTrue(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + } + + @Test + public void test_addressDoesNotContainAnyPartial_returnFalse() { + AddressContainsKeywordsPredicate predicate = new AddressContainsKeywordsPredicate( + new ArrayList<>(Arrays.asList("Juron", "East"))); + assertFalse(predicate.test(new PersonBuilder().withAddress("123, Jurong West Ave 6, #08-111").build())); + } + + @Test + public void equals_differentNumberKeywords() { + AddressContainsKeywordsPredicate firstPredicate = new + AddressContainsKeywordsPredicate(Collections.singletonList("first")); + AddressContainsKeywordsPredicate secondPredicate = new + AddressContainsKeywordsPredicate(Arrays.asList("first", "second")); + assertFalse(firstPredicate.equals(secondPredicate)); + } + + +} diff --git a/src/test/java/seedu/address/model/predicates/EmailContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/predicates/EmailContainsKeywordsPredicateTest.java new file mode 100644 index 00000000000..dd3b144bd1d --- /dev/null +++ b/src/test/java/seedu/address/model/predicates/EmailContainsKeywordsPredicateTest.java @@ -0,0 +1,44 @@ +package seedu.address.model.predicates; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.person.predicates.EmailContainsKeywordsPredicate; +import seedu.address.testutil.PersonBuilder; +public class EmailContainsKeywordsPredicateTest { + + @Test + public void test_diffEmail() { + List keywords = Collections.singletonList("emailer@gmail.com"); + EmailContainsKeywordsPredicate predicate = new EmailContainsKeywordsPredicate(keywords); + assertFalse(predicate.test(new PersonBuilder().withEmail("emailer2@gmail.com").build())); + } + + @Test + public void test_partial_returnTrue() { + List keywords = Collections.singletonList("test@gmai"); + EmailContainsKeywordsPredicate predicate = new EmailContainsKeywordsPredicate(keywords); + assertTrue(predicate.test(new PersonBuilder().withEmail("test@gmail.com").build())); + } + + @Test + public void equals_sameObject_returnTrue() { + List keywords = Collections.singletonList("test@gmail.com"); + EmailContainsKeywordsPredicate predicate = new EmailContainsKeywordsPredicate(keywords); + assertTrue(predicate.equals(predicate)); + } + + @Test + public void equals_sameValues_returnTrue() { + List keywords = Collections.singletonList("test@gmail.com"); + EmailContainsKeywordsPredicate predicate = new EmailContainsKeywordsPredicate(keywords); + EmailContainsKeywordsPredicate predicateCopy = new EmailContainsKeywordsPredicate(keywords); + assertTrue(predicate.equals(predicateCopy)); + } +} + diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/predicates/NameContainsKeywordsPredicateTest.java similarity index 83% rename from src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java rename to src/test/java/seedu/address/model/predicates/NameContainsKeywordsPredicateTest.java index 6b3fd90ade7..b9608ac21ed 100644 --- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java +++ b/src/test/java/seedu/address/model/predicates/NameContainsKeywordsPredicateTest.java @@ -1,4 +1,4 @@ -package seedu.address.model.person; +package seedu.address.model.predicates; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; +import seedu.address.model.person.predicates.NameContainsKeywordsPredicate; import seedu.address.testutil.PersonBuilder; public class NameContainsKeywordsPredicateTest { @@ -74,6 +75,20 @@ public void test_nameDoesNotContainKeywords_returnsFalse() { .withEmail("alice@email.com").withAddress("Main Street").build())); } + @Test + public void test_namePartialKeyword_returnTrue() { + NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate( + Collections.singletonList("Ali")); + assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build())); + } + + @Test + public void test_nameNotAllMatch_returnFalse() { + NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate( + Arrays.asList("Ali", "Co")); + assertFalse(predicate.test(new PersonBuilder().withName("Alice Bob").build())); + } + @Test public void toStringMethod() { List keywords = List.of("keyword1", "keyword2"); @@ -82,4 +97,6 @@ public void toStringMethod() { String expected = NameContainsKeywordsPredicate.class.getCanonicalName() + "{keywords=" + keywords + "}"; assertEquals(expected, predicate.toString()); } + + } diff --git a/src/test/java/seedu/address/model/person/PersonIsRolePredicateTest.java b/src/test/java/seedu/address/model/predicates/PersonIsRolePredicateTest.java similarity index 96% rename from src/test/java/seedu/address/model/person/PersonIsRolePredicateTest.java rename to src/test/java/seedu/address/model/predicates/PersonIsRolePredicateTest.java index 9b26ee5a254..edaf2d20b59 100644 --- a/src/test/java/seedu/address/model/person/PersonIsRolePredicateTest.java +++ b/src/test/java/seedu/address/model/predicates/PersonIsRolePredicateTest.java @@ -1,4 +1,4 @@ -package seedu.address.model.person; +package seedu.address.model.predicates; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; +import seedu.address.model.person.predicates.PersonIsRolePredicate; import seedu.address.model.role.Attendee; import seedu.address.model.role.Role; import seedu.address.model.role.Sponsor; diff --git a/src/test/java/seedu/address/model/predicates/PhoneNumberContainsKeywordPredicateTest.java b/src/test/java/seedu/address/model/predicates/PhoneNumberContainsKeywordPredicateTest.java new file mode 100644 index 00000000000..51d4fef98e8 --- /dev/null +++ b/src/test/java/seedu/address/model/predicates/PhoneNumberContainsKeywordPredicateTest.java @@ -0,0 +1,51 @@ +package seedu.address.model.predicates; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.person.predicates.PhoneNumberContainsKeywordPredicate; +import seedu.address.testutil.PersonBuilder; +public class PhoneNumberContainsKeywordPredicateTest { + + @Test + public void test_diffNumber() { + List keywords = Collections.singletonList("12345678"); + PhoneNumberContainsKeywordPredicate predicate = new PhoneNumberContainsKeywordPredicate(keywords); + assertFalse(predicate.test(new PersonBuilder().withPhone("87654321").build())); + } + + @Test + public void test_samePartial_returnFalse() { + List keywords = Collections.singletonList("12345679"); + PhoneNumberContainsKeywordPredicate predicate = new PhoneNumberContainsKeywordPredicate(keywords); + assertFalse(predicate.test(new PersonBuilder().withPhone("12345678").build())); + } + + @Test + public void test_partialNumber_returnTrue() { + List keywords = Collections.singletonList("1234567"); + PhoneNumberContainsKeywordPredicate predicate = new PhoneNumberContainsKeywordPredicate(keywords); + assertTrue(predicate.test(new PersonBuilder().withPhone("12345678").build())); + } + + @Test + public void test_multiplePartialNumber_returnFalse() { + List keywords = Arrays.asList("1234567", "8765432"); + PhoneNumberContainsKeywordPredicate predicate = new PhoneNumberContainsKeywordPredicate(keywords); + assertFalse(predicate.test(new PersonBuilder().withPhone("12345678").build())); + } + + @Test + public void test_multipleCompelte_returnTrue() { + List keywords = Arrays.asList("12345678", "87654321"); + PhoneNumberContainsKeywordPredicate predicate = new PhoneNumberContainsKeywordPredicate(keywords); + assertTrue(predicate.test(new PersonBuilder().withPhone("12345678").build())); + assertTrue(predicate.test(new PersonBuilder().withPhone("87654321").build())); + } +} diff --git a/src/test/java/seedu/address/model/predicates/TelegramContainsKeywordPredicateTest.java b/src/test/java/seedu/address/model/predicates/TelegramContainsKeywordPredicateTest.java new file mode 100644 index 00000000000..126fe3bb03b --- /dev/null +++ b/src/test/java/seedu/address/model/predicates/TelegramContainsKeywordPredicateTest.java @@ -0,0 +1,59 @@ +package seedu.address.model.predicates; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.person.predicates.TelegramContainsKeywordsPredicate; +import seedu.address.testutil.PersonBuilder; +public class TelegramContainsKeywordPredicateTest { + @Test + public void test_diffUsername() { + List keywords = Collections.singletonList("amybee"); + TelegramContainsKeywordsPredicate predicate = new TelegramContainsKeywordsPredicate(keywords); + assertFalse(predicate.test(new PersonBuilder().withTelegramUsername("amybe").build())); + } + + @Test + public void test_samePartial_returnFalse() { + List keywords = Collections.singletonList("amybeee"); + TelegramContainsKeywordsPredicate predicate = new TelegramContainsKeywordsPredicate(keywords); + assertFalse(predicate.test(new PersonBuilder().withTelegramUsername("amybee").build())); + } + + @Test + public void test_partialUsername_returnTrue() { + List keywords = Collections.singletonList("amybe"); + TelegramContainsKeywordsPredicate predicate = new TelegramContainsKeywordsPredicate(keywords); + assertTrue(predicate.test(new PersonBuilder().withTelegramUsername("amybee").build())); + } + + @Test + public void test_multipleComplete_returnTrue() { + List keywords = Arrays.asList("amybee", "john"); + TelegramContainsKeywordsPredicate predicate = new TelegramContainsKeywordsPredicate(keywords); + assertTrue(predicate.test(new PersonBuilder().withTelegramUsername("amybee").build())); + assertTrue(predicate.test(new PersonBuilder().withTelegramUsername("john123").build())); + } + + @Test + public void equals_sameObject_returnTrue() { + List keywords = Collections.singletonList("amybee"); + TelegramContainsKeywordsPredicate predicate = new TelegramContainsKeywordsPredicate(keywords); + assertTrue(predicate.equals(predicate)); + } + + @Test + public void equals_sameValues_returnTrue() { + List keywords = Collections.singletonList("amybee"); + TelegramContainsKeywordsPredicate predicate = new TelegramContainsKeywordsPredicate(keywords); + TelegramContainsKeywordsPredicate predicateCopy = new TelegramContainsKeywordsPredicate(keywords); + assertTrue(predicate.equals(predicateCopy)); + } + +}