From 61fda2b29b11c1b395a9a6428fcd61258684b10d Mon Sep 17 00:00:00 2001 From: "LAPTOP-O5OGN9M1\\Wei Zheng" Date: Tue, 11 Sep 2018 19:54:25 +0800 Subject: [PATCH 1/6] commands: add FindTagCommand class Currently, the tags for each person do not seem to serve any purpose. However, the tags can be a useful and flexible way for filtering out certain types of people. Let's add a new command to allow users to search people by their tags. --- .../addressbook/commands/FindTagCommand.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/seedu/addressbook/commands/FindTagCommand.java diff --git a/src/seedu/addressbook/commands/FindTagCommand.java b/src/seedu/addressbook/commands/FindTagCommand.java new file mode 100644 index 000000000..8604f0fb5 --- /dev/null +++ b/src/seedu/addressbook/commands/FindTagCommand.java @@ -0,0 +1,44 @@ +package seedu.addressbook.commands; + +import seedu.addressbook.data.person.ReadOnlyPerson; + +import java.util.HashSet; +import java.util.Set; +import java.util.List; + + +/** + * 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 keywords; + + public FindTagCommand(Set keywords) { this.keywords = keywords; } + + /** + * Returns a copy of keywords in this command. + */ + public Set getKeywords() { + return new HashSet<>(keywords); + } + + @Override + public CommandResult execute() { + return new CommandResult("testing"); + /* + final List personsFound = getPersonsWithTagsContainingAnyKeyword(keywords); + return new CommandResult(getMessageForPersonListShownSummary(personsFound), personsFound); + */ + } + +} From 49bcc9d4d86e18b3f7136d1bb04dc929365b2f7b Mon Sep 17 00:00:00 2001 From: "LAPTOP-O5OGN9M1\\Wei Zheng" Date: Tue, 11 Sep 2018 20:57:38 +0800 Subject: [PATCH 2/6] parser/Parser.java: add findtag case The new command for finding people by tag is not a recognised command yet. This commit adds the option "findtag" into the CLI. At this stage, invoking the "findtag" command with any number of arguments will only print a test message. --- src/seedu/addressbook/parser/Parser.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/seedu/addressbook/parser/Parser.java b/src/seedu/addressbook/parser/Parser.java index abddb3f45..d54219ceb 100644 --- a/src/seedu/addressbook/parser/Parser.java +++ b/src/seedu/addressbook/parser/Parser.java @@ -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; /** @@ -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(); @@ -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 keywordSet = new HashSet<>(Arrays.asList(keywords)); + return new FindTagCommand(keywordSet); + } + } From 21af196f1b24a462eac36cf7915e53dc7e296276 Mon Sep 17 00:00:00 2001 From: "LAPTOP-O5OGN9M1\\Wei Zheng" Date: Tue, 11 Sep 2018 22:29:37 +0800 Subject: [PATCH 3/6] commands: add findtag functionality The "findtag" command is currently recognised but only prints a test message as of now. This commit adds in the functionality of this function. Users may now use the "findtag" command and provide multiple tags to search for people with the given tags. --- .../addressbook/commands/FindTagCommand.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/seedu/addressbook/commands/FindTagCommand.java b/src/seedu/addressbook/commands/FindTagCommand.java index 8604f0fb5..a8ecd56d7 100644 --- a/src/seedu/addressbook/commands/FindTagCommand.java +++ b/src/seedu/addressbook/commands/FindTagCommand.java @@ -1,10 +1,14 @@ 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; /** @@ -34,11 +38,31 @@ public Set getKeywords() { @Override public CommandResult execute() { - return new CommandResult("testing"); - /* final List personsFound = getPersonsWithTagsContainingAnyKeyword(keywords); return new CommandResult(getMessageForPersonListShownSummary(personsFound), personsFound); - */ } + private List getPersonsWithTagsContainingAnyKeyword (Set keywords) { + // convert the keywords into tags + final Set 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 matchedPersons = new ArrayList<>(); + for (ReadOnlyPerson person : addressBook.getAllPersons()) { + final Set personsTags = person.getTags(); + if (!Collections.disjoint(keywordTags, personsTags)) { + matchedPersons.add(person); + } + } + return matchedPersons; + } } From 15e4c5362b5f8781cfbf8991f05b201ce35068d2 Mon Sep 17 00:00:00 2001 From: "LAPTOP-O5OGN9M1\\Wei Zheng" Date: Tue, 11 Sep 2018 22:58:21 +0800 Subject: [PATCH 4/6] test: add findtag test cases The command "findtag" has been implemented but not tested yet. This commit adds several test cases to ensure that the command functions properly. --- test/expected.txt | 35 +++++++++++++++++++++++++++++++++++ test/input.txt | 20 ++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/test/expected.txt b/test/expected.txt index 56fe5fcac..915f60ef0 100644 --- a/test/expected.txt +++ b/test/expected.txt @@ -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: charlie.d@nus.edu.sg 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: charlie.d@nus.edu.sg 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. diff --git a/test/input.txt b/test/input.txt index eb8df81f8..2cf611400 100644 --- a/test/input.txt +++ b/test/input.txt @@ -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 ########################################################## From a9d91f5e716d7a9517a9ad4027e04e1f369af4c1 Mon Sep 17 00:00:00 2001 From: "LAPTOP-O5OGN9M1\\Wei Zheng" Date: Wed, 12 Sep 2018 00:02:07 +0800 Subject: [PATCH 5/6] test: add JUnit tests The "findtag" command has been implemented but lacks a proper unit test. Bugs may be present that may not be discoverable by users. This commit adds several JUnit tests to ensure the correctness of this command. --- .../commands/FindTagCommandTest.java | 66 +++++++++++++++++++ .../addressbook/util/TypicalPersons.java | 6 +- 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 test/java/seedu/addressbook/commands/FindTagCommandTest.java diff --git a/test/java/seedu/addressbook/commands/FindTagCommandTest.java b/test/java/seedu/addressbook/commands/FindTagCommandTest.java new file mode 100644 index 000000000..2c04f12a5 --- /dev/null +++ b/test/java/seedu/addressbook/commands/FindTagCommandTest.java @@ -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 expectedPersonList) { + FindTagCommand command = createFindTagCommand(keywords); + CommandResult result = command.execute(); + + assertEquals(Command.getMessageForPersonListShownSummary(expectedPersonList), result.feedbackToUser); + } + + private FindTagCommand createFindTagCommand(String[] keywords) { + final Set keywordSet = new HashSet<>(Arrays.asList(keywords)); + FindTagCommand command = new FindTagCommand(keywordSet); + command.setData(addressBook, Collections.emptyList()); + return command; + } + +} diff --git a/test/java/seedu/addressbook/util/TypicalPersons.java b/test/java/seedu/addressbook/util/TypicalPersons.java index cd3a3f819..9f2239a4f 100644 --- a/test/java/seedu/addressbook/util/TypicalPersons.java +++ b/test/java/seedu/addressbook/util/TypicalPersons.java @@ -21,13 +21,13 @@ public class TypicalPersons { public TypicalPersons() { try { amy = new Person(new Name("Amy Buck"), new Phone("91119111", false), new Email("ab@gmail.com", 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("bc@gmail.com", 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("cd@gmail.com", false), new Address("3 Clementi Road", true), Collections.emptySet()); dan = new Person(new Name("Dan Smith"), new Phone("1234556", true), new Email("ss@tt.com", 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"; From 981caed19f22b1b0be0e529950a22a6b73948f5d Mon Sep 17 00:00:00 2001 From: "LAPTOP-O5OGN9M1\\Wei Zheng" Date: Wed, 12 Sep 2018 00:24:44 +0800 Subject: [PATCH 6/6] docs: update UserGuide The command "findtag" has been implemented but the user guide has not been updated. Users may be unaware of the existence of this command or may not understand how to use it. The user guide has been updated to teach users about this command. --- docs/UserGuide.adoc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 4abb17e3e..e7928e539 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -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` @@ -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`