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

[W5.7][F11-2] Teo Wei Zheng #458

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
21 changes: 20 additions & 1 deletion docs/UserGuide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ What's different from AddressBook-Level1:
* Support for storing address (`a/`) and tags (`t/`)
* Support for marking a contact detail as 'private' (`pa/`) (`pe/`) (`pp/`)
* View details of a person (`view` : shows non-private details), (`viewall` : shows all details)
* Search for persons by tags (`find` : searches for persons by name), (`findtag` : searches for persons by tags)

== Viewing help : `help`

Expand Down Expand Up @@ -89,7 +90,25 @@ Examples:
Returns `John Doe` but not `john`.

* `find Betsy Tim John` +
Returns Any person having names `Betsy`, `Tim`, or `John`.
Returns any person having names `Betsy`, `Tim`, or `John`.

== Finding all persons containing any keyword in their tags: `findtag`

Finds persons who are tagged with the given keywords. +
Format: `findtag KEYWORD [MORE_KEYWORDS]`

[NOTE]
====
The search is case sensitive, the order of the keywords does not matter, only the tags searched,
and persons with at least one tag in the keywords will be returned.
====

Examples:
* `findtag friends` +
Returns all the people with the tag `friends`.

* `findtag adorable pretty hot` +
Returns any person with any one of the tags `adorable`, `pretty` or `hot`.

== Deleting a person : `delete`

Expand Down
68 changes: 68 additions & 0 deletions src/seedu/addressbook/commands/FindTagCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package seedu.addressbook.commands;

import seedu.addressbook.data.person.ReadOnlyPerson;
import seedu.addressbook.data.tag.Tag;
import seedu.addressbook.data.exception.IllegalValueException;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
import java.util.Collections;


/**
* Finds and lists all the people in the address book who are tagged with the argument keywords.
* Keyword matching is case sensitive.
*/
public class FindTagCommand extends Command {

public static final String COMMAND_WORD = "findtag";

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Finds all the people who are tagged with the specified keywords (case-sensitive) and "
+ "displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ "Example: " + COMMAND_WORD + " isCute isHandsome";

private final Set<String> keywords;

public FindTagCommand(Set<String> keywords) { this.keywords = keywords; }

/**
* Returns a copy of keywords in this command.
*/
public Set<String> getKeywords() {
return new HashSet<>(keywords);
}

@Override
public CommandResult execute() {
final List<ReadOnlyPerson> personsFound = getPersonsWithTagsContainingAnyKeyword(keywords);
return new CommandResult(getMessageForPersonListShownSummary(personsFound), personsFound);
}

private List<ReadOnlyPerson> getPersonsWithTagsContainingAnyKeyword (Set<String> keywords) {
// convert the keywords into tags
final Set<Tag> keywordTags = new HashSet<>();
for (String keyword : keywords) {
try {
keywordTags.add(new Tag(keyword));
} catch (IllegalValueException e) {
// if an invalid string is provided as argument, just ignore, since
// the string will not be able to be the tag of a Person.
continue;
}
}

// compare tags
final List<ReadOnlyPerson> matchedPersons = new ArrayList<>();
for (ReadOnlyPerson person : addressBook.getAllPersons()) {
final Set<Tag> personsTags = person.getTags();
if (!Collections.disjoint(keywordTags, personsTags)) {
matchedPersons.add(person);
}
}
return matchedPersons;
}
}
23 changes: 23 additions & 0 deletions src/seedu/addressbook/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import seedu.addressbook.commands.ListCommand;
import seedu.addressbook.commands.ViewAllCommand;
import seedu.addressbook.commands.ViewCommand;
import seedu.addressbook.commands.FindTagCommand;
import seedu.addressbook.data.exception.IllegalValueException;

/**
Expand Down Expand Up @@ -97,6 +98,9 @@ public Command parseCommand(String userInput) {
case ExitCommand.COMMAND_WORD:
return new ExitCommand();

case FindTagCommand.COMMAND_WORD:
return prepareFindTag(arguments);

case HelpCommand.COMMAND_WORD: // Fallthrough
default:
return new HelpCommand();
Expand Down Expand Up @@ -249,4 +253,23 @@ private Command prepareFind(String args) {
}


/**
* Parses arguments in the context of the find tag command.
*
* @param args full command args string
* @return the prepared command
*/
private Command prepareFindTag(String args) {
final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim());
if (!matcher.matches()) {
return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
FindTagCommand.MESSAGE_USAGE));
}

