Skip to content

Commit

Permalink
Merge pull request #54 from cliveong/search-by-involvement
Browse files Browse the repository at this point in the history
Add filter by involvement
  • Loading branch information
junghon3709 authored Oct 12, 2021
2 parents 76455b1 + b45b090 commit 24603dc
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 0 deletions.
43 changes: 43 additions & 0 deletions src/main/java/seedu/address/logic/commands/FilterCommand.java
Original file line number Diff line number Diff line change
@@ -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.InvolvementContainsKeywordsPredicate;

/**
* Filters and lists all persons in address book whose involvement contains any of the argument keywords.
* Keyword matching is case insensitive.
*/
public class FilterCommand extends Command {

public static final String COMMAND_WORD = "filter";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all persons whose involvement 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 + " donut buddies";

private final InvolvementContainsKeywordsPredicate predicate;

public FilterCommand(InvolvementContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
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 FilterCommand // instanceof handles nulls
&& predicate.equals(((FilterCommand) other).predicate)); // state check
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import seedu.address.logic.commands.CopyCommand;
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
Expand Down Expand Up @@ -74,6 +75,9 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();

case FilterCommand.COMMAND_WORD:
return new FilterCommandParser().parse(arguments);

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/seedu/address/logic/parser/FilterCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package seedu.address.logic.parser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import java.util.Arrays;

import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.InvolvementContainsKeywordsPredicate;



/**
* Parses input arguments and creates a new FindCommand object
*/
public class FilterCommandParser implements Parser<FilterCommand> {

/**
* Parses the given {@code String} of arguments in the context of the FindCommand
* and returns a FindCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public FilterCommand parse(String args) throws ParseException {
String trimmedArgs = args.trim();
if (trimmedArgs.isEmpty()) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}

String[] nameKeywords = trimmedArgs.split("\\s+");

return new FilterCommand(new InvolvementContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package seedu.address.model.person;

import java.util.List;
import java.util.function.Predicate;

import seedu.address.commons.util.StringUtil;

/**
* Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
*/
public class InvolvementContainsKeywordsPredicate implements Predicate<Person> {
private final List<String> keywords;

public InvolvementContainsKeywordsPredicate(List<String> keywords) {
this.keywords = keywords;
}

@Override
public boolean test(Person person) {
return keywords.stream()
.anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getInvolvement().involvement, keyword));
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof InvolvementContainsKeywordsPredicate // instanceof handles nulls
&& keywords.equals(((InvolvementContainsKeywordsPredicate) other).keywords)); // state check
}

}
87 changes: 87 additions & 0 deletions src/test/java/seedu/address/logic/commands/FilterCommandTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
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.TypicalStudents.ALICE;
import static seedu.address.testutil.TypicalStudents.BENSON;
import static seedu.address.testutil.TypicalStudents.CARL;
import static seedu.address.testutil.TypicalStudents.DANIEL;
import static seedu.address.testutil.TypicalStudents.ELLE;
import static seedu.address.testutil.TypicalStudents.FIONA;
import static seedu.address.testutil.TypicalStudents.GEORGE;
import static seedu.address.testutil.TypicalStudents.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.InvolvementContainsKeywordsPredicate;

/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
*/
public class FilterCommandTest {
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());

@Test
public void equals() {
InvolvementContainsKeywordsPredicate firstPredicate =
new InvolvementContainsKeywordsPredicate(Collections.singletonList("first"));
InvolvementContainsKeywordsPredicate secondPredicate =
new InvolvementContainsKeywordsPredicate(Collections.singletonList("second"));

FilterCommand findFirstCommand = new FilterCommand(firstPredicate);
FilterCommand findSecondCommand = new FilterCommand(secondPredicate);

// same object -> returns true
assertTrue(findFirstCommand.equals(findFirstCommand));

// same values -> returns true
FilterCommand findFirstCommandCopy = new FilterCommand(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_zeroKeywords_noPersonFound() {
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
InvolvementContainsKeywordsPredicate predicate = preparePredicate(" ");
FilterCommand command = new FilterCommand(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, 7);
InvolvementContainsKeywordsPredicate predicate = preparePredicate("Form class");
FilterCommand command = new FilterCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE), model.getFilteredPersonList());
}

/**
* Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
*/
private InvolvementContainsKeywordsPredicate preparePredicate(String userInput) {
return new InvolvementContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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.Arrays;

import org.junit.jupiter.api.Test;

import seedu.address.logic.commands.FilterCommand;
import seedu.address.model.person.InvolvementContainsKeywordsPredicate;


public class FilterCommandParserTest {

private FilterCommandParser parser = new FilterCommandParser();

@Test
public void parse_emptyArg_throwsParseException() {
assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}

@Test
public void parse_validArgs_returnsFilterCommand() {
// no leading and trailing whitespaces
FilterCommand expectedFilterCommand =
new FilterCommand(new InvolvementContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
assertParseSuccess(parser, "Alice Bob", expectedFilterCommand);

// multiple whitespaces between keywords
assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFilterCommand);
}

}

0 comments on commit 24603dc

Please sign in to comment.