Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Find command to search using Person's IC #46

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/main/java/seedu/address/logic/commands/FindCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
16 changes: 9 additions & 7 deletions src/main/java/seedu/address/logic/parser/FindCommandParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,9 +24,12 @@
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 = 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);

Check warning on line 32 in src/main/java/seedu/address/logic/parser/FindCommandParser.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/seedu/address/logic/parser/FindCommandParser.java#L30-L32

Added lines #L30 - L32 were not covered by tests
}
}

}
16 changes: 16 additions & 0 deletions src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Person> {
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;

Check warning on line 29 in src/main/java/seedu/address/model/person/IdentityCardNumberMatchesPredicate.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/seedu/address/model/person/IdentityCardNumberMatchesPredicate.java#L29

Added line #L29 was not covered by tests
}

IdentityCardNumberMatchesPredicate predicate = (IdentityCardNumberMatchesPredicate) other;
return targetIcNumber.equals(predicate.targetIcNumber);
}

@Override
public String toString() {
return new ToStringBuilder(this).toString();
}

}

43 changes: 17 additions & 26 deletions src/test/java/seedu/address/logic/commands/FindCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,33 @@
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;

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);
Expand All @@ -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());
Expand All @@ -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));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -72,10 +69,9 @@ public void parseCommand_exit() throws Exception {

@Test
public void parseCommand_find() throws Exception {
List<String> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -22,13 +22,31 @@ 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", IdentityCardNumber.MESSAGE_CONSTRAINTS);

// IC with incorrect format and additional arguments
assertParseFailure(parser, "S1234 extra", IdentityCardNumber.MESSAGE_CONSTRAINTS);

// IC with correct format but contains non-alphanumeric characters
assertParseFailure(parser, "S1234$%^", IdentityCardNumber.MESSAGE_CONSTRAINTS);
}

@Test
public void parse_nullArgs_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> parser.parse(null));
}

}
Loading