From 0813c1753e3f735d66fefa81ab4bd0698af2c3a6 Mon Sep 17 00:00:00 2001 From: jiahui0309 Date: Sat, 16 Mar 2024 14:37:00 +0800 Subject: [PATCH 1/2] Update Find command to search with Person's IC --- .../address/logic/commands/FindCommand.java | 18 ++++---- .../logic/parser/FindCommandParser.java | 16 ++++--- .../model/person/IdentityCardNumber.java | 2 +- .../IdentityCardNumberMatchesPredicate.java | 42 ++++++++++++++++++ .../logic/commands/FindCommandTest.java | 43 ++++++++----------- .../logic/parser/AddressBookParserTest.java | 14 +++--- .../logic/parser/FindCommandParserTest.java | 34 ++++++++++++--- 7 files changed, 110 insertions(+), 59 deletions(-) create mode 100644 src/main/java/seedu/address/model/person/IdentityCardNumberMatchesPredicate.java diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java index 72b9eddd3a7..c722dd85fb2 100644 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ b/src/main/java/seedu/address/logic/commands/FindCommand.java @@ -5,24 +5,24 @@ import seedu.address.commons.util.ToStringBuilder; import seedu.address.logic.Messages; import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.IdentityCardNumberMatchesPredicate; /** - * Finds and lists all persons in address book whose name contains any of the argument keywords. - * Keyword matching is case insensitive. + * Finds and lists all persons in address book whose IC matches the argument IC. + * 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 " - + "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"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose profile matches " + + "the specified IC (case-insensitive) and displays them.\n" + + "Parameters: IC\n" + + "Example: " + COMMAND_WORD + " t1234567A"; - private final NameContainsKeywordsPredicate predicate; + private final IdentityCardNumberMatchesPredicate predicate; - public FindCommand(NameContainsKeywordsPredicate predicate) { + public FindCommand(IdentityCardNumberMatchesPredicate predicate) { this.predicate = predicate; } diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java index 2867bde857b..eff90421123 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java @@ -2,11 +2,10 @@ import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import java.util.Arrays; - import seedu.address.logic.commands.FindCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.IdentityCardNumber; +import seedu.address.model.person.IdentityCardNumberMatchesPredicate; /** * Parses input arguments and creates a new FindCommand object @@ -25,9 +24,12 @@ public FindCommand parse(String args) throws ParseException { String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); } - String[] nameKeywords = trimmedArgs.split("\\s+"); - - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); + try { + IdentityCardNumber IC = new IdentityCardNumber(trimmedArgs); + return new FindCommand(new IdentityCardNumberMatchesPredicate(IC)); + } catch (IllegalArgumentException e) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE), e); + } } - } diff --git a/src/main/java/seedu/address/model/person/IdentityCardNumber.java b/src/main/java/seedu/address/model/person/IdentityCardNumber.java index 6c75beeebb7..e08b0429737 100644 --- a/src/main/java/seedu/address/model/person/IdentityCardNumber.java +++ b/src/main/java/seedu/address/model/person/IdentityCardNumber.java @@ -14,7 +14,7 @@ public class IdentityCardNumber { "IC number starts with one letter (S,T,F,G,M) followed by seven digits and one letter behind" + " It is case insensitive. An example is S1234567A."; - public static final String VALIDATION_REGEX = "[STFGM][0-9]{7}[A-Z]"; + public static final String VALIDATION_REGEX = "[STFGMstfgm][0-9]{7}[A-Z,a-z]"; public final String value; diff --git a/src/main/java/seedu/address/model/person/IdentityCardNumberMatchesPredicate.java b/src/main/java/seedu/address/model/person/IdentityCardNumberMatchesPredicate.java new file mode 100644 index 00000000000..5859e4f3179 --- /dev/null +++ b/src/main/java/seedu/address/model/person/IdentityCardNumberMatchesPredicate.java @@ -0,0 +1,42 @@ +package seedu.address.model.person; + +import java.util.function.Predicate; + +import seedu.address.commons.util.ToStringBuilder; + +/** + * Tests that a {@code Person}'s {@code IdentityCardNumber} matches the given IC number. + */ +public class IdentityCardNumberMatchesPredicate implements Predicate { + private final IdentityCardNumber targetIcNumber; + + public IdentityCardNumberMatchesPredicate(IdentityCardNumber targetIcNumber) { + this.targetIcNumber = targetIcNumber; + } + + @Override + public boolean test(Person person) { + return person.getIdentityCardNumber().equals(targetIcNumber); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof IdentityCardNumberMatchesPredicate)) { + return false; + } + + IdentityCardNumberMatchesPredicate predicate = (IdentityCardNumberMatchesPredicate) other; + return targetIcNumber.equals(predicate.targetIcNumber); + } + + @Override + public String toString() { + return new ToStringBuilder(this).toString(); + } + +} + diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java index b8b7dbba91a..ef99cda63ba 100644 --- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java @@ -5,12 +5,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.testutil.TypicalPersons.CARL; -import static seedu.address.testutil.TypicalPersons.ELLE; -import static seedu.address.testutil.TypicalPersons.FIONA; +import static seedu.address.testutil.TypicalPersons.ALICE; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; -import java.util.Arrays; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -18,21 +15,23 @@ 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.IdentityCardNumber; +import seedu.address.model.person.IdentityCardNumberMatchesPredicate; /** * Contains integration tests (interaction with the Model) for {@code FindCommand}. */ + public class FindCommandTest { private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); @Test public void equals() { - NameContainsKeywordsPredicate firstPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("first")); - NameContainsKeywordsPredicate secondPredicate = - new NameContainsKeywordsPredicate(Collections.singletonList("second")); + IdentityCardNumberMatchesPredicate firstPredicate = + new IdentityCardNumberMatchesPredicate(new IdentityCardNumber("S1234567A")); + IdentityCardNumberMatchesPredicate secondPredicate = + new IdentityCardNumberMatchesPredicate(new IdentityCardNumber("S9876543B")); FindCommand findFirstCommand = new FindCommand(firstPredicate); FindCommand findSecondCommand = new FindCommand(secondPredicate); @@ -55,28 +54,19 @@ public void equals() { } @Test - public void execute_zeroKeywords_noPersonFound() { - String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); - NameContainsKeywordsPredicate predicate = preparePredicate(" "); - FindCommand command = new FindCommand(predicate); - expectedModel.updateFilteredPersonList(predicate); - assertCommandSuccess(command, model, expectedMessage, expectedModel); - assertEquals(Collections.emptyList(), model.getFilteredPersonList()); - } - - @Test - public void execute_multipleKeywords_multiplePersonsFound() { - String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3); - NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz"); + public void execute_validIC_singlePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + IdentityCardNumberMatchesPredicate predicate = preparePredicate("S1234567A"); FindCommand command = new FindCommand(predicate); expectedModel.updateFilteredPersonList(predicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); - assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList()); + assertEquals(Collections.singletonList(ALICE), model.getFilteredPersonList()); } @Test public void toStringMethod() { - NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword")); + IdentityCardNumberMatchesPredicate predicate = new IdentityCardNumberMatchesPredicate( + new IdentityCardNumber("S1234567A")); FindCommand findCommand = new FindCommand(predicate); String expected = FindCommand.class.getCanonicalName() + "{predicate=" + predicate + "}"; assertEquals(expected, findCommand.toString()); @@ -85,7 +75,8 @@ public void toStringMethod() { /** * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}. */ - private NameContainsKeywordsPredicate preparePredicate(String userInput) { - return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))); + private IdentityCardNumberMatchesPredicate preparePredicate(String userInput) { + return new IdentityCardNumberMatchesPredicate(new IdentityCardNumber(userInput)); } } + diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 42e1f2c4de2..020a119dcd1 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -7,10 +7,6 @@ import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -24,7 +20,8 @@ import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.IdentityCardNumber; +import seedu.address.model.person.IdentityCardNumberMatchesPredicate; import seedu.address.model.person.Person; import seedu.address.testutil.EditPersonDescriptorBuilder; import seedu.address.testutil.PersonBuilder; @@ -72,10 +69,9 @@ public void parseCommand_exit() throws Exception { @Test public void parseCommand_find() throws Exception { - List keywords = Arrays.asList("foo", "bar", "baz"); - FindCommand command = (FindCommand) parser.parseCommand( - FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" "))); - assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command); + String args = "s1234567a"; + FindCommand command = (FindCommand) parser.parseCommand(FindCommand.COMMAND_WORD + " " + args); + assertEquals(new FindCommand(new IdentityCardNumberMatchesPredicate(new IdentityCardNumber(args))), command); } @Test diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java index d92e64d12f9..89235706fe8 100644 --- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java @@ -3,13 +3,13 @@ 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.Arrays; +import static seedu.address.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; import seedu.address.logic.commands.FindCommand; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.person.IdentityCardNumber; +import seedu.address.model.person.IdentityCardNumberMatchesPredicate; public class FindCommandParserTest { @@ -22,13 +22,33 @@ public void parse_emptyArg_throwsParseException() { @Test public void parse_validArgs_returnsFindCommand() { - // no leading and trailing whitespaces FindCommand expectedFindCommand = - new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"))); - assertParseSuccess(parser, "Alice Bob", expectedFindCommand); + new FindCommand(new IdentityCardNumberMatchesPredicate(new IdentityCardNumber("S1234567A"))); + assertParseSuccess(parser, "S1234567A", expectedFindCommand); // multiple whitespaces between keywords - assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand); + assertParseSuccess(parser, " \n" + + " S1234567A \n" + + " \t \t", expectedFindCommand); + } + + @Test + public void parse_invalidArgs_throwsParseException() { + // IC with incorrect format + assertParseFailure(parser, "S1234", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + + // IC with incorrect format and additional arguments + assertParseFailure(parser, "S1234 extra", String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + + // IC with correct format but contains non-alphanumeric characters + assertParseFailure(parser, "S1234$%^", String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_nullArgs_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> parser.parse(null)); } } From 53dac0a58990075939d2d93e04d7670b08f9eac6 Mon Sep 17 00:00:00 2001 From: jiahui0309 Date: Sat, 16 Mar 2024 15:18:03 +0800 Subject: [PATCH 2/2] Update PaserUtil to add parseIC --- .../address/logic/parser/FindCommandParser.java | 4 ++-- .../seedu/address/logic/parser/ParserUtil.java | 16 ++++++++++++++++ .../logic/parser/FindCommandParserTest.java | 8 +++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java index eff90421123..cd1116c9e87 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java @@ -25,8 +25,8 @@ public FindCommand parse(String args) throws ParseException { } try { - IdentityCardNumber IC = new IdentityCardNumber(trimmedArgs); - return new FindCommand(new IdentityCardNumberMatchesPredicate(IC)); + IdentityCardNumber ic = ParserUtil.parseIC(trimmedArgs); + return new FindCommand(new IdentityCardNumberMatchesPredicate(ic)); } catch (IllegalArgumentException e) { throw new ParseException( String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE), e); diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index b117acb9c55..85d360634cc 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -11,6 +11,7 @@ import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.person.Address; import seedu.address.model.person.Email; +import seedu.address.model.person.IdentityCardNumber; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; @@ -65,6 +66,21 @@ public static Phone parsePhone(String phone) throws ParseException { return new Phone(trimmedPhone); } + /** + * Parses a {@code String identityCardNumber} into a {@code IdentityCardNumber}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code identityCardNumber} is invalid. + */ + public static IdentityCardNumber parseIC(String identityCardNumber) throws ParseException { + requireNonNull(identityCardNumber); + String trimmedIdentityCardNumber = identityCardNumber.trim(); + if (!IdentityCardNumber.isValidIdentityCardNumber(trimmedIdentityCardNumber)) { + throw new ParseException(IdentityCardNumber.MESSAGE_CONSTRAINTS); + } + return new IdentityCardNumber(trimmedIdentityCardNumber); + } + /** * Parses a {@code String address} into an {@code Address}. * Leading and trailing whitespaces will be trimmed. diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java index 89235706fe8..89d38b87869 100644 --- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java @@ -35,15 +35,13 @@ public void parse_validArgs_returnsFindCommand() { @Test public void parse_invalidArgs_throwsParseException() { // IC with incorrect format - assertParseFailure(parser, "S1234", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + assertParseFailure(parser, "S1234", IdentityCardNumber.MESSAGE_CONSTRAINTS); // IC with incorrect format and additional arguments - assertParseFailure(parser, "S1234 extra", String.format(MESSAGE_INVALID_COMMAND_FORMAT, - FindCommand.MESSAGE_USAGE)); + assertParseFailure(parser, "S1234 extra", IdentityCardNumber.MESSAGE_CONSTRAINTS); // IC with correct format but contains non-alphanumeric characters - assertParseFailure(parser, "S1234$%^", String.format(MESSAGE_INVALID_COMMAND_FORMAT, - FindCommand.MESSAGE_USAGE)); + assertParseFailure(parser, "S1234$%^", IdentityCardNumber.MESSAGE_CONSTRAINTS); } @Test