diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java index d6b19b0a0de..e60dbbbc51a 100644 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ b/src/main/java/seedu/address/logic/commands/FindCommand.java @@ -1,34 +1,36 @@ package seedu.address.logic.commands; + import static java.util.Objects.requireNonNull; import seedu.address.commons.core.Messages; import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.FindPredicate; + /** - * Finds and lists all persons in address book whose name contains any of the argument keywords. + * Finds and lists all persons in address book whose details contain ALL of the argument keywords provided. * Keyword matching is case insensitive. */ public class FindCommand extends Command { public static final String COMMAND_WORD = "find"; - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of " + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain ALL of " + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; + + "Parameters: n/[name] ... t/[tag] ...\n" + + "Example: " + COMMAND_WORD + " n/alice n/bob t/friends t/colleagues"; - private final NameContainsKeywordsPredicate predicate; + private final FindPredicate findPredicate; - public FindCommand(NameContainsKeywordsPredicate predicate) { - this.predicate = predicate; + public FindCommand(FindPredicate findPredicate) { + this.findPredicate = findPredicate; } @Override public CommandResult execute(Model model) { requireNonNull(model); - model.updateFilteredPersonList(predicate); + model.updateFilteredPersonList(findPredicate); return new CommandResult( String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size())); } @@ -36,7 +38,7 @@ public CommandResult execute(Model model) { @Override public boolean equals(Object other) { return other == this // short circuit if same object - || (other instanceof FindCommand // instanceof handles nulls - && predicate.equals(((FindCommand) other).predicate)); // state check + || ((other instanceof FindCommand) // instanceof handles nulls + && findPredicate.equals(((FindCommand) other).findPredicate)); // state check } } diff --git a/src/main/java/seedu/address/logic/commands/FindOrCommand.java b/src/main/java/seedu/address/logic/commands/FindOrCommand.java new file mode 100644 index 00000000000..64e90cea738 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/FindOrCommand.java @@ -0,0 +1,43 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import seedu.address.commons.core.Messages; +import seedu.address.model.Model; +import seedu.address.model.person.FindOrPredicate; + + +/** + * Finds and lists all persons in address book whose name contains ANY of the argument keywords provided. + * Keyword matching is case insensitive. + */ +public class FindOrCommand extends Command { + + public static final String COMMAND_WORD = "findOr"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain ANY of " + + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" + + "Parameters: n/[name] ... t/[tag] ...\n" + + "Example: " + COMMAND_WORD + " n/alice n/bob t/friends t/colleagues"; + + private final FindOrPredicate findOrPredicate; + + public FindOrCommand(FindOrPredicate findOrPredicate) { + this.findOrPredicate = findOrPredicate; + } + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredPersonList(findOrPredicate); + return new CommandResult( + String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || ((other instanceof FindOrCommand) // instanceof handles nulls + && findOrPredicate.equals(((FindOrCommand) other).findOrPredicate)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 72c95e69e8a..a0a3069cc2c 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -14,6 +14,7 @@ import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.FindCommand; +import seedu.address.logic.commands.FindOrCommand; import seedu.address.logic.commands.FindTagCaseInsensitiveCommand; import seedu.address.logic.commands.FindTagCaseSensitiveCommand; import seedu.address.logic.commands.HelpCommand; @@ -73,6 +74,9 @@ public Command parseCommand(String userInput) throws ParseException { case FindCommand.COMMAND_WORD: return new FindCommandParser().parse(arguments); + case FindOrCommand.COMMAND_WORD: + return new FindOrCommandParser().parse(arguments); + case ListCommand.COMMAND_WORD: return new ListCommand(); diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java index 4fb71f23103..b3ee54fab89 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java @@ -1,12 +1,17 @@ package seedu.address.logic.parser; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; -import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; import seedu.address.logic.commands.FindCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.FindPredicate; +import seedu.address.model.person.Name; +import seedu.address.model.tag.Tag; /** * Parses input arguments and creates a new FindCommand object @@ -25,9 +30,22 @@ public FindCommand parse(String args) throws ParseException { String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); } - String[] nameKeywords = trimmedArgs.split("\\s+"); + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TAG); + List nameStringList = argMultimap.getAllValues(PREFIX_NAME); + List tagStringList = argMultimap.getAllValues(PREFIX_TAG); + + List nameKeywords; + List tagList; + try { + nameKeywords = nameStringList.stream().map(Name::new).collect(Collectors.toList()); + tagList = tagStringList.stream().map(Tag::new).collect(Collectors.toList()); + } catch (IllegalArgumentException e) { + throw new ParseException(e.getMessage()); + } - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); - } + FindPredicate findpredicate = new FindPredicate(nameKeywords, tagList); + return new FindCommand(findpredicate); + } } diff --git a/src/main/java/seedu/address/logic/parser/FindOrCommandParser.java b/src/main/java/seedu/address/logic/parser/FindOrCommandParser.java new file mode 100644 index 00000000000..8f53d0d1d1f --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/FindOrCommandParser.java @@ -0,0 +1,54 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.List; +import java.util.stream.Collectors; + +import seedu.address.logic.commands.FindCommand; +import seedu.address.logic.commands.FindOrCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.FindOrPredicate; +import seedu.address.model.person.Name; +import seedu.address.model.tag.Tag; + +/** + * Parses input arguments and creates a new FindCommand object + */ +public class FindOrCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the FindOrCommand + * and returns a FindOrCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public FindOrCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); + + if (trimmedArgs.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TAG); + List nameStringList = argMultimap.getAllValues(PREFIX_NAME); + List tagStringList = argMultimap.getAllValues(PREFIX_TAG); + + List nameKeywords; + List tagList; + try { + nameKeywords = nameStringList.stream().map(Name::new).collect(Collectors.toList()); + tagList = tagStringList.stream().map(Tag::new).collect(Collectors.toList()); + } catch (IllegalArgumentException e) { + throw new ParseException(e.getMessage()); + } + + FindOrPredicate findOrPredicate = new FindOrPredicate(nameKeywords, tagList); + return new FindOrCommand(findOrPredicate); + } + +} + diff --git a/src/main/java/seedu/address/model/person/FindOrPredicate.java b/src/main/java/seedu/address/model/person/FindOrPredicate.java new file mode 100644 index 00000000000..22fbc75216a --- /dev/null +++ b/src/main/java/seedu/address/model/person/FindOrPredicate.java @@ -0,0 +1,52 @@ +package seedu.address.model.person; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.tag.Tag; + +/** + * Tests that a {@code Person}'s {@code Name} OR {@code Tag} matches ANY of the keywords given. + */ +public class FindOrPredicate implements Predicate { + + private final List nameList; + private final List tagList; + + /** + * Creates a FindOrPredicate + * + * @param nameList refers to the list of Names to be searched for + * @param tagList refers to the list of Tags to be searched for + */ + public FindOrPredicate(List nameList, List tagList) { + this.nameList = nameList; + this.tagList = tagList; + } + + @Override + public boolean test(Person person) { + Tag[] arrayTags = new Tag[person.getTags().toArray().length]; + if (!nameList.isEmpty()) { + return nameList.stream() + .anyMatch(name -> StringUtil.containsWordIgnoreCase(person.getName().fullName, name.fullName)) + || tagList.stream() + .anyMatch(tag -> Arrays.stream(person.getTags().toArray(arrayTags)) + .anyMatch(personTag -> personTag.compareTag(tag, false))); + } else { + return tagList.stream() + .anyMatch(tag -> Arrays.stream(person.getTags().toArray(arrayTags)) + .anyMatch(personTag -> personTag.compareTag(tag, false))); + } + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof FindOrPredicate) // instanceof handles nulls + && (nameList.equals(((FindOrPredicate) other).nameList) + && tagList.equals(((FindOrPredicate) other).tagList)); // state check + } +} diff --git a/src/main/java/seedu/address/model/person/FindPredicate.java b/src/main/java/seedu/address/model/person/FindPredicate.java new file mode 100644 index 00000000000..c188c3f2d3c --- /dev/null +++ b/src/main/java/seedu/address/model/person/FindPredicate.java @@ -0,0 +1,47 @@ +package seedu.address.model.person; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.tag.Tag; + + +/** + * Tests that a {@code Person}'s {@code Name} AND {@code Tag} matches ALL of the keywords given. + */ +public class FindPredicate implements Predicate { + + private final List nameList; + private final List tagList; + + /** + * Creates a FindPredicate + * + * @param nameList refers to the list of Names to be searched for + * @param tagList refers to the list of Tags to be searched for + */ + public FindPredicate(List nameList, List tagList) { + this.nameList = nameList; + this.tagList = tagList; + } + + @Override + public boolean test(Person person) { + Tag[] arrayTags = new Tag[person.getTags().toArray().length]; + return nameList.stream() + .allMatch(name -> StringUtil.containsWordIgnoreCase(person.getName().fullName, name.fullName)) + && tagList.stream() + .allMatch(tag -> Arrays.stream(person.getTags().toArray(arrayTags)) + .anyMatch(personTag-> personTag.compareTag(tag, false))); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof FindPredicate) // instanceof handles nulls + && (nameList.equals(((FindPredicate) other).nameList) + && tagList.equals(((FindPredicate) other).tagList)); // state check + } +} diff --git a/src/main/java/seedu/address/ui/BirthdayReminderCard.java b/src/main/java/seedu/address/ui/BirthdayReminderCard.java index db90beb6b9d..b30f5124dec 100644 --- a/src/main/java/seedu/address/ui/BirthdayReminderCard.java +++ b/src/main/java/seedu/address/ui/BirthdayReminderCard.java @@ -41,7 +41,7 @@ public BirthdayReminderCard(Person person) { phone.setText(person.getPhoneNumber()); Optional possibleBirthday = person.getBirthday(); assert possibleBirthday.isPresent(); - birthday.setText(possibleBirthday.map(Birthday::display).get()); + birthday.setText(possibleBirthday.map(Birthday::display).orElse("")); } @Override diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java index 9b15db28bbb..891b3aebadc 100644 --- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java @@ -5,20 +5,30 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.BENSON; import static seedu.address.testutil.TypicalPersons.CARL; +import static seedu.address.testutil.TypicalPersons.DANIEL; import static seedu.address.testutil.TypicalPersons.ELLE; -import static seedu.address.testutil.TypicalPersons.FIONA; +import static seedu.address.testutil.TypicalPersons.GEORGE; +import static seedu.address.testutil.TypicalPersons.HANNAH; +import static seedu.address.testutil.TypicalPersons.HANNAH_NO_BIRTHDAY; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; import java.util.Arrays; import java.util.Collections; +import java.util.List; 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.FindPredicate; +import seedu.address.model.person.Name; import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.tag.Tag; + /** * Contains integration tests (interaction with the Model) for {@code FindCommand}. @@ -29,10 +39,12 @@ public class FindCommandTest { @Test public void equals() { - NameContainsKeywordsPredicate firstPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("first")); - NameContainsKeywordsPredicate secondPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("second")); + List firstNameList = List.of(new Name(CARL.getFullName())); + List firstTagList = List.of(new Tag("football"), new Tag("friends")); + List secondNameList = List.of(new Name(ELLE.getFullName())); + List secondTagList = List.of(new Tag("colleagues")); + FindPredicate firstPredicate = new FindPredicate(firstNameList, firstTagList); + FindPredicate secondPredicate = new FindPredicate(secondNameList, secondTagList); FindCommand findFirstCommand = new FindCommand(firstPredicate); FindCommand findSecondCommand = new FindCommand(secondPredicate); @@ -55,23 +67,123 @@ public void equals() { } @Test - public void execute_zeroKeywords_noPersonFound() { + public void execute_nonExistentName_noPersonFound() { String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); - NameContainsKeywordsPredicate predicate = preparePredicate(" "); - FindCommand command = new FindCommand(predicate); - expectedModel.updateFilteredPersonList(predicate); + List firstNameList = List.of(new Name("zeke")); + List firstTagList = List.of(); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); assertEquals(Collections.emptyList(), model.getFilteredPersonList()); } @Test - public void execute_multipleKeywords_multiplePersonsFound() { + public void execute_oneExistentName_onePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(new Name("benson")); + List firstTagList = List.of(); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(BENSON), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentName_twoPersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2); + List firstNameList = List.of(new Name("hannah")); + List firstTagList = List.of(); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(HANNAH, HANNAH_NO_BIRTHDAY), model.getFilteredPersonList()); + } + + @Test + public void execute_twoExistentName_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + List firstNameList = List.of(new Name("alice"), new Name("benson")); + List firstTagList = List.of(); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getFilteredPersonList()); + } + + @Test + public void execute_nonExistentTag_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("Chef")); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentTag_onePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("football")); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(GEORGE), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentTag_multiplePersonsFound() { String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); - NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz"); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("friends")); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(ALICE, BENSON, DANIEL), model.getFilteredPersonList()); + } + + @Test + public void execute_multipleExistentTag_multiplePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("friends"), new Tag("owesMoney")); + FindPredicate findPredicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(BENSON, DANIEL), model.getFilteredPersonList()); + } + + @Test + public void execute_nameAndTag_onePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(new Name("benson")); + List firstTagList = List.of(new Tag("friends")); + FindPredicate predicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(BENSON), model.getFilteredPersonList()); + } + + @Test + public void execute_nameAndTagCaseInsensitive_onePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(new Name("bEnSon")); + List firstTagList = List.of(new Tag("fRiENds")); + FindPredicate predicate = new FindPredicate(firstNameList, firstTagList); FindCommand command = new FindCommand(predicate); expectedModel.updateFilteredPersonList(predicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); - assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList()); + assertEquals(Arrays.asList(BENSON), model.getFilteredPersonList()); } /** diff --git a/src/test/java/seedu/address/logic/commands/FindOrCommandTest.java b/src/test/java/seedu/address/logic/commands/FindOrCommandTest.java new file mode 100644 index 00000000000..33fb7d2f180 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/FindOrCommandTest.java @@ -0,0 +1,197 @@ +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.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.BENSON; +import static seedu.address.testutil.TypicalPersons.CARL; +import static seedu.address.testutil.TypicalPersons.DANIEL; +import static seedu.address.testutil.TypicalPersons.ELLE; +import static seedu.address.testutil.TypicalPersons.GEORGE; +import static seedu.address.testutil.TypicalPersons.HANNAH; +import static seedu.address.testutil.TypicalPersons.HANNAH_NO_BIRTHDAY; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +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.FindOrPredicate; +import seedu.address.model.person.FindPredicate; +import seedu.address.model.person.Name; +import seedu.address.model.tag.Tag; + + +public class FindOrCommandTest { + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void equals() { + List firstNameList = List.of(new Name(CARL.getFullName())); + List firstTagList = List.of(new Tag("football"), new Tag("friends")); + List secondNameList = List.of(new Name(ELLE.getFullName())); + List secondTagList = List.of(new Tag("colleagues")); + FindOrPredicate firstPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrPredicate secondPredicate = new FindOrPredicate(secondNameList, secondTagList); + + FindOrCommand findFirstCommand = new FindOrCommand(firstPredicate); + FindOrCommand findSecondCommand = new FindOrCommand(secondPredicate); + + // same object -> returns true + assertTrue(findFirstCommand.equals(findFirstCommand)); + + // same values -> returns true + FindOrCommand findFirstCommandCopy = new FindOrCommand(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_nonExistentName_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + List firstNameList = List.of(new Name("zeke")); + List firstTagList = List.of(); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentName_onePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(new Name("benson")); + List firstTagList = List.of(); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(BENSON), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentName_twoPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2); + List firstNameList = List.of(new Name("hannah")); + List firstTagList = List.of(); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(HANNAH, HANNAH_NO_BIRTHDAY), model.getFilteredPersonList()); + } + + @Test + public void execute_twoExistentName_twoPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2); + List firstNameList = List.of(new Name("alice"), new Name("benson")); + List firstTagList = List.of(); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(ALICE, BENSON), model.getFilteredPersonList()); + } + + @Test + public void execute_nonExistentTag_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("Chef")); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Collections.emptyList(), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentTag_onePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("football")); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(GEORGE), model.getFilteredPersonList()); + } + + @Test + public void execute_oneExistentTag_multiplePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("friends")); + FindOrPredicate findOrPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findOrPredicate); + expectedModel.updateFilteredPersonList(findOrPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(ALICE, BENSON, DANIEL), model.getFilteredPersonList()); + } + + @Test + public void execute_multipleExistentTag_multiplePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); + List firstNameList = List.of(); + List firstTagList = List.of(new Tag("friends"), new Tag("owesMoney")); + FindOrPredicate findPredicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(findPredicate); + expectedModel.updateFilteredPersonList(findPredicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(ALICE, BENSON, DANIEL), model.getFilteredPersonList()); + } + + @Test + public void execute_nameAndTag_onePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + List firstNameList = List.of(new Name("best")); + List firstTagList = List.of(new Tag("football")); + FindPredicate predicate = new FindPredicate(firstNameList, firstTagList); + FindCommand command = new FindCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(GEORGE), model.getFilteredPersonList()); + } + + @Test + public void execute_namesAndTags_multiplePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 4); + List firstNameList = List.of(new Name("carl"), new Name("benson")); + List firstTagList = List.of(new Tag("friends")); + FindOrPredicate predicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(ALICE, BENSON, CARL, DANIEL), model.getFilteredPersonList()); + } + + @Test + public void execute_namesAndTagsCaseInsensitive_multiplePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 4); + List firstNameList = List.of(new Name("cArL"), new Name("bEnsOn")); + List firstTagList = List.of(new Tag("friENDs")); + FindOrPredicate predicate = new FindOrPredicate(firstNameList, firstTagList); + FindOrCommand command = new FindOrCommand(predicate); + expectedModel.updateFilteredPersonList(predicate); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + assertEquals(Arrays.asList(ALICE, BENSON, CARL, DANIEL), model.getFilteredPersonList()); + } +} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 45b8749c00b..f82646f87a2 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -8,6 +8,8 @@ import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; import static seedu.address.logic.commands.DeleteMultipleCommand.INDEX_SPLITTER; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalIndexes.INDEX_EIGHTH_PERSON; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; @@ -25,6 +27,7 @@ import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.FindCommand; +import seedu.address.logic.commands.FindOrCommand; import seedu.address.logic.commands.FindTagCaseInsensitiveCommand; import seedu.address.logic.commands.FindTagCaseSensitiveCommand; import seedu.address.logic.commands.HelpCommand; @@ -32,7 +35,9 @@ import seedu.address.logic.commands.TagCommand; import seedu.address.logic.commands.UntagCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.FindOrPredicate; +import seedu.address.model.person.FindPredicate; +import seedu.address.model.person.Name; import seedu.address.model.person.Person; import seedu.address.model.person.PersonTagsContainsCaseInsensitiveTagsPredicate; import seedu.address.model.person.PersonTagsContainsCaseSensitiveTagsPredicate; @@ -107,11 +112,87 @@ public void parseCommand_exit() throws Exception { } @Test - public void parseCommand_find() throws Exception { - List keywords = Arrays.asList("foo", "bar", "baz"); + public void parseCommand_findOnlyNames() throws Exception { + List nameStringList = List.of("Alan", "Bob", "Chris"); + List tagStringList = List.of(); + List nameList = List.of(new Name("Alan"), new Name("Bob"), new Name("Chris")); + List tagList = List.of(); + FindPredicate findPredicate = new FindPredicate(nameList, tagList); + FindCommand command = (FindCommand) parser.parseCommand( + FindCommand.COMMAND_WORD + " " + nameStringList.stream().map(x -> PREFIX_NAME + x) + .collect(Collectors.joining(" ")) + + " " + tagStringList.stream().map(x -> PREFIX_TAG + x).collect(Collectors.joining(" "))); + assertEquals(new FindCommand(findPredicate), command); + } + + @Test + public void parseCommand_findOnlyTags() throws Exception { + List nameStringList = List.of(); + List tagStringList = List.of("football", "friends"); + List nameList = List.of(); + List tagList = List.of(new Tag("football"), new Tag("friends")); + FindPredicate findPredicate = new FindPredicate(nameList, tagList); + FindCommand command = (FindCommand) parser.parseCommand( + FindCommand.COMMAND_WORD + " " + nameStringList.stream().map(x -> PREFIX_NAME + x) + .collect(Collectors.joining(" ")) + + " " + tagStringList.stream().map(x -> PREFIX_TAG + x).collect(Collectors.joining(" "))); + assertEquals(new FindCommand(findPredicate), command); + } + + @Test + public void parseCommand_findNamesAndTags() throws Exception { + List nameStringList = List.of("Alan", "Bob", "Chris"); + List tagStringList = List.of("football", "friends"); + List nameList = List.of(new Name("Alan"), new Name("Bob"), new Name("Chris")); + List tagList = List.of(new Tag("football"), new Tag("friends")); + FindPredicate findPredicate = new FindPredicate(nameList, tagList); FindCommand command = (FindCommand) parser.parseCommand( - FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); - assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command); + FindCommand.COMMAND_WORD + " " + nameStringList.stream().map(x -> PREFIX_NAME + x) + .collect(Collectors.joining(" ")) + + " " + tagStringList.stream().map(x -> PREFIX_TAG + x).collect(Collectors.joining(" "))); + assertEquals(new FindCommand(findPredicate), command); + } + + @Test + public void parseCommand_findOrOnlyNames() throws Exception { + List nameStringList = List.of("Alan", "Bob", "Chris"); + List tagStringList = List.of(); + List nameList = List.of(new Name("Alan"), new Name("Bob"), new Name("Chris")); + List tagList = List.of(); + FindOrPredicate findOrPredicate = new FindOrPredicate(nameList, tagList); + FindOrCommand command = (FindOrCommand) parser.parseCommand( + FindOrCommand.COMMAND_WORD + " " + nameStringList.stream().map(x -> PREFIX_NAME + x) + .collect(Collectors.joining(" ")) + + " " + tagStringList.stream().map(x -> PREFIX_TAG + x).collect(Collectors.joining(" "))); + assertEquals(new FindOrCommand(findOrPredicate), command); + } + + @Test + public void parseCommand_findOrOnlyTags() throws Exception { + List nameStringList = List.of(); + List tagStringList = List.of("football", "friends"); + List nameList = List.of(); + List tagList = List.of(new Tag("football"), new Tag("friends")); + FindOrPredicate findOrPredicate = new FindOrPredicate(nameList, tagList); + FindOrCommand command = (FindOrCommand) parser.parseCommand( + FindOrCommand.COMMAND_WORD + " " + nameStringList.stream().map(x -> PREFIX_NAME + x) + .collect(Collectors.joining(" ")) + + " " + tagStringList.stream().map(x -> PREFIX_TAG + x).collect(Collectors.joining(" "))); + assertEquals(new FindOrCommand(findOrPredicate), command); + } + + @Test + public void parseCommand_findOrNamesAndTags() throws Exception { + List nameStringList = List.of("Alan", "Bob", "Chris"); + List tagStringList = List.of("football", "friends"); + List nameList = List.of(new Name("Alan"), new Name("Bob"), new Name("Chris")); + List tagList = List.of(new Tag("football"), new Tag("friends")); + FindOrPredicate findOrPredicate = new FindOrPredicate(nameList, tagList); + FindOrCommand command = (FindOrCommand) parser.parseCommand( + FindOrCommand.COMMAND_WORD + " " + nameStringList.stream().map(x -> PREFIX_NAME + x) + .collect(Collectors.joining(" ")) + + " " + tagStringList.stream().map(x -> PREFIX_TAG + x).collect(Collectors.joining(" "))); + assertEquals(new FindOrCommand(findOrPredicate), 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 70f4f0e79c4..f97eebfdde9 100644 --- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java @@ -4,12 +4,14 @@ import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; -import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.Test; import seedu.address.logic.commands.FindCommand; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.FindPredicate; +import seedu.address.model.person.Name; +import seedu.address.model.tag.Tag; public class FindCommandParserTest { @@ -21,14 +23,75 @@ public void parse_emptyArg_throwsParseException() { } @Test - public void parse_validArgs_returnsFindCommand() { - // no leading and trailing whitespaces + public void parse_oneName_returnsFindCommand() { + List nameList = List.of(new Name("Alice")); + List tagList = List.of(); FindCommand expectedFindCommand = - new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); - assertParseSuccess(parser, "Alice Bob", expectedFindCommand); + new FindCommand(new FindPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice", expectedFindCommand); // multiple whitespaces between keywords - assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand); + assertParseSuccess(parser, " \n n/Alice \n \t \t", expectedFindCommand); + } + + @Test + public void parse_multipleNames_returnsFindCommand() { + List nameList = List.of(new Name("Alice"), new Name("Bob")); + List tagList = List.of(); + FindCommand expectedFindCommand = + new FindCommand(new FindPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice n/Bob", expectedFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t n/Bob \t", expectedFindCommand); + } + + @Test + public void parse_oneTag_returnsFindCommand() { + List nameList = List.of(); + List tagList = List.of(new Tag("friends")); + FindCommand expectedFindCommand = + new FindCommand(new FindPredicate(nameList, tagList)); + assertParseSuccess(parser, " t/friends", expectedFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n \n \t \t t/friends", expectedFindCommand); + } + + @Test + public void parse_multipleTags_returnsFindCommand() { + List nameList = List.of(); + List tagList = List.of(new Tag("friends"), new Tag("colleagues")); + FindCommand expectedFindCommand = + new FindCommand(new FindPredicate(nameList, tagList)); + assertParseSuccess(parser, " t/friends t/colleagues", expectedFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n \n \t t/friends \t t/colleagues", expectedFindCommand); + } + + @Test + public void parse_oneNamesAndTag_returnsFindCommand() { + List nameList = List.of(new Name("Alice")); + List tagList = List.of(new Tag("friends")); + FindCommand expectedFindCommand = + new FindCommand(new FindPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice t/friends", expectedFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t \t t/friends", expectedFindCommand); + } + + @Test + public void parse_multipleNamesAndTags_returnsFindCommand() { + List nameList = List.of(new Name("Alice"), new Name("Bob")); + List tagList = List.of(new Tag("friends"), new Tag("colleagues")); + FindCommand expectedFindCommand = + new FindCommand(new FindPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice n/Bob t/friends t/colleagues", expectedFindCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t n/Bob \t t/friends t/colleagues", expectedFindCommand); } } diff --git a/src/test/java/seedu/address/logic/parser/FindOrCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindOrCommandParserTest.java new file mode 100644 index 00000000000..34a8e67188b --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/FindOrCommandParserTest.java @@ -0,0 +1,99 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.FindCommand; +import seedu.address.logic.commands.FindOrCommand; +import seedu.address.model.person.FindOrPredicate; +import seedu.address.model.person.Name; +import seedu.address.model.tag.Tag; + + +public class FindOrCommandParserTest { + + private FindOrCommandParser parser = new FindOrCommandParser(); + + @Test + public void parse_emptyArg_throwsParseException() { + assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_oneName_returnsFindOrCommand() { + List nameList = List.of(new Name("Alice")); + List tagList = List.of(); + FindOrCommand expectedFindOrCommand = + new FindOrCommand(new FindOrPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice", expectedFindOrCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t \t", expectedFindOrCommand); + } + + @Test + public void parse_multipleNames_returnsFindOrCommand() { + List nameList = List.of(new Name("Alice"), new Name("Bob")); + List tagList = List.of(); + FindOrCommand expectedFindOrCommand = + new FindOrCommand(new FindOrPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice n/Bob", expectedFindOrCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t n/Bob \t", expectedFindOrCommand); + } + + @Test + public void parse_oneTag_returnsFindOrCommand() { + List nameList = List.of(); + List tagList = List.of(new Tag("friends")); + FindOrCommand expectedFindOrCommand = + new FindOrCommand(new FindOrPredicate(nameList, tagList)); + assertParseSuccess(parser, " t/friends", expectedFindOrCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n \n \t \t t/friends", expectedFindOrCommand); + } + + @Test + public void parse_multipleTags_returnsFindOrCommand() { + List nameList = List.of(); + List tagList = List.of(new Tag("friends"), new Tag("colleagues")); + FindOrCommand expectedFindOrCommand = + new FindOrCommand(new FindOrPredicate(nameList, tagList)); + assertParseSuccess(parser, " t/friends t/colleagues", expectedFindOrCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n t/friends \n \t \t t/colleagues", expectedFindOrCommand); + } + + @Test + public void parse_oneNameAndTag_returnsFindOrCommand() { + List nameList = List.of(new Name("Alice")); + List tagList = List.of(new Tag("friends")); + FindOrCommand expectedFindOrCommand = + new FindOrCommand(new FindOrPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice t/friends", expectedFindOrCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t \t t/friends", expectedFindOrCommand); + } + + @Test + public void parse_multipleNamesAndTags_returnsFindOrCommand() { + List nameList = List.of(new Name("Alice"), new Name("Bob")); + List tagList = List.of(new Tag("friends"), new Tag("colleagues")); + FindOrCommand expectedFindOrCommand = + new FindOrCommand(new FindOrPredicate(nameList, tagList)); + assertParseSuccess(parser, " n/Alice n/Bob t/friends t/colleagues", expectedFindOrCommand); + + // multiple whitespaces between keywords + assertParseSuccess(parser, " \n n/Alice \n \t n/Bob \t t/friends t/colleagues", expectedFindOrCommand); + } + +}