// keywords delimited by whitespace
final String[] keywords = matcher.group("keywords").split("\\s+");
final Set<String> keywordSet = new HashSet<>(Arrays.asList(keywords));
return new FindTagCommand(keywordSet);
}

}
35 changes: 35 additions & 0 deletions test/expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,41 @@
||
|| 2 persons listed!
|| ===================================================
|| Enter command: || [Command entered: findtag]
|| Invalid command format!
|| findtag: Finds all the people who are tagged with the specified keywords (case-sensitive) and displays them as a list with index numbers.
|| Parameters: KEYWORD [MORE_KEYWORDS]...
|| Example: findtag isCute isHandsome
|| ===================================================
|| Enter command: || [Command entered: findtag fre]
||
|| 0 persons listed!
|| ===================================================
|| Enter command: || [Command entered: findtag nonexistent]
||
|| 0 persons listed!
|| ===================================================
|| Enter command: || [Command entered: findtag FRIENDS]
||
|| 0 persons listed!
|| ===================================================
|| Enter command: || [Command entered: findtag secretive]
|| 1. Betsy Choo Tags: [secretive]
||
|| 1 persons listed!
|| ===================================================
|| Enter command: || [Command entered: findtag friends]
|| 1. Charlie Dickson Email: [email protected] Address: 333, gamma street Tags: [school][friends]
|| 2. Dickson Ee Phone: 444444 Address: 444, delta street Tags: [friends]
||
|| 2 persons listed!
|| ===================================================
|| Enter command: || [Command entered: findtag secretive school]
|| 1. Betsy Choo Tags: [secretive]
|| 2. Charlie Dickson Email: [email protected] Address: 333, gamma street Tags: [school][friends]
||
|| 2 persons listed!
|| ===================================================
|| Enter command: || [Command entered: delete]
|| Invalid command format!
|| delete: Deletes the person identified by the index number used in the last person listing.
Expand Down
20 changes: 20 additions & 0 deletions test/input.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@
# find multiple with some keywords
find Charlie Betsy

##########################################################
# test find tag command
##########################################################

# should consider no keywords as invalid command format
findtag
# should only match full words in tag names
findtag fre
# does not match if none have keyword
findtag nonexistent
# matching should be case-sensitive
findtag FRIENDS

# find unique keyword
findtag secretive
# find multiple with same keyword
findtag friends
# find multiple with some keywords
findtag secretive school

##########################################################
# test delete person command
##########################################################
Expand Down
66 changes: 66 additions & 0 deletions test/java/seedu/addressbook/commands/FindTagCommandTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package seedu.addressbook.commands;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.Test;

import seedu.addressbook.data.AddressBook;
import seedu.addressbook.data.exception.IllegalValueException;
import seedu.addressbook.data.person.ReadOnlyPerson;
import seedu.addressbook.util.TypicalPersons;

public class FindTagCommandTest {

private final AddressBook addressBook = new TypicalPersons().getTypicalAddressBook();
private final TypicalPersons td = new TypicalPersons();

@Test
public void execute() throws IllegalValueException {
//same word, same case: matched
assertFindTagCommandBehavior(new String[]{"test1"}, Arrays.asList(td.amy, td.dan));

//same word, different case: not matched
assertFindTagCommandBehavior(new String[]{"Test1"}, Collections.emptyList());

//partial word: not matched
assertFindTagCommandBehavior(new String[]{"test"}, Collections.emptyList());

//multiple tags: matched
assertFindTagCommandBehavior(new String[]{"test1", "test2"},
Arrays.asList(td.amy, td.bill, td.dan));

//repeated tags: matched
assertFindTagCommandBehavior(new String[]{"test2", "test2"}, Arrays.asList(td.bill));

//Keyword matching a name: not matched
assertFindTagCommandBehavior(new String[]{"Amy Buck"}, Collections.emptyList());

//Keyword matching a word in address: not matched
assertFindTagCommandBehavior(new String[]{"Clementi"}, Collections.emptyList());
}

/**
* Executes the findtag command for the given keywords and verifies
* the result matches the persons in the expectedPersonList exactly.
*/
private void assertFindTagCommandBehavior(String[] keywords, List<ReadOnlyPerson> expectedPersonList) {
FindTagCommand command = createFindTagCommand(keywords);
CommandResult result = command.execute();

assertEquals(Command.getMessageForPersonListShownSummary(expectedPersonList), result.feedbackToUser);
}

private FindTagCommand createFindTagCommand(String[] keywords) {
final Set<String> keywordSet = new HashSet<>(Arrays.asList(keywords));
FindTagCommand command = new FindTagCommand(keywordSet);
command.setData(addressBook, Collections.emptyList());
return command;
}

}
6 changes: 3 additions & 3 deletions test/java/seedu/addressbook/util/TypicalPersons.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ public class TypicalPersons {
public TypicalPersons() {
try {
amy = new Person(new Name("Amy Buck"), new Phone("91119111", false), new Email("[email protected]", false),
new Address("1 Clementi Road", false), Collections.emptySet());
new Address("1 Clementi Road", false), Collections.singleton(new Tag("test1")));
bill = new Person(new Name("Bill Clint"), new Phone("92229222", false), new Email("[email protected]", false),
new Address("2 Clementi Road", true), Collections.emptySet());
new Address("2 Clementi Road", true), Collections.singleton(new Tag("test2")));
candy = new Person(new Name("Candy Destiny"), new Phone("93339333", true),
new Email("[email protected]", false), new Address("3 Clementi Road", true), Collections.emptySet());
dan = new Person(new Name("Dan Smith"), new Phone("1234556", true), new Email("[email protected]", true),
new Address("NUS", true), Collections.singleton(new Tag("test")));
new Address("NUS", true), Collections.singleton(new Tag("test1")));
} catch (IllegalValueException e) {
e.printStackTrace();
assert false : "not possible";
Expand Down