Skip to content

Commit 20270ad

Browse files
committed
I want to merge remote-tracking branch 'upstream/master' into AddMeetingParser
2 parents 6d1c332 + 202fb0a commit 20270ad

8 files changed

Lines changed: 279 additions & 8 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package seedu.address.logic.commands.persons;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import seedu.address.commons.core.Messages;
6+
import seedu.address.logic.commands.Command;
7+
import seedu.address.logic.commands.CommandResult;
8+
import seedu.address.model.Model;
9+
import seedu.address.model.group.GroupContainsKeywordsPredicate;
10+
11+
/**
12+
* Finds and lists all persons in address book whose group contains any of the argument keywords.
13+
* Keyword matching is case insensitive.
14+
*/
15+
public class FindGroupCommand extends Command {
16+
17+
public static final String COMMAND_WORD = "findg";
18+
19+
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose groups contain any of "
20+
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
21+
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
22+
+ "Example: " + COMMAND_WORD + " badminton tennis";
23+
24+
private final GroupContainsKeywordsPredicate predicate;
25+
26+
public FindGroupCommand(GroupContainsKeywordsPredicate predicate) {
27+
this.predicate = predicate;
28+
}
29+
30+
@Override
31+
public CommandResult execute(Model model) {
32+
requireNonNull(model);
33+
model.updateFilteredPersonList(predicate);
34+
return new CommandResult(
35+
String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
36+
}
37+
38+
@Override
39+
public boolean equals(Object other) {
40+
return other == this // short circuit if same object
41+
|| (other instanceof FindGroupCommand // instanceof handles nulls
42+
&& predicate.equals(((FindGroupCommand) other).predicate)); // state check
43+
}
44+
}
45+

src/main/java/seedu/address/logic/parser/MeetBuddyParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import seedu.address.logic.parser.persons.AddPersonCommandParser;
1717
import seedu.address.logic.parser.persons.DeletePersonCommandParser;
1818
import seedu.address.logic.parser.persons.EditPersonCommandParser;
19+
import seedu.address.logic.parser.persons.FindGroupCommandParser;
1920
import seedu.address.logic.parser.persons.FindPersonCommandParser;
2021
import seedu.address.logic.parser.exceptions.ParseException;
2122

@@ -61,6 +62,9 @@ public Command parseCommand(String userInput) throws ParseException {
6162
case FindPersonCommand.COMMAND_WORD:
6263
return new FindPersonCommandParser().parse(arguments);
6364

65+
case FindGroupCommand.COMMAND_WORD:
66+
return new FindGroupCommandParser().parse(arguments);
67+
6468
case ListPersonCommand.COMMAND_WORD:
6569
return new ListPersonCommand();
6670

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package seedu.address.logic.parser.persons;
2+
3+
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
4+
5+
import java.util.Arrays;
6+
7+
import seedu.address.logic.commands.persons.FindGroupCommand;
8+
import seedu.address.logic.parser.Parser;
9+
import seedu.address.logic.parser.exceptions.ParseException;
10+
import seedu.address.model.group.GroupContainsKeywordsPredicate;
11+
12+
/**
13+
* Parses input arguments and creates a new FindPersonCommand object
14+
*/
15+
public class FindGroupCommandParser implements Parser<FindGroupCommand> {
16+
17+
/**
18+
* Parses the given {@code String} of arguments in the context of the FindPersonCommand
19+
* and returns a FindPersonCommand object for execution.
20+
* @throws ParseException if the user input does not conform the expected format
21+
*/
22+
public FindGroupCommand parse(String args) throws ParseException {
23+
String trimmedArgs = args.trim();
24+
if (trimmedArgs.isEmpty()) {
25+
throw new ParseException(
26+
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindGroupCommand.MESSAGE_USAGE));
27+
}
28+
29+
String[] nameKeywords = trimmedArgs.split("\\s+");
30+
31+
return new FindGroupCommand(new GroupContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
32+
}
33+
34+
}

src/main/java/seedu/address/model/group/Group.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ public int hashCode() {
4444
return groupName.hashCode();
4545
}
4646

47+
public String getGroupName() {
48+
return this.groupName;
49+
}
50+
4751
/**
4852
* Format state as text for viewing.
4953
*/
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package seedu.address.model.group;
2+
3+
import java.util.List;
4+
import java.util.Set;
5+
import java.util.function.Predicate;
6+
7+
import seedu.address.commons.util.StringUtil;
8+
import seedu.address.model.person.Person;
9+
10+
/**
11+
* Tests that a {@code Person}'s {@code Group} matches any of the keywords given.
12+
*/
13+
public class GroupContainsKeywordsPredicate implements Predicate<Person> {
14+
private final List<String> keywords;
15+
16+
public GroupContainsKeywordsPredicate(List<String> keywords) {
17+
this.keywords = keywords;
18+
}
19+
20+
@Override
21+
public boolean test(Person person) {
22+
Set<Group> groups = person.getGroups();
23+
return keywords.stream()
24+
.anyMatch(keyword ->
25+
groups.stream().anyMatch(group ->
26+
StringUtil.containsWordIgnoreCase(group.getGroupName(), keyword)));
27+
}
28+
29+
@Override
30+
public boolean equals(Object other) {
31+
return other == this // short circuit if same object
32+
|| (other instanceof seedu.address.model.group.GroupContainsKeywordsPredicate // instanceof handles nulls
33+
&& keywords.equals(((seedu.address.model.group.GroupContainsKeywordsPredicate) other).keywords)); // state check
34+
}
35+
36+
}

src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
"phone" : "94351253",
66
"email" : "alice@example.com",
77
"address" : "123, Jurong West Ave 6, #08-111",
8-
"group": [ "friends" ]
8+
"group": [ "table tennis" ]
99
}, {
1010
"name" : "Benson Meier",
1111
"phone" : "98765432",
1212
"email" : "johnd@example.com",
1313
"address" : "311, Clementi Ave 2, #02-25",
14-
"group": [ "owesMoney", "friends" ]
14+
"group": [ "CS2106", "table tennis" ]
1515
}, {
1616
"name" : "Carl Kurz",
1717
"phone" : "95352563",
@@ -23,7 +23,7 @@
2323
"phone" : "87652533",
2424
"email" : "cornelia@example.com",
2525
"address" : "10th street",
26-
"group": [ "friends" ]
26+
"group": [ "table tennis" ]
2727
}, {
2828
"name" : "Elle Meyer",
2929
"phone" : "9482224",
@@ -42,5 +42,17 @@
4242
"email" : "anna@example.com",
4343
"address" : "4th street",
4444
"group": [ ]
45-
} ]
45+
} , {
46+
"name" : "Jenny Li",
47+
"phone" : "9482432",
48+
"email" : "jenny@example.com",
49+
"address" : "5th road",
50+
"group": [ "badminton", "CS2106" ]
51+
}, {
52+
"name" : "Wendy Chen",
53+
"phone" : "9482222",
54+
"email" : "wendy@example.com",
55+
"address" : "7th way",
56+
"group": [ "badminton", "CS2103", "CS2106" ]
57+
}]
4658
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package seedu.address.logic.commands;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
7+
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
8+
import static seedu.address.testutil.TypicalPersons.ALICE;
9+
import static seedu.address.testutil.TypicalPersons.BENSON;
10+
import static seedu.address.testutil.TypicalPersons.DANIEL;
11+
import static seedu.address.testutil.TypicalPersons.JENNY;
12+
import static seedu.address.testutil.TypicalPersons.WENDY;
13+
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
14+
15+
import java.util.Arrays;
16+
import java.util.Collections;
17+
18+
import org.junit.jupiter.api.Test;
19+
20+
import seedu.address.logic.commands.persons.FindGroupCommand;
21+
import seedu.address.model.Model;
22+
import seedu.address.model.ModelManager;
23+
import seedu.address.model.UserPrefs;
24+
import seedu.address.model.group.GroupContainsKeywordsPredicate;
25+
26+
/**
27+
* Contains integration tests (interaction with the Model) for {@code FindGroupCommand}.
28+
*/
29+
public class FindGroupCommandTest {
30+
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
31+
private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
32+
33+
@Test
34+
public void equals() {
35+
GroupContainsKeywordsPredicate firstPredicate =
36+
new GroupContainsKeywordsPredicate(Collections.singletonList("first"));
37+
GroupContainsKeywordsPredicate secondPredicate =
38+
new GroupContainsKeywordsPredicate(Collections.singletonList("second"));
39+
40+
FindGroupCommand findFirstCommand = new FindGroupCommand(firstPredicate);
41+
FindGroupCommand findSecondCommand = new FindGroupCommand(secondPredicate);
42+
43+
// same object -> returns true
44+
assertTrue(findFirstCommand.equals(findFirstCommand));
45+
46+
// same values -> returns true
47+
FindGroupCommand findFirstCommandCopy = new FindGroupCommand(firstPredicate);
48+
assertTrue(findFirstCommand.equals(findFirstCommandCopy));
49+
50+
// different types -> returns false
51+
assertFalse(findFirstCommand.equals(1));
52+
53+
// null -> returns false
54+
assertFalse(findFirstCommand.equals(null));
55+
56+
// different person -> returns false
57+
assertFalse(findFirstCommand.equals(findSecondCommand));
58+
}
59+
60+
@Test
61+
public void execute_zeroKeywords_noPersonFound() {
62+
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
63+
GroupContainsKeywordsPredicate predicate = preparePredicate(" ");
64+
FindGroupCommand command = new FindGroupCommand(predicate);
65+
expectedModel.updateFilteredPersonList(predicate);
66+
assertCommandSuccess(command, model, expectedMessage, expectedModel);
67+
assertEquals(Collections.emptyList(), model.getFilteredPersonList());
68+
}
69+
70+
/**
71+
* Correctly returns an empty collection when a non-existing group is inputted as keyword
72+
*/
73+
@Test
74+
public void execute_wrongKeywords_noPersonFound() {
75+
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
76+
GroupContainsKeywordsPredicate predicate = preparePredicate("test");
77+
FindGroupCommand command = new FindGroupCommand(predicate);
78+
expectedModel.updateFilteredPersonList(predicate);
79+
assertCommandSuccess(command, model, expectedMessage, expectedModel);
80+
assertEquals(Collections.emptyList(), model.getFilteredPersonList());
81+
}
82+
83+
/**
84+
* Correctly returns all people in the specified group - first test
85+
*/
86+
@Test
87+
public void execute_multipleGroupsFoundFirst() {
88+
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
89+
GroupContainsKeywordsPredicate predicate = preparePredicate("table tennis");
90+
FindGroupCommand command = new FindGroupCommand(predicate);
91+
expectedModel.updateFilteredPersonList(predicate);
92+
assertCommandSuccess(command, model, expectedMessage, expectedModel);
93+
assertEquals(Arrays.asList(ALICE, BENSON, DANIEL), model.getFilteredPersonList());
94+
}
95+
96+
/**
97+
* Correctly returns all people in the specified group - second test
98+
*/
99+
@Test
100+
public void execute_multipleGroupsFoundSecond() {
101+
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
102+
GroupContainsKeywordsPredicate predicate = preparePredicate("CS2106");
103+
FindGroupCommand command = new FindGroupCommand(predicate);
104+
expectedModel.updateFilteredPersonList(predicate);
105+
assertCommandSuccess(command, model, expectedMessage, expectedModel);
106+
assertEquals(Arrays.asList(BENSON, JENNY, WENDY), model.getFilteredPersonList());
107+
}
108+
109+
/**
110+
* Correctly returns all people in groups with the partial keyword
111+
*/
112+
@Test
113+
public void execute_partialGroupKeyword_multipleGroupsFound() {
114+
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
115+
GroupContainsKeywordsPredicate predicate = preparePredicate("table");
116+
FindGroupCommand command = new FindGroupCommand(predicate);
117+
expectedModel.updateFilteredPersonList(predicate);
118+
assertCommandSuccess(command, model, expectedMessage, expectedModel);
119+
assertEquals(Arrays.asList(ALICE, BENSON, DANIEL), model.getFilteredPersonList());
120+
}
121+
122+
/**
123+
* Parses {@code userInput} into a {@code GroupContainsKeywordsPredicate}.
124+
*/
125+
private GroupContainsKeywordsPredicate preparePredicate(String userInput) {
126+
return new GroupContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
127+
}
128+
}
129+

src/test/java/seedu/address/testutil/TypicalPersons.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,28 @@ public class TypicalPersons {
2626
public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
2727
.withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
2828
.withPhone("94351253")
29-
.withGroups("friends").build();
29+
.withGroups("table tennis").build();
3030
public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
3131
.withAddress("311, Clementi Ave 2, #02-25")
3232
.withEmail("johnd@example.com").withPhone("98765432")
33-
.withGroups("owesMoney", "friends").build();
33+
.withGroups("CS2106", "table tennis").build();
3434
public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
3535
.withEmail("heinz@example.com").withAddress("wall street").build();
3636
public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
37-
.withEmail("cornelia@example.com").withAddress("10th street").withGroups("friends").build();
37+
.withEmail("cornelia@example.com").withAddress("10th street")
38+
.withGroups("table tennis").build();
3839
public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
3940
.withEmail("werner@example.com").withAddress("michegan ave").build();
4041
public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
4142
.withEmail("lydia@example.com").withAddress("little tokyo").build();
4243
public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
4344
.withEmail("anna@example.com").withAddress("4th street").build();
45+
public static final Person JENNY = new PersonBuilder().withName("Jenny Li").withPhone("9482432")
46+
.withEmail("jenny@example.com").withAddress("5th road")
47+
.withGroups("badminton", "CS2106").build();
48+
public static final Person WENDY = new PersonBuilder().withName("Wendy Chen").withPhone("9482222")
49+
.withEmail("wendy@example.com").withAddress("7th way")
50+
.withGroups("badminton", "CS2103", "CS2106").build();
4451

4552
// Manually added
4653
public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
@@ -71,6 +78,6 @@ public static AddressBook getTypicalAddressBook() {
7178
}
7279

7380
public static List<Person> getTypicalPersons() {
74-
return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
81+
return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE, JENNY, WENDY));
7582
}
7683
}

0 commit comments

Comments
 (0)