diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 6c7f6d2ee01..d1dddca70d1 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -81,7 +81,7 @@ Adds a contact to OutBook.
Format: `addc n/NAME p/PHONE_NUMBER e/EMAIL l/LAST_CONTACTED_TIME s/STATUS [t/TAG]…`
-* NAME, PHONE_NUMBER, EMAIL and LAST_CONTACTED_TIME are compulsory fields. STATUS and TAG are optional.
+* NAME, PHONE_NUMBER, and EMAIL are compulsory fields. STATUS, TAG and LAST_CONTACTED_TIME are optional.
* PHONE_NUMBER must contain only numbers, and be at least 3 digits long.
* EMAIL must be of the format local-part@domain and adhere to the following constraints:
1. The local-part should only contain alphanumeric characters and these special characters, excluding the parentheses, (+_.-).
@@ -174,23 +174,28 @@ Examples:
* `viewc 2` Displays detailed information related to the 2nd contact on the list.
-### Locating persons by name: `findc`
+### Search for persons using contact fields: `findc`
+Find persons whose contact details match the keywords specified for at least 1 of these fields: name, phone, email, status, tag
-Find contacts whose names contain any of the given keywords.
+Format: `findc [n/KEYWORDS] [p/KEYWORDS] [e/KEYWORDS] [l/DATETIME] [s/KEYWORDS] [t/KEYWORDS]`
-Format: `findc KEYWORD [MORE_KEYWORDS]`
-
-* The search is case-insensitive. e.g `hans` will match `Hans`
-* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
-* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
-* Persons matching at least one keyword will be returned (i.e. `OR` search).
- e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
+* The search is case-insensitive. e.g `shop` will match `SHOP`
+* The order of the keywords does not matter. e.g. `Shop Meet` will match `Meet Shop`
+* For name, status and tags, only full words will be matched e.g. `Meet` will not match `Meeting`
+* For email, any characters (alphanumeric, special characters) will be matched e.g. `_` will match `m_e@gmail.com`
+* For phone, the entire length of the input digits will be matched e.g. `913` will match `90091300` but not `90103000`
+* For last contacted time, the input must adhere to the dd.MM.yyyy HHmm format e.g. 9th October 2023 10.30am will be `09.10.2023 1030`
+* For a single field, a Person must match at least one keyword to be returned as a result (i.e. `OR` search).
+ e.g. `John Doe` will return `John Lee`, `James Doe`
+* If there are multiple fields specified, the Person must match at least one keyword in each field to be returned as a result (i.e. `AND` search).
+ e.g. `m/Shop Meet a/Mall` will return `Meeting: Shop at mall, Location:Mall`
Examples:
-* `findc John` returns `john` and `John Doe`
-* `findc alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+* `findc n/alice` returns `Alice` and `alice tan`
+* `findc p/51` returns `95163890` and `40351`
+* `findc e/_@GMAIL` returns `alice_@gmail.com`
+* `findc p/9 s/inactive claimant t/friend` returns persons with a `9` in their phone number, whose status is either `inactive` or `claimant`, and has a `friend` tag
+ ![result for 'findContact'](images/findContactResult.png)
## Meeting commands
diff --git a/docs/images/findContactResult.png b/docs/images/findContactResult.png
new file mode 100644
index 00000000000..ffb5f6ad841
Binary files /dev/null and b/docs/images/findContactResult.png differ
diff --git a/docs/team/qz1004.md b/docs/team/qz1004.md
index 2630c06a5d9..1a3f80b1d99 100644
--- a/docs/team/qz1004.md
+++ b/docs/team/qz1004.md
@@ -20,10 +20,11 @@ My contributions to the project are listed below.
- **Enhancements to existing features**:
- Add Status field to Person
+ - Improve `findc` to search for phone, email, status and tags in addition to name
- **Documentation**:
- - Update Developer Guide with the features that I implemented
- - Update User Guide with the features that I implemented
+ - "Add attendee" feature in Developer Guide
+ - Modified the User Guide for `addc`, `findc` and `addmc`
- **Community**:
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 3f4cdb50bc4..ee0e98c0d1f 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -27,7 +27,7 @@ public class AddCommand extends Command {
+ PREFIX_NAME + "NAME "
+ PREFIX_PHONE + "PHONE "
+ PREFIX_EMAIL + "EMAIL "
- + PREFIX_LASTTIME + "LAST CONTACTED TIME "
+ + "[" + PREFIX_LASTTIME + "LAST CONTACTED TIME] "
+ "[" + PREFIX_STATUS + "STATUS] "
+ "[" + PREFIX_REMARK + "REMARK] "
+ "[" + PREFIX_TAG + "TAG]...\n"
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index e471daf0e2e..386c3495f47 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -5,7 +5,7 @@
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.GeneralPersonPredicate;
/**
* Finds and lists all persons in address book whose name contains any of the argument keywords.
@@ -15,14 +15,20 @@ public class FindCommand extends Command {
public static final String COMMAND_WORD = "findc";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Finds all contacts whose specified fields (except remarks) 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";
+ + "Parameters: n/KEYWORDS p/KEYWORDS e/KEYWORDS l/LOCALDATETIME s/KEYWORDS t/KEYWORDS\n"
+ + "Example: " + COMMAND_WORD + " n/alice l/10.10.2023 0900 s/Prospective t/Health";
- private final NameContainsKeywordsPredicate predicate;
+ private final GeneralPersonPredicate predicate;
- public FindCommand(NameContainsKeywordsPredicate predicate) {
+ /**
+ * Constructs a FindCommand object.
+ * @param predicate The predicate that will be used by the FindCommand object.
+ */
+ public FindCommand(GeneralPersonPredicate predicate) {
+ requireNonNull(predicate);
this.predicate = predicate;
}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 1161258301f..917fdf54a70 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -16,7 +16,6 @@
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Email;
-import seedu.address.model.person.LastContactedTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
@@ -39,7 +38,7 @@ public AddCommand parse(String args) throws ParseException {
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_LASTTIME,
PREFIX_STATUS, PREFIX_REMARK, PREFIX_TAG);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_LASTTIME)
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
@@ -49,10 +48,7 @@ public AddCommand parse(String args) throws ParseException {
Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- LocalDateTime lastContactedTime = ParserUtil.parseContactTime(argMultimap.getValue(PREFIX_LASTTIME).get());
- if (!LastContactedTime.isValidLastContactedTime(lastContactedTime)) {
- throw new ParseException(LastContactedTime.MESSAGE_CONSTRAINTS);
- }
+ LocalDateTime lastContactedTime = ParserUtil.parseContactTime(argMultimap.getValue(PREFIX_LASTTIME).orElse(""));
Status status = ParserUtil.parseStatus(argMultimap.getValue(PREFIX_STATUS).orElse(""));
Remark remark = ParserUtil.parseRemark(argMultimap.getValue(PREFIX_REMARK).orElse(""));
Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 2867bde857b..56829bbca15 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -1,17 +1,28 @@
package seedu.address.logic.parser;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTTIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import java.util.Arrays;
+import java.time.LocalDateTime;
+import java.util.logging.Logger;
+import seedu.address.Main;
+import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.GeneralPersonPredicate;
+import seedu.address.model.person.LastContactedTime;
/**
* Parses input arguments and creates a new FindCommand object
*/
public class FindCommandParser implements Parser {
+ private static Logger logger = LogsCenter.getLogger(Main.class);
/**
* Parses the given {@code String} of arguments in the context of the FindCommand
@@ -19,15 +30,43 @@ public class FindCommandParser implements Parser {
* @throws ParseException if the user input does not conform the expected format
*/
public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ logger.info("Begin FindCommand parse");
+ assert args != null;
+
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_LASTTIME, PREFIX_STATUS, PREFIX_TAG);
+ if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_LASTTIME, PREFIX_STATUS, PREFIX_TAG);
+
+ logger.info("Begin creation of Meeting predicates");
+ String[] nameKeyWords = argMultimap.getValue(PREFIX_NAME).orElse("").split("\\s+");
+ String[] phoneValues = argMultimap.getValue(PREFIX_PHONE).orElse("").split("\\s+");
+ String[] emailKeyWords = argMultimap.getValue(PREFIX_EMAIL).orElse("").split("\\s+");
+ String[] statusKeyWords = argMultimap.getValue(PREFIX_STATUS).orElse("").split("\\s+");
+ String[] tagKeyWords = argMultimap.getValue(PREFIX_TAG).orElse("").split("\\s+");
+
+ LocalDateTime lastContacted = LocalDateTime.MIN;
+ if (argMultimap.getValue(PREFIX_LASTTIME).isPresent()) {
+ lastContacted = ParserUtil.parseContactTime(argMultimap.getValue(PREFIX_LASTTIME).get());
+ if (!LastContactedTime.isValidLastContactedTime(lastContacted)) {
+ throw new ParseException(LastContactedTime.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ GeneralPersonPredicate generalPersonPredicate = new GeneralPersonPredicate(
+ nameKeyWords,
+ phoneValues,
+ emailKeyWords,
+ lastContacted,
+ statusKeyWords,
+ tagKeyWords);
- String[] nameKeywords = trimmedArgs.split("\\s+");
+ logger.info("All Person predicates created");
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ return new FindCommand(generalPersonPredicate);
}
}
diff --git a/src/main/java/seedu/address/logic/parser/FindMeetingCommandParser.java b/src/main/java/seedu/address/logic/parser/FindMeetingCommandParser.java
index d2eefb72bfe..627ea6cff38 100644
--- a/src/main/java/seedu/address/logic/parser/FindMeetingCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindMeetingCommandParser.java
@@ -59,7 +59,6 @@ public FindMeetingCommand parse(String args) throws ParseException {
String[] attendeeKeyWords = argMultimap.getValue(PREFIX_NAME).orElse("").split("\\s+");
String[] tagKeyWords = argMultimap.getValue(PREFIX_TAG).orElse("").split("\\s+");
-
GeneralMeetingPredicate generalMeetingPredicate = new GeneralMeetingPredicate(
titleKeyWords,
locationKeyWords,
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index 2607a071c0e..cb16e8339e9 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -155,8 +155,16 @@ public static Email parseEmail(String email) throws ParseException {
public static LocalDateTime parseContactTime(String time) throws ParseException {
requireNonNull(time);
String trimmedStart = time.trim();
+ //set last contacted to LocalDateTime.MIN if last contacted field is not specified
+ if (trimmedStart.isEmpty()) {
+ return LocalDateTime.MIN;
+ }
try {
- return LocalDateTime.parse(trimmedStart, FORMAT);
+ LocalDateTime preppedTime = LocalDateTime.parse(trimmedStart, FORMAT);
+ if (!LastContactedTime.isValidLastContactedTime(preppedTime)) {
+ throw new ParseException(LastContactedTime.MESSAGE_CONSTRAINTS);
+ }
+ return preppedTime;
} catch (DateTimeParseException e) {
throw new ParseException(LastContactedTime.MESSAGE_CONSTRAINTS);
}
diff --git a/src/main/java/seedu/address/model/meeting/GeneralMeetingPredicate.java b/src/main/java/seedu/address/model/meeting/GeneralMeetingPredicate.java
index b8b6086bff9..f8962347086 100644
--- a/src/main/java/seedu/address/model/meeting/GeneralMeetingPredicate.java
+++ b/src/main/java/seedu/address/model/meeting/GeneralMeetingPredicate.java
@@ -4,18 +4,15 @@
import java.util.Arrays;
import java.util.function.Predicate;
-import seedu.address.model.tag.TagContainsKeywordsPredicate;
-
-
/**
- * The predicate class that brings together of all the other predicate class.
+ * The predicate class that brings together of all the other predicate class for Meeting.
*/
public class GeneralMeetingPredicate implements Predicate {
private final TitleContainsKeywordsPredicate titlePredicate;
private final LocationContainsKeywordsPredicate locationPredicate;
private final MeetingTimeContainsPredicate meetingTimePredicate;
private final AttendeeContainsKeywordsPredicate attendeePredicate;
- private final TagContainsKeywordsPredicate tagPredicate;
+ private final MeetingTagContainsKeywordsPredicate tagPredicate;
/**
* Constructs a predicate class that fulfills all the argument predicates
@@ -29,7 +26,7 @@ public GeneralMeetingPredicate(TitleContainsKeywordsPredicate titlePredicate,
LocationContainsKeywordsPredicate locationPredicate,
MeetingTimeContainsPredicate meetingTimePredicate,
AttendeeContainsKeywordsPredicate attendeePredicate,
- TagContainsKeywordsPredicate tagPredicate) {
+ MeetingTagContainsKeywordsPredicate tagPredicate) {
this.titlePredicate = titlePredicate;
this.locationPredicate = locationPredicate;
this.meetingTimePredicate = meetingTimePredicate;
@@ -52,7 +49,7 @@ public GeneralMeetingPredicate(String[] titleKeyWords, String[] locationKeyWords
this.locationPredicate = new LocationContainsKeywordsPredicate(Arrays.asList(locationKeyWords));
this.meetingTimePredicate = new MeetingTimeContainsPredicate(start, end);
this.attendeePredicate = new AttendeeContainsKeywordsPredicate(Arrays.asList(attendeeKeyWords));
- this.tagPredicate = new TagContainsKeywordsPredicate(Arrays.asList(tagKeyWords));
+ this.tagPredicate = new MeetingTagContainsKeywordsPredicate(Arrays.asList(tagKeyWords));
}
@Override
diff --git a/src/main/java/seedu/address/model/tag/TagContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/meeting/MeetingTagContainsKeywordsPredicate.java
similarity index 66%
rename from src/main/java/seedu/address/model/tag/TagContainsKeywordsPredicate.java
rename to src/main/java/seedu/address/model/meeting/MeetingTagContainsKeywordsPredicate.java
index 1c6499f13fb..9e9a06424d1 100644
--- a/src/main/java/seedu/address/model/tag/TagContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/meeting/MeetingTagContainsKeywordsPredicate.java
@@ -1,19 +1,18 @@
-package seedu.address.model.tag;
+package seedu.address.model.meeting;
import java.util.List;
import java.util.function.Predicate;
import seedu.address.commons.util.StringUtil;
import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.meeting.Meeting;
/**
- * Tests that a {@code Meetings}'s {@code Title} matches any of the keywords given.
+ * Tests that a {@code Meeting}'s {@code Tag} matches any of the keywords given.
*/
-public class TagContainsKeywordsPredicate implements Predicate {
+public class MeetingTagContainsKeywordsPredicate implements Predicate {
private final List keywords;
- public TagContainsKeywordsPredicate(List keywords) {
+ public MeetingTagContainsKeywordsPredicate(List keywords) {
this.keywords = keywords;
}
@@ -31,11 +30,12 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof TagContainsKeywordsPredicate)) {
+ if (!(other instanceof MeetingTagContainsKeywordsPredicate)) {
return false;
}
- TagContainsKeywordsPredicate otherTagContainsKeywordsPredicate = (TagContainsKeywordsPredicate) other;
+ MeetingTagContainsKeywordsPredicate otherTagContainsKeywordsPredicate =
+ (MeetingTagContainsKeywordsPredicate) other;
return keywords.equals(otherTagContainsKeywordsPredicate.keywords);
}
diff --git a/src/main/java/seedu/address/model/meeting/MeetingTimeContainsPredicate.java b/src/main/java/seedu/address/model/meeting/MeetingTimeContainsPredicate.java
index b5aa1c091fd..b6f60fb7772 100644
--- a/src/main/java/seedu/address/model/meeting/MeetingTimeContainsPredicate.java
+++ b/src/main/java/seedu/address/model/meeting/MeetingTimeContainsPredicate.java
@@ -8,7 +8,7 @@
import seedu.address.commons.util.ToStringBuilder;
/**
- * Tests that a {@code Meetings}'s {@code MeetingTime} duration within the given start and end.
+ * Tests that a {@code Meeting}'s {@code MeetingTime} duration within the given start and end.
*/
public class MeetingTimeContainsPredicate implements Predicate {
private final LocalDateTime start;
diff --git a/src/main/java/seedu/address/model/person/EmailContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/EmailContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..77488cba4f6
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/EmailContainsKeywordsPredicate.java
@@ -0,0 +1,47 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Email} matches any of the keywords given.
+ */
+public class EmailContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public EmailContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ String email = person.getEmail().toString();
+ Boolean result = false;
+ for (String keyword : keywords) {
+ result |= email.contains(keyword.toLowerCase());
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EmailContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ EmailContainsKeywordsPredicate otherEmailContainsKeywordsPredicate = (EmailContainsKeywordsPredicate) other;
+ return keywords.equals(otherEmailContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/GeneralPersonPredicate.java b/src/main/java/seedu/address/model/person/GeneralPersonPredicate.java
new file mode 100644
index 00000000000..aaf660d263e
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/GeneralPersonPredicate.java
@@ -0,0 +1,89 @@
+package seedu.address.model.person;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.function.Predicate;
+
+/**
+ * The predicate class that brings together of all the other predicate class for Person.
+ */
+public class GeneralPersonPredicate implements Predicate {
+ private final NameContainsKeywordsPredicate namePredicate;
+ private final PhoneContainsPredicate phonePredicate;
+ private final EmailContainsKeywordsPredicate emailPredicate;
+ private final LastContactTimeContainsPredicate lastContactTimePredicate;
+ private final StatusContainsKeywordsPredicate statusPredicate;
+ private final PersonTagContainsKeywordsPredicate tagPredicate;
+
+ /**
+ * Constructs a predicate class that fulfills all the argument predicates
+ * @param namePredicate A predicate that test a person's name.
+ * @param phonePredicate A predicate that test a person's phone.
+ * @param emailPredicate A predicate that test a person's email.
+ * @param lastContactTimePredicate A predicate that test a person's last contacted time.
+ * @param statusPredicate A predicate that test a person's status.
+ * @param tagPredicate A predicate that test a person's tags.
+ */
+ public GeneralPersonPredicate(NameContainsKeywordsPredicate namePredicate,
+ PhoneContainsPredicate phonePredicate,
+ EmailContainsKeywordsPredicate emailPredicate,
+ LastContactTimeContainsPredicate lastContactTimePredicate,
+ StatusContainsKeywordsPredicate statusPredicate,
+ PersonTagContainsKeywordsPredicate tagPredicate) {
+ this.namePredicate = namePredicate;
+ this.phonePredicate = phonePredicate;
+ this.emailPredicate = emailPredicate;
+ this.lastContactTimePredicate = lastContactTimePredicate;
+ this.statusPredicate = statusPredicate;
+ this.tagPredicate = tagPredicate;
+ }
+
+ /**
+ * Constructs a predicate class that fulfills all the argument predicates
+ * @param nameKeyWords String array that will be used to construct NameContainsKeywordsPredicate
+ * @param phoneValues String array that will be used to construct PhoneContainsPredicate
+ * @param emailKeyWords String array that will be used to construct EmailContainsKeywordsPredicate
+ * @param lastContacted A predicate that wil be used to construct LastContactTimeContainsPredicate.
+ * @param statusKeyWords String array that will be used to construct StatusContainsKeywordsPredicate
+ * @param tagKeyWords String array that will be used to construct PersonTagContainsKeywordsPredicate
+ */
+ public GeneralPersonPredicate(String[] nameKeyWords, String[] phoneValues, String[] emailKeyWords,
+ LocalDateTime lastContacted, String[] statusKeyWords, String[] tagKeyWords) {
+ this.namePredicate = new NameContainsKeywordsPredicate(Arrays.asList(nameKeyWords));
+ this.phonePredicate = new PhoneContainsPredicate(Arrays.asList(phoneValues));
+ this.emailPredicate = new EmailContainsKeywordsPredicate(Arrays.asList(emailKeyWords));
+ this.lastContactTimePredicate = new LastContactTimeContainsPredicate(lastContacted);
+ this.statusPredicate = new StatusContainsKeywordsPredicate(Arrays.asList(statusKeyWords));
+ this.tagPredicate = new PersonTagContainsKeywordsPredicate(Arrays.asList(tagKeyWords));
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return namePredicate.test(person)
+ && phonePredicate.test(person)
+ && emailPredicate.test(person)
+ && lastContactTimePredicate.test(person)
+ && statusPredicate.test(person)
+ && tagPredicate.test(person);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof GeneralPersonPredicate)) {
+ return false;
+ }
+
+ GeneralPersonPredicate otherGeneralPersonPredicate = (GeneralPersonPredicate) other;
+ return namePredicate.equals(otherGeneralPersonPredicate.namePredicate)
+ && phonePredicate.equals(otherGeneralPersonPredicate.phonePredicate)
+ && emailPredicate.equals(otherGeneralPersonPredicate.emailPredicate)
+ && lastContactTimePredicate.equals(otherGeneralPersonPredicate.lastContactTimePredicate)
+ && statusPredicate.equals(otherGeneralPersonPredicate.statusPredicate)
+ && tagPredicate.equals(otherGeneralPersonPredicate.tagPredicate);
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/LastContactTimeContainsPredicate.java b/src/main/java/seedu/address/model/person/LastContactTimeContainsPredicate.java
new file mode 100644
index 00000000000..e8c8d958bbd
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/LastContactTimeContainsPredicate.java
@@ -0,0 +1,54 @@
+package seedu.address.model.person;
+
+import static seedu.address.logic.parser.ParserUtil.FORMAT;
+
+import java.time.LocalDateTime;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code LastContactedTime} matches the given time.
+ */
+public class LastContactTimeContainsPredicate implements Predicate {
+ private final LocalDateTime time;
+
+ /**
+ * Constructs a predicate with the given time.
+ * @param time time to be checked.
+ */
+ public LastContactTimeContainsPredicate(LocalDateTime time) {
+ this.time = time;
+ this.time.format(FORMAT);
+ LastContactedTime.isValidLastContactedTime(time);
+ }
+
+ @Override
+ public boolean test(Person person) {
+ if (time.equals(LocalDateTime.MIN)) {
+ return true;
+ }
+ return person.getLastContactedTime().equals(time);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof LastContactTimeContainsPredicate)) {
+ return false;
+ }
+
+ LastContactTimeContainsPredicate otherLastContactTimeContainsPredicate =
+ (LastContactTimeContainsPredicate) other;
+ return this.time.equals(otherLastContactTimeContainsPredicate.time);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("time", time).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/LastContactedTime.java b/src/main/java/seedu/address/model/person/LastContactedTime.java
index 5f2c9f4f7cd..cccd4273b12 100644
--- a/src/main/java/seedu/address/model/person/LastContactedTime.java
+++ b/src/main/java/seedu/address/model/person/LastContactedTime.java
@@ -40,10 +40,8 @@ public static String toDisplayFormat(LastContactedTime dateTime) {
* Returns true if a given LocalDateTime input is valid.
*/
public static boolean isValidLastContactedTime(LocalDateTime input) {
- if (input == null) {
- return false;
- }
- return true;
+ return input.isEqual(LocalDateTime.MIN)
+ || input.isAfter(LocalDateTime.MIN) && input.isBefore(LocalDateTime.MAX);
}
@Override
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
index 62d19be2977..a7775f9a3be 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
@@ -19,7 +19,8 @@ public NameContainsKeywordsPredicate(List keywords) {
@Override
public boolean test(Person person) {
return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ .anyMatch(keyword -> keyword.isEmpty()
+ || StringUtil.containsWordIgnoreCase(person.getName().toString(), keyword));
}
@Override
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index 8267c6dd1af..4681118138e 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -33,7 +33,7 @@ public class Person {
*/
public Person(Name name, Phone phone, Email email, LocalDateTime time, Status status, Remark remark,
Set tags) {
- requireAllNonNull(name, phone, email, status, remark, tags);
+ requireAllNonNull(name, phone, email, time, status, remark, tags);
this.name = name;
this.phone = phone;
this.email = email;
diff --git a/src/main/java/seedu/address/model/person/PersonTagContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/PersonTagContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..9127aa2e7e7
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonTagContainsKeywordsPredicate.java
@@ -0,0 +1,46 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.StringUtil;
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Tag} matches any of the keywords given.
+ */
+public class PersonTagContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public PersonTagContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return keywords.stream()
+ .anyMatch(keyword -> keyword.isEmpty() || person.getTags().stream()
+ .anyMatch(tag -> StringUtil.containsWordIgnoreCase(tag.tagName, keyword)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PersonTagContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ PersonTagContainsKeywordsPredicate otherTagContainsKeywordsPredicate =
+ (PersonTagContainsKeywordsPredicate) other;
+ return keywords.equals(otherTagContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PhoneContainsPredicate.java b/src/main/java/seedu/address/model/person/PhoneContainsPredicate.java
new file mode 100644
index 00000000000..34d66a69ae2
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PhoneContainsPredicate.java
@@ -0,0 +1,44 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Phone} matches any of the values given.
+ */
+public class PhoneContainsPredicate implements Predicate {
+ private final List values;
+
+ public PhoneContainsPredicate(List values) {
+ this.values = values;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return values.stream()
+ .anyMatch(value -> value.isEmpty()
+ || person.getPhone().toString().contains(value));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PhoneContainsPredicate)) {
+ return false;
+ }
+
+ PhoneContainsPredicate otherPhoneContainsPredicate = (PhoneContainsPredicate) other;
+ return values.equals(otherPhoneContainsPredicate.values);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("values", values).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/StatusContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/StatusContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..cf6c7499e2f
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/StatusContainsKeywordsPredicate.java
@@ -0,0 +1,46 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.StringUtil;
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Status} duration within the given start and end.
+ */
+public class StatusContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public StatusContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return keywords.stream()
+ .anyMatch(keyword -> keyword.isEmpty()
+ || StringUtil.containsWordIgnoreCase(person.getStatus().toString(), keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof StatusContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ StatusContainsKeywordsPredicate otherStatusContainsKeywordsPredicate = (StatusContainsKeywordsPredicate) other;
+ return keywords.equals(otherStatusContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index c7dcad41e27..b7410a80be0 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -39,6 +39,8 @@ public class PersonCard extends UiPart {
@FXML
private Label email;
@FXML
+ private Label status;
+ @FXML
private Label lastContactedTime;
@FXML
private FlowPane tags;
@@ -54,7 +56,10 @@ public PersonCard(Person person, int displayedIndex) {
phone.setText(person.getPhone().value);
email.setText(person.getEmail().value);
LocalDateTime time = person.getLastContactedTime();
- lastContactedTime.setText(time.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HHmm")));
+ lastContactedTime.setText(time.isEqual(LocalDateTime.MIN)
+ ? "Not contacted yet"
+ : time.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HHmm")));
+ status.setText(person.getStatus().value);
person.getTags().stream()
.sorted(Comparator.comparing(tag -> tag.tagName))
.forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index b2bc9a2bca6..e35618c2c2d 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -132,6 +132,15 @@
-fx-text-fill: #010504;
}
+.cell_status_label {
+ -fx-text-fill: white;
+ -fx-background-color: #70798c;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 11;
+}
+
.stack-pane {
-fx-background-color: derive(#1d1d1d, 20%);
}
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index 5c4cb11a5f0..948411f6ea5 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -29,6 +29,7 @@
+
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index b8b7dbba91a..312a46ad551 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -5,20 +5,36 @@
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.logic.parser.ParserUtil.FORMAT;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
import static seedu.address.testutil.TypicalPersons.CARL;
+import static seedu.address.testutil.TypicalPersons.DANIEL;
import static seedu.address.testutil.TypicalPersons.ELLE;
import static seedu.address.testutil.TypicalPersons.FIONA;
+import static seedu.address.testutil.TypicalPersons.GEORGE;
+import static seedu.address.testutil.TypicalPersons.HOON;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
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.EmailContainsKeywordsPredicate;
+import seedu.address.model.person.GeneralPersonPredicate;
+import seedu.address.model.person.LastContactTimeContainsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.PersonTagContainsKeywordsPredicate;
+import seedu.address.model.person.PhoneContainsPredicate;
+import seedu.address.model.person.StatusContainsKeywordsPredicate;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
@@ -26,13 +42,32 @@
public class FindCommandTest {
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private LocalDateTime emptyDateTime = LocalDateTime.MIN;
+ private LocalDateTime lastContacted =
+ LocalDateTime.of(LocalDate.of(0001, 01, 01), LocalTime.of(00, 00));
+ private LocalDateTime lastContacted2 =
+ LocalDateTime.of(LocalDate.of(0001, 01, 30), LocalTime.of(12, 00));
@Test
public void equals() {
- NameContainsKeywordsPredicate firstPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("first"));
- NameContainsKeywordsPredicate secondPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("second"));
+ GeneralPersonPredicate firstPredicate =
+ new GeneralPersonPredicate(
+ new NameContainsKeywordsPredicate(Collections.singletonList("first")),
+ new PhoneContainsPredicate(List.of("")),
+ new EmailContainsKeywordsPredicate(List.of("")),
+ new LastContactTimeContainsPredicate(lastContacted),
+ new StatusContainsKeywordsPredicate(List.of("")),
+ new PersonTagContainsKeywordsPredicate(List.of(""))
+ );
+ GeneralPersonPredicate secondPredicate =
+ new GeneralPersonPredicate(
+ new NameContainsKeywordsPredicate(Collections.singletonList("second")),
+ new PhoneContainsPredicate(List.of("")),
+ new EmailContainsKeywordsPredicate(List.of("")),
+ new LastContactTimeContainsPredicate(lastContacted2),
+ new StatusContainsKeywordsPredicate(List.of("")),
+ new PersonTagContainsKeywordsPredicate(List.of(""))
+ );
FindCommand findFirstCommand = new FindCommand(firstPredicate);
FindCommand findSecondCommand = new FindCommand(secondPredicate);
@@ -55,19 +90,64 @@ public void equals() {
}
@Test
- public void execute_zeroKeywords_noPersonFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
- NameContainsKeywordsPredicate predicate = preparePredicate(" ");
+ public void execute_zeroKeywords_allPersonFound() {
+ int expectedNumber = model.getFilteredPersonList().size();
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, expectedNumber);
+ GeneralPersonPredicate predicate = preparePredicate(new String[]{"", "", "", "", ""}, emptyDateTime);
FindCommand command = new FindCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ assertEquals(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE, HOON),
+ model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_oneNameKeyword_onePersonFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1);
+ GeneralPersonPredicate namePredicate = preparePredicate(new String[]{"ALICE", "", "", "", ""}, emptyDateTime);
+ FindCommand findNameCommand = new FindCommand(namePredicate);
+ expectedModel.updateFilteredPersonList(namePredicate);
+ assertCommandSuccess(findNameCommand, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_onePhoneKeyword_onePersonFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1);
+ GeneralPersonPredicate phonePredicate = preparePredicate(new String[]{"", "512", "", "", ""}, emptyDateTime);
+ FindCommand findPhoneCommand = new FindCommand(phonePredicate);
+ expectedModel.updateFilteredPersonList(phonePredicate);
+ assertCommandSuccess(findPhoneCommand, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_oneLastContactKeyword_onePersonFound() {
+ LocalDateTime time = LocalDateTime.parse("20.10.2023 1100", FORMAT);
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1);
+ GeneralPersonPredicate phonePredicate = preparePredicate(new String[]{"", "", "", "", ""}, time);
+ FindCommand findPhoneCommand = new FindCommand(phonePredicate);
+ expectedModel.updateFilteredPersonList(phonePredicate);
+ assertCommandSuccess(findPhoneCommand, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_oneKeyword_multiplePersonFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2);
+ GeneralPersonPredicate predicate =
+ preparePredicate(new String[]{"Alice Benson", "", "", "", ""}, emptyDateTime);
+ FindCommand command = new FindCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON), model.getFilteredPersonList());
}
@Test
public void execute_multipleKeywords_multiplePersonsFound() {
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
- NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
+ GeneralPersonPredicate predicate =
+ preparePredicate(new String[]{"Kurz Elle Kunz", "", "", "", ""}, emptyDateTime);
FindCommand command = new FindCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
@@ -76,7 +156,14 @@ public void execute_multipleKeywords_multiplePersonsFound() {
@Test
public void toStringMethod() {
- NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
+ GeneralPersonPredicate predicate = new GeneralPersonPredicate(
+ new NameContainsKeywordsPredicate(List.of("keyword")),
+ new PhoneContainsPredicate(List.of("0")),
+ new EmailContainsKeywordsPredicate(List.of("keyword")),
+ new LastContactTimeContainsPredicate(lastContacted),
+ new StatusContainsKeywordsPredicate(List.of("keyword")),
+ new PersonTagContainsKeywordsPredicate(List.of("keyword"))
+ );
FindCommand findCommand = new FindCommand(predicate);
String expected = FindCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
assertEquals(expected, findCommand.toString());
@@ -85,7 +172,14 @@ public void toStringMethod() {
/**
* Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
*/
- private NameContainsKeywordsPredicate preparePredicate(String userInput) {
- return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
+ private GeneralPersonPredicate preparePredicate(String[] userInput, LocalDateTime lastContacted) {
+ return new GeneralPersonPredicate(
+ new NameContainsKeywordsPredicate(List.of(userInput[0].split("\\s+"))),
+ new PhoneContainsPredicate(List.of(userInput[1].split("\\s+"))),
+ new EmailContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
+ new LastContactTimeContainsPredicate(lastContacted),
+ new StatusContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))),
+ new PersonTagContainsKeywordsPredicate(List.of(userInput[4].split("\\s+")))
+ );
}
}
diff --git a/src/test/java/seedu/address/logic/commands/FindMeetingCommandTest.java b/src/test/java/seedu/address/logic/commands/FindMeetingCommandTest.java
index e2ab4071dd0..fc260150d42 100644
--- a/src/test/java/seedu/address/logic/commands/FindMeetingCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindMeetingCommandTest.java
@@ -24,13 +24,13 @@
import seedu.address.model.meeting.AttendeeContainsKeywordsPredicate;
import seedu.address.model.meeting.GeneralMeetingPredicate;
import seedu.address.model.meeting.LocationContainsKeywordsPredicate;
+import seedu.address.model.meeting.MeetingTagContainsKeywordsPredicate;
import seedu.address.model.meeting.MeetingTimeContainsPredicate;
import seedu.address.model.meeting.TitleContainsKeywordsPredicate;
-import seedu.address.model.tag.TagContainsKeywordsPredicate;
import seedu.address.testutil.TypicalMeetings;
/**
- * Contains integration tests (interaction with the Model) for {@code FindCommand}.
+ * Contains integration tests (interaction with the Model) for {@code FindMeetingCommand}.
*/
public class FindMeetingCommandTest {
private Model model = new ModelManager(TypicalMeetings.getTypicalAddressBook(), new UserPrefs());
@@ -47,13 +47,13 @@ public void equals() {
new LocationContainsKeywordsPredicate(List.of("")),
new MeetingTimeContainsPredicate(start, end),
new AttendeeContainsKeywordsPredicate(List.of("")),
- new TagContainsKeywordsPredicate(List.of("")));
+ new MeetingTagContainsKeywordsPredicate(List.of("")));
GeneralMeetingPredicate secondPredicate =
new GeneralMeetingPredicate(new TitleContainsKeywordsPredicate(List.of("")),
new LocationContainsKeywordsPredicate(List.of("")),
new MeetingTimeContainsPredicate(start2, end),
new AttendeeContainsKeywordsPredicate(List.of("")),
- new TagContainsKeywordsPredicate(List.of("")));
+ new MeetingTagContainsKeywordsPredicate(List.of("")));
FindMeetingCommand filterFirstCommand = new FindMeetingCommand(firstPredicate);
FindMeetingCommand filterSecondCommand = new FindMeetingCommand(secondPredicate);
@@ -203,7 +203,7 @@ public void toStringMethod() {
new LocationContainsKeywordsPredicate(List.of("Keywords")),
new MeetingTimeContainsPredicate(start, end),
new AttendeeContainsKeywordsPredicate(List.of("Keywords")),
- new TagContainsKeywordsPredicate(List.of("Keywords")));
+ new MeetingTagContainsKeywordsPredicate(List.of("Keywords")));
FindMeetingCommand findMeetingCommand = new FindMeetingCommand(predicate);
String expected = FindMeetingCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
assertEquals(expected, findMeetingCommand.toString());
@@ -217,6 +217,6 @@ private GeneralMeetingPredicate preparePredicate(String[] userInput, LocalDateTi
new LocationContainsKeywordsPredicate(List.of(userInput[1].split("\\s+"))),
new MeetingTimeContainsPredicate(start, end),
new AttendeeContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
- new TagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
+ new MeetingTagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
index cdda0b01987..4c36159afba 100644
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
@@ -10,9 +10,7 @@
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import java.time.LocalDateTime;
-import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
@@ -38,11 +36,17 @@
import seedu.address.model.meeting.GeneralMeetingPredicate;
import seedu.address.model.meeting.LocationContainsKeywordsPredicate;
import seedu.address.model.meeting.Meeting;
+import seedu.address.model.meeting.MeetingTagContainsKeywordsPredicate;
import seedu.address.model.meeting.MeetingTimeContainsPredicate;
import seedu.address.model.meeting.TitleContainsKeywordsPredicate;
+import seedu.address.model.person.EmailContainsKeywordsPredicate;
+import seedu.address.model.person.GeneralPersonPredicate;
+import seedu.address.model.person.LastContactTimeContainsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;
import seedu.address.model.person.Person;
-import seedu.address.model.tag.TagContainsKeywordsPredicate;
+import seedu.address.model.person.PersonTagContainsKeywordsPredicate;
+import seedu.address.model.person.PhoneContainsPredicate;
+import seedu.address.model.person.StatusContainsKeywordsPredicate;
import seedu.address.testutil.EditMeetingDescriptorBuilder;
import seedu.address.testutil.EditPersonDescriptorBuilder;
import seedu.address.testutil.MeetingBuilder;
@@ -108,22 +112,24 @@ public void parseCommand_exit() throws Exception {
}
@Test
- public void parseCommand_find() throws Exception {
- List keywords = Arrays.asList("foo", "bar", "baz");
+ public void parseCommand_findc() throws Exception {
+ LocalDateTime lastContacted = LocalDateTime.parse("20.09.2023 1000", FORMAT);
FindCommand command = (FindCommand) parser
- .parseCommand(FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
- assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
+ .parseCommand(FindCommand.COMMAND_WORD + " n/Alice p/913 e/gmail l/20.09.2023 1000 s/Active t/friend");
+ assertEquals(new FindCommand(
+ preparePersonPredicate(new String[]{"Alice", "913", "gmail", "Active", "friend"}, lastContacted)),
+ command);
}
@Test
- public void parseCommand_filterm() throws Exception {
+ public void parseCommand_findm() throws Exception {
LocalDateTime start = LocalDateTime.parse("20.09.2023 1000", FORMAT);
LocalDateTime end = LocalDateTime.parse("20.09.2023 1200", FORMAT);
FindMeetingCommand command = (FindMeetingCommand) parser
- .parseCommand(seedu.address.logic.commands.FindMeetingCommand.COMMAND_WORD
+ .parseCommand(FindMeetingCommand.COMMAND_WORD
+ " m/CS2103T a/Zoom s/20.09.2023 1000 e/20.09.2023 1200 n/Alice Bob t/friend");
- assertEquals(new FindMeetingCommand(preparePredicate(new String[] {"CS2103T", "Zoom", "Alice Bob", "friend"},
- start, end)),
+ assertEquals(new FindMeetingCommand(
+ prepareMeetingPredicate(new String[] {"CS2103T", "Zoom", "Alice Bob", "friend"}, start, end)),
command);
}
@@ -173,13 +179,28 @@ public void parseCommand_unknownCommand_throwsParseException() {
}
/**
- * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
+ * Parses {@code userInput} into a {@code GeneralMeetingPredicate}.
*/
- private GeneralMeetingPredicate preparePredicate(String[] userInput, LocalDateTime start, LocalDateTime end) {
+ private GeneralMeetingPredicate prepareMeetingPredicate(String[] userInput,
+ LocalDateTime start, LocalDateTime end) {
return new GeneralMeetingPredicate(new TitleContainsKeywordsPredicate(List.of(userInput[0].split("\\s+"))),
new LocationContainsKeywordsPredicate(List.of(userInput[1].split("\\s+"))),
new MeetingTimeContainsPredicate(start, end),
new AttendeeContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
- new TagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
+ new MeetingTagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code GeneralPersonPredicate}.
+ */
+ private GeneralPersonPredicate preparePersonPredicate(String[] userInput, LocalDateTime lastContacted) {
+ return new GeneralPersonPredicate(
+ new NameContainsKeywordsPredicate(List.of(userInput[0].split("\\s+"))),
+ new PhoneContainsPredicate(List.of(userInput[1].split("\\s+"))),
+ new EmailContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
+ new LastContactTimeContainsPredicate(lastContacted),
+ new StatusContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))),
+ new PersonTagContainsKeywordsPredicate(List.of(userInput[4].split("\\s+")))
+ );
}
}
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
index d92e64d12f9..0ba37968e03 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
@@ -3,32 +3,96 @@
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 static seedu.address.logic.parser.ParserUtil.FORMAT;
-import java.util.Arrays;
+import java.time.LocalDateTime;
+import java.util.List;
import org.junit.jupiter.api.Test;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.model.person.EmailContainsKeywordsPredicate;
+import seedu.address.model.person.GeneralPersonPredicate;
+import seedu.address.model.person.LastContactTimeContainsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.PersonTagContainsKeywordsPredicate;
+import seedu.address.model.person.PhoneContainsPredicate;
+import seedu.address.model.person.StatusContainsKeywordsPredicate;
public class FindCommandParserTest {
private FindCommandParser parser = new FindCommandParser();
+ private LocalDateTime lastContacted = LocalDateTime.MIN;
@Test
- public void parse_emptyArg_throwsParseException() {
- assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ public void parse_nonEmptyPreambleArg_throwsParseException() {
+ assertParseFailure(parser, " bobby n/Alice",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgsName_returnsFindCommand() {
+ FindCommand expectedFindCommand =
+ new FindCommand(preparePredicate(new String[]{"Alice", "", "", "", ""}, lastContacted));
+ assertParseSuccess(parser, " n/Alice", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsPhone_returnsFindCommand() {
+ FindCommand expectedFindCommand =
+ new FindCommand(preparePredicate(new String[]{"", "51", "", "", ""}, lastContacted));
+ assertParseSuccess(parser, " p/51", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsEmail_returnsFindCommand() {
+ FindCommand expectedFindCommand =
+ new FindCommand(preparePredicate(new String[]{"", "", "gmail.com", "", ""}, lastContacted));
+ assertParseSuccess(parser, " e/gmail.com", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsLastContacted_returnsFindCommand() {
+ LocalDateTime time = LocalDateTime.parse("20.09.2023 1000", FORMAT);
+ FindCommand expectedFindCommand =
+ new FindCommand(preparePredicate(new String[]{"", "", "", "", ""}, time));
+ assertParseSuccess(parser, " l/20.09.2023 1000", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsStatus_returnsFindCommand() {
+ FindCommand expectedFindCommand =
+ new FindCommand(preparePredicate(new String[]{"", "", "", "active", ""}, lastContacted));
+ assertParseSuccess(parser, " s/active", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsTag_returnsFindCommand() {
+ FindCommand expectedFindCommand =
+ new FindCommand(preparePredicate(new String[]{"", "", "", "", "friend important"}, lastContacted));
+ assertParseSuccess(parser, " t/friend important", expectedFindCommand);
}
@Test
public void parse_validArgs_returnsFindCommand() {
- // no leading and trailing whitespaces
+ LocalDateTime time = LocalDateTime.parse("20.09.2023 1000", FORMAT);
FindCommand expectedFindCommand =
- new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
- assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
+ new FindCommand(preparePredicate(new String[]{"Alice", "913", "gmail", "Active", "friend"}, time));
+ assertParseSuccess(parser, " n/Alice p/913 e/gmail l/20.09.2023 1000 s/Active t/friend", expectedFindCommand);
+ }
- // multiple whitespaces between keywords
- assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
+ /**
+ * Parses {@code userInput} into a {@code GeneralPersonPredicate}.
+ */
+ private GeneralPersonPredicate preparePredicate(String[] userInput, LocalDateTime lastContacted) {
+ return new GeneralPersonPredicate(
+ new NameContainsKeywordsPredicate(List.of(userInput[0].split("\\s+"))),
+ new PhoneContainsPredicate(List.of(userInput[1].split("\\s+"))),
+ new EmailContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
+ new LastContactTimeContainsPredicate(lastContacted),
+ new StatusContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))),
+ new PersonTagContainsKeywordsPredicate(List.of(userInput[4].split("\\s+")))
+ );
}
}
diff --git a/src/test/java/seedu/address/logic/parser/FindMeetingCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindMeetingCommandParserTest.java
index 99a9160bc36..057e0ee0b78 100644
--- a/src/test/java/seedu/address/logic/parser/FindMeetingCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindMeetingCommandParserTest.java
@@ -14,10 +14,10 @@
import seedu.address.model.meeting.AttendeeContainsKeywordsPredicate;
import seedu.address.model.meeting.GeneralMeetingPredicate;
import seedu.address.model.meeting.LocationContainsKeywordsPredicate;
+import seedu.address.model.meeting.MeetingTagContainsKeywordsPredicate;
import seedu.address.model.meeting.MeetingTime;
import seedu.address.model.meeting.MeetingTimeContainsPredicate;
import seedu.address.model.meeting.TitleContainsKeywordsPredicate;
-import seedu.address.model.tag.TagContainsKeywordsPredicate;
public class FindMeetingCommandParserTest {
@@ -97,6 +97,6 @@ private GeneralMeetingPredicate preparePredicate(String[] userInput, LocalDateTi
new LocationContainsKeywordsPredicate(List.of(userInput[1].split("\\s+"))),
new MeetingTimeContainsPredicate(start, end),
new AttendeeContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
- new TagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
+ new MeetingTagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
}
}
diff --git a/src/test/java/seedu/address/model/meeting/GeneralMeetingPredicateTest.java b/src/test/java/seedu/address/model/meeting/GeneralMeetingPredicateTest.java
index 14d988790f9..ff30b765b72 100644
--- a/src/test/java/seedu/address/model/meeting/GeneralMeetingPredicateTest.java
+++ b/src/test/java/seedu/address/model/meeting/GeneralMeetingPredicateTest.java
@@ -10,7 +10,6 @@
import org.junit.jupiter.api.Test;
-import seedu.address.model.tag.TagContainsKeywordsPredicate;
import seedu.address.testutil.MeetingBuilder;
public class GeneralMeetingPredicateTest {
@@ -144,6 +143,6 @@ private GeneralMeetingPredicate preparePredicate(String[] userInput, LocalDateTi
new LocationContainsKeywordsPredicate(List.of(userInput[1].split("\\s+"))),
new MeetingTimeContainsPredicate(start, end),
new AttendeeContainsKeywordsPredicate(List.of(userInput[2].split("\\s+"))),
- new TagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
+ new MeetingTagContainsKeywordsPredicate(List.of(userInput[3].split("\\s+"))));
}
}
diff --git a/src/test/java/seedu/address/model/meeting/TagContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/meeting/MeetingTagContainsKeywordsPredicateTest.java
similarity index 59%
rename from src/test/java/seedu/address/model/meeting/TagContainsKeywordsPredicateTest.java
rename to src/test/java/seedu/address/model/meeting/MeetingTagContainsKeywordsPredicateTest.java
index a8b25ffd5ce..7e653e6181a 100644
--- a/src/test/java/seedu/address/model/meeting/TagContainsKeywordsPredicateTest.java
+++ b/src/test/java/seedu/address/model/meeting/MeetingTagContainsKeywordsPredicateTest.java
@@ -10,24 +10,26 @@
import org.junit.jupiter.api.Test;
-import seedu.address.model.tag.TagContainsKeywordsPredicate;
import seedu.address.testutil.MeetingBuilder;
-public class TagContainsKeywordsPredicateTest {
+public class MeetingTagContainsKeywordsPredicateTest {
@Test
public void equals() {
List firstPredicateKeywordList = Collections.singletonList("first");
List secondPredicateKeywordList = Arrays.asList("first", "second");
- TagContainsKeywordsPredicate firstPredicate = new TagContainsKeywordsPredicate(firstPredicateKeywordList);
- TagContainsKeywordsPredicate secondPredicate = new TagContainsKeywordsPredicate(secondPredicateKeywordList);
+ MeetingTagContainsKeywordsPredicate firstPredicate =
+ new MeetingTagContainsKeywordsPredicate(firstPredicateKeywordList);
+ MeetingTagContainsKeywordsPredicate secondPredicate =
+ new MeetingTagContainsKeywordsPredicate(secondPredicateKeywordList);
// same object -> returns true
assertTrue(firstPredicate.equals(firstPredicate));
// same values -> returns true
- TagContainsKeywordsPredicate firstPredicateCopy = new TagContainsKeywordsPredicate(firstPredicateKeywordList);
+ MeetingTagContainsKeywordsPredicate firstPredicateCopy =
+ new MeetingTagContainsKeywordsPredicate(firstPredicateKeywordList);
assertTrue(firstPredicate.equals(firstPredicateCopy));
// different types -> returns false
@@ -43,35 +45,37 @@ public void equals() {
@Test
public void test_locationContainsKeywords_returnsTrue() {
// One keyword
- TagContainsKeywordsPredicate predicate =
- new TagContainsKeywordsPredicate(Collections.singletonList("CS2103T"));
+ MeetingTagContainsKeywordsPredicate predicate =
+ new MeetingTagContainsKeywordsPredicate(Collections.singletonList("CS2103T"));
assertTrue(predicate.test(new MeetingBuilder().withTags("CS2103T").build()));
// Multiple keywords
- predicate = new TagContainsKeywordsPredicate(Arrays.asList("CS2103T", "meeting"));
+ predicate = new MeetingTagContainsKeywordsPredicate(Arrays.asList("CS2103T", "meeting"));
assertTrue(predicate.test(new MeetingBuilder().withTags("CS2103T", "meeting").build()));
// Only one matching keyword
- predicate = new TagContainsKeywordsPredicate(Arrays.asList("CS2013T", "meeting"));
+ predicate = new MeetingTagContainsKeywordsPredicate(Arrays.asList("CS2013T", "meeting"));
assertTrue(predicate.test(new MeetingBuilder().withTags("ABCDE", "meeting").build()));
// Mixed-case keywords
- predicate = new TagContainsKeywordsPredicate(Arrays.asList("CS2103T", "meeting"));
+ predicate = new MeetingTagContainsKeywordsPredicate(Arrays.asList("CS2103T", "meeting"));
assertTrue(predicate.test(new MeetingBuilder().withTags("cs2103t", "MEETING").build()));
}
@Test
public void test_locationDoesNotContainKeywords_returnsFalse() {
// Zero keywords
- TagContainsKeywordsPredicate predicate = new TagContainsKeywordsPredicate(Collections.emptyList());
+ MeetingTagContainsKeywordsPredicate predicate =
+ new MeetingTagContainsKeywordsPredicate(Collections.emptyList());
assertFalse(predicate.test(new MeetingBuilder().withTags("Alice").build()));
// Non-matching keyword
- predicate = new TagContainsKeywordsPredicate(Arrays.asList("Carol"));
+ predicate = new MeetingTagContainsKeywordsPredicate(Arrays.asList("Carol"));
assertFalse(predicate.test(new MeetingBuilder().withTags("Alice", "Bob").build()));
// Keywords match others
- predicate = new TagContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
+ predicate =
+ new MeetingTagContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
assertFalse(predicate.test(new MeetingBuilder().withTags("Alice")
.build()));
}
@@ -79,9 +83,9 @@ public void test_locationDoesNotContainKeywords_returnsFalse() {
@Test
public void toStringMethod() {
List keywords = List.of("keyword1", "keyword2");
- TagContainsKeywordsPredicate predicate = new TagContainsKeywordsPredicate(keywords);
+ MeetingTagContainsKeywordsPredicate predicate = new MeetingTagContainsKeywordsPredicate(keywords);
- String expected = TagContainsKeywordsPredicate.class.getCanonicalName() + "{keywords=" + keywords + "}";
+ String expected = MeetingTagContainsKeywordsPredicate.class.getCanonicalName() + "{keywords=" + keywords + "}";
assertEquals(expected, predicate.toString());
}
}
diff --git a/src/test/java/seedu/address/model/person/EmailContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/EmailContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..ea597885e52
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/EmailContainsKeywordsPredicateTest.java
@@ -0,0 +1,90 @@
+package seedu.address.model.person;
+
+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 java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+public class EmailContainsKeywordsPredicateTest {
+ @Test
+ public void equals() {
+ List firstPredicateKeywordList = Collections.singletonList("first");
+ List secondPredicateKeywordList = Arrays.asList("first", "second");
+
+ EmailContainsKeywordsPredicate firstPredicate = new EmailContainsKeywordsPredicate(firstPredicateKeywordList);
+ EmailContainsKeywordsPredicate secondPredicate = new EmailContainsKeywordsPredicate(secondPredicateKeywordList);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ EmailContainsKeywordsPredicate firstPredicateCopy =
+ new EmailContainsKeywordsPredicate(firstPredicateKeywordList);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_emailContainsKeywords_returnsTrue() {
+ // One keyword
+ EmailContainsKeywordsPredicate predicate =
+ new EmailContainsKeywordsPredicate(Collections.singletonList("gmail"));
+ assertTrue(predicate.test(new PersonBuilder().withEmail("alice@gmail.com").build()));
+
+ // Multiple keywords
+ predicate = new EmailContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"));
+ assertTrue(predicate.test(new PersonBuilder().withEmail("bob@gmail.com").build()));
+
+ // Only one matching keyword
+ predicate = new EmailContainsKeywordsPredicate(Arrays.asList("Bob", "Carol"));
+ assertTrue(predicate.test(new PersonBuilder().withEmail("bob@gmail.com").build()));
+
+ // Mixed-case keywords
+ predicate = new EmailContainsKeywordsPredicate(Arrays.asList("aLIce", "bOB"));
+ assertTrue(predicate.test(new PersonBuilder().withEmail("alice@gmail.com").build()));
+
+ // Special characters
+ predicate = new EmailContainsKeywordsPredicate(Arrays.asList("_"));
+ assertTrue(predicate.test(new PersonBuilder().withEmail("alice_bob@gmail.com").build()));
+ }
+
+ @Test
+ public void test_emailDoesNotContainKeywords_returnsFalse() {
+ // Zero keywords
+ EmailContainsKeywordsPredicate predicate = new EmailContainsKeywordsPredicate(Collections.emptyList());
+ assertFalse(predicate.test(new PersonBuilder().withEmail("alice@gmail.com").build()));
+
+ // Non-matching keyword
+ predicate = new EmailContainsKeywordsPredicate(Arrays.asList("Carol"));
+ assertFalse(predicate.test(new PersonBuilder().withEmail("alice@gmail.com").build()));
+
+ // Keywords match name and phone, but does not match email
+ predicate = new EmailContainsKeywordsPredicate(Arrays.asList("Alice", "12345", "alice@hotmail.com"));
+ assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
+ .withEmail("alicce@email.com").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ List keywords = List.of("keyword1", "keyword2");
+ EmailContainsKeywordsPredicate predicate = new EmailContainsKeywordsPredicate(keywords);
+
+ String expected = EmailContainsKeywordsPredicate.class.getCanonicalName() + "{keywords=" + keywords + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/LastContactTimeContainsPredicateTest.java b/src/test/java/seedu/address/model/person/LastContactTimeContainsPredicateTest.java
new file mode 100644
index 00000000000..0fed54ebef3
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/LastContactTimeContainsPredicateTest.java
@@ -0,0 +1,64 @@
+package seedu.address.model.person;
+
+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.logic.parser.ParserUtil.FORMAT;
+
+import java.time.LocalDateTime;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+public class LastContactTimeContainsPredicateTest {
+ private LocalDateTime time1 = LocalDateTime.parse("10.09.2023 1000", FORMAT);
+ private LocalDateTime time2 = LocalDateTime.parse("11.09.2023 1000", FORMAT);
+
+ @Test
+ public void equals() {
+ LastContactTimeContainsPredicate firstPredicate = new LastContactTimeContainsPredicate(time1);
+ LastContactTimeContainsPredicate secondPredicate = new LastContactTimeContainsPredicate(time2);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ LastContactTimeContainsPredicate firstPredicateCopy = new LastContactTimeContainsPredicate(time1);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_lastContactTimeMatches_returnsTrue() {
+ LastContactTimeContainsPredicate predicate =
+ new LastContactTimeContainsPredicate(time1);
+ assertTrue(predicate.test(new PersonBuilder()
+ .withLastContactedTime("10.09.2023 1000").build()));
+ }
+
+ @Test
+ public void test_lastContactTimeDoesNotMatch_returnsFalse() {
+ LastContactTimeContainsPredicate predicate =
+ new LastContactTimeContainsPredicate(time2);
+ assertFalse(predicate.test(new PersonBuilder()
+ .withLastContactedTime("10.09.2023 1000").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ LastContactTimeContainsPredicate predicate = new LastContactTimeContainsPredicate(time1);
+
+ String expected = LastContactTimeContainsPredicate.class.getCanonicalName()
+ + "{time=" + time1 + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/LastContactedTimeTest.java b/src/test/java/seedu/address/model/person/LastContactedTimeTest.java
index 923113f3cb8..12ca934a5c6 100644
--- a/src/test/java/seedu/address/model/person/LastContactedTimeTest.java
+++ b/src/test/java/seedu/address/model/person/LastContactedTimeTest.java
@@ -20,8 +20,8 @@ public void constructor_null_throwsNullPointerException() {
@Test
public void isValidLastContactedTime() {
- // null and invalid
- assertFalse(LastContactedTime.isValidLastContactedTime(null));
+ // default value
+ assertTrue(LastContactedTime.isValidLastContactedTime(LocalDateTime.MIN));
// valid
assertTrue(LastContactedTime.isValidLastContactedTime(LocalDateTime.parse("02.10.2023 1000", FORMAT)));
diff --git a/src/test/java/seedu/address/model/person/PersonTagContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/PersonTagContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..0629fcff07a
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonTagContainsKeywordsPredicateTest.java
@@ -0,0 +1,89 @@
+package seedu.address.model.person;
+
+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 java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+public class PersonTagContainsKeywordsPredicateTest {
+ @Test
+ public void equals() {
+ List firstPredicateKeywordList = Collections.singletonList("first");
+ List secondPredicateKeywordList = Arrays.asList("first", "second");
+
+ PersonTagContainsKeywordsPredicate firstPredicate =
+ new PersonTagContainsKeywordsPredicate(firstPredicateKeywordList);
+ PersonTagContainsKeywordsPredicate secondPredicate =
+ new PersonTagContainsKeywordsPredicate(secondPredicateKeywordList);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ PersonTagContainsKeywordsPredicate firstPredicateCopy =
+ new PersonTagContainsKeywordsPredicate(firstPredicateKeywordList);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_personTagContainsKeywords_returnsTrue() {
+ // One keyword
+ PersonTagContainsKeywordsPredicate predicate =
+ new PersonTagContainsKeywordsPredicate(Collections.singletonList("VIP"));
+ assertTrue(predicate.test(new PersonBuilder().withTags("VIP").build()));
+
+ // Multiple keywords
+ predicate = new PersonTagContainsKeywordsPredicate(Arrays.asList("VIP", "Family"));
+ assertTrue(predicate.test(new PersonBuilder().withTags("VIP", "Family").build()));
+
+ // Only one matching keyword
+ predicate = new PersonTagContainsKeywordsPredicate(Arrays.asList("VIP", "Family"));
+ assertTrue(predicate.test(new PersonBuilder().withTags("Friend", "VIP").build()));
+
+ // Mixed-case keywords
+ predicate = new PersonTagContainsKeywordsPredicate(Arrays.asList("vip", "Family"));
+ assertTrue(predicate.test(new PersonBuilder().withTags("VIP", "family").build()));
+ }
+
+ @Test
+ public void test_personTagDoesNotContainKeywords_returnsFalse() {
+ // Zero keywords
+ PersonTagContainsKeywordsPredicate predicate = new PersonTagContainsKeywordsPredicate(Collections.emptyList());
+ assertFalse(predicate.test(new PersonBuilder().withTags("VIP").build()));
+
+ // Non-matching keyword
+ predicate = new PersonTagContainsKeywordsPredicate(Arrays.asList("Friend"));
+ assertFalse(predicate.test(new PersonBuilder().withTags("VIP", "Family").build()));
+
+ // Keywords match others
+ predicate = new PersonTagContainsKeywordsPredicate(
+ Arrays.asList("Alice", "12345", "alice@email.com", "Renewal", "Friend"));
+ assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
+ .withEmail("alice@email.com").withStatus("Renewal").withTags("Family").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ List keywords = List.of("keyword1", "keyword2");
+ PersonTagContainsKeywordsPredicate predicate = new PersonTagContainsKeywordsPredicate(keywords);
+
+ String expected = PersonTagContainsKeywordsPredicate.class.getCanonicalName() + "{keywords=" + keywords + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PhoneContainsPredicateTest.java b/src/test/java/seedu/address/model/person/PhoneContainsPredicateTest.java
new file mode 100644
index 00000000000..72d972fba90
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PhoneContainsPredicateTest.java
@@ -0,0 +1,80 @@
+package seedu.address.model.person;
+
+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 java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+public class PhoneContainsPredicateTest {
+ @Test
+ public void equals() {
+ List firstPredicateValueList = Collections.singletonList("0");
+ List secondPredicateValueList = Arrays.asList("1", "9");
+
+ PhoneContainsPredicate firstPredicate = new PhoneContainsPredicate(firstPredicateValueList);
+ PhoneContainsPredicate secondPredicate = new PhoneContainsPredicate(secondPredicateValueList);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ PhoneContainsPredicate firstPredicateCopy = new PhoneContainsPredicate(firstPredicateValueList);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_phoneContainsValues_returnsTrue() {
+ // One keyword
+ PhoneContainsPredicate predicate = new PhoneContainsPredicate(Collections.singletonList("01"));
+ assertTrue(predicate.test(new PersonBuilder().withPhone("90199029").build()));
+
+ // Multiple keywords
+ predicate = new PhoneContainsPredicate(Arrays.asList("01", "02"));
+ assertTrue(predicate.test(new PersonBuilder().withPhone("90199029").build()));
+
+ // Only one matching keyword
+ predicate = new PhoneContainsPredicate(Arrays.asList("29", "55"));
+ assertTrue(predicate.test(new PersonBuilder().withPhone("90199029").build()));
+ }
+
+ @Test
+ public void test_phoneDoesNotContainValues_returnsFalse() {
+ // Zero keywords
+ PhoneContainsPredicate predicate = new PhoneContainsPredicate(Collections.emptyList());
+ assertFalse(predicate.test(new PersonBuilder().withPhone("90199029").build()));
+
+ // Non-matching keyword
+ predicate = new PhoneContainsPredicate(Arrays.asList("9o19"));
+ assertFalse(predicate.test(new PersonBuilder().withPhone("90199029").build()));
+
+ // Keywords match name and email, but does not match phone
+ predicate = new PhoneContainsPredicate(Arrays.asList("Alice", "123456", "alice@email.com"));
+ assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
+ .withEmail("alice@email.com").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ List values = List.of("123", "456");
+ PhoneContainsPredicate predicate = new PhoneContainsPredicate(values);
+
+ String expected = PhoneContainsPredicate.class.getCanonicalName() + "{values=" + values + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/StatusContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/StatusContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..b7b31305489
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/StatusContainsKeywordsPredicateTest.java
@@ -0,0 +1,84 @@
+package seedu.address.model.person;
+
+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 java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+public class StatusContainsKeywordsPredicateTest {
+ @Test
+ public void equals() {
+ List firstPredicateKeywordList = Collections.singletonList("first");
+ List secondPredicateKeywordList = Arrays.asList("first", "second");
+
+ StatusContainsKeywordsPredicate firstPredicate =
+ new StatusContainsKeywordsPredicate(firstPredicateKeywordList);
+ StatusContainsKeywordsPredicate secondPredicate =
+ new StatusContainsKeywordsPredicate(secondPredicateKeywordList);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ StatusContainsKeywordsPredicate firstPredicateCopy =
+ new StatusContainsKeywordsPredicate(firstPredicateKeywordList);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_statusContainsKeywords_returnsTrue() {
+ // One keyword
+ StatusContainsKeywordsPredicate predicate =
+ new StatusContainsKeywordsPredicate(Collections.singletonList("Active"));
+ assertTrue(predicate.test(new PersonBuilder().withStatus("Active").build()));
+
+ // Multiple keywords
+ predicate = new StatusContainsKeywordsPredicate(Arrays.asList("Active", "Prospective"));
+ assertTrue(predicate.test(new PersonBuilder().withStatus("Active").build()));
+
+ // Mixed-case keywords
+ predicate = new StatusContainsKeywordsPredicate(Arrays.asList("inAcTive"));
+ assertTrue(predicate.test(new PersonBuilder().withStatus("Inactive").build()));
+ }
+
+ @Test
+ public void test_nameDoesNotContainKeywords_returnsFalse() {
+ // Zero keywords
+ StatusContainsKeywordsPredicate predicate = new StatusContainsKeywordsPredicate(Collections.emptyList());
+ assertFalse(predicate.test(new PersonBuilder().withStatus("").build()));
+
+ // Non-matching keyword
+ predicate = new StatusContainsKeywordsPredicate(Arrays.asList("Actve"));
+ assertFalse(predicate.test(new PersonBuilder().withStatus("Active").build()));
+
+ // Keywords match name, phone and email, but does not match status
+ predicate = new StatusContainsKeywordsPredicate(Arrays.asList("Alice", "12345", "alice@email.com", "Claimant"));
+ assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
+ .withEmail("alice@email.com").withStatus("Renewal").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ List keywords = List.of("keyword1", "keyword2");
+ StatusContainsKeywordsPredicate predicate = new StatusContainsKeywordsPredicate(keywords);
+
+ String expected = StatusContainsKeywordsPredicate.class.getCanonicalName() + "{keywords=" + keywords + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}