diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 30b2a62503b..c7d8de0cd97 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -56,6 +56,15 @@ Name -[hidden]right-> Phone
Phone -[hidden]right-> Address
Address -[hidden]right-> Email
+Person "1" -- "0..*" Meeting
+
+' AddMeetingCommand Class and its relation to Meeting
+Class AddMeetingCommand {
+ +execute(): CommandResult
+}
+AddMeetingCommand ..> Meeting : creates
+
ModelManager --> "~* filtered" Person
ModelManager --> "~* filtered" Meeting
@enduml
+```
diff --git a/docs/team/zixuan.md b/docs/team/zixuan.md
index 333b62161d7..64a3402df8e 100644
--- a/docs/team/zixuan.md
+++ b/docs/team/zixuan.md
@@ -11,6 +11,10 @@ The user interacts with it using a CLI, and it has a GUI created with JavaFX. It
Given below are my contributions to the project.
* **New Feature**:
+ * Added the addMeeting command
+ * Edited Meeting Model class
+ * **Code contributed**:
+ * [RepoSense link](https://nus-cs2103-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=chewbum&tabRepo=AY2324S2-CS2103-F08-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
* **Project management**:
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index 935dd329da5..ce7c6b639d9 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -5,8 +5,10 @@
import java.util.stream.Stream;
import seedu.address.logic.parser.Prefix;
+import seedu.address.model.meeting.Meeting;
import seedu.address.model.person.Person;
+
/**
* Container for user visible messages.
*/
@@ -15,7 +17,7 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
- public static final String MESSAFE_MISSING_MEETING_IDENTIFIER = "Error: Please specify a meeting identifier";
+ public static final String MESSAGE_MISSING_MEETING_IDENTIFIER = "Error: Please specify a meeting identifier";
public static final String MESSAGE_INVALID_MEETING_DISPLAYED_INDEX = "Error: Meeting %1$d not found";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_DUPLICATE_FIELDS = "Multiple values specified for "
@@ -48,5 +50,18 @@ public static String format(Person person) {
person.getTags().forEach(builder::append);
return builder.toString();
}
+ /**
+ * Formats the {@code meeting} for display to the user.
+ */
+ public static String format(Meeting meeting) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Client: ")
+ .append(meeting.getClientName())
+ .append("DateTime: ")
+ .append(meeting.getDateTime())
+ .append("; Description: ")
+ .append(meeting.getDescription());
+ return builder.toString();
+ }
}
diff --git a/src/main/java/seedu/address/logic/commands/AddMeetingCommand.java b/src/main/java/seedu/address/logic/commands/AddMeetingCommand.java
new file mode 100644
index 00000000000..298b9260c91
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddMeetingCommand.java
@@ -0,0 +1,122 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.meeting.Meeting;
+import seedu.address.model.person.Person;
+
+/**
+ * Represents a command to add a meeting associated with a specific client in the address book.
+ * This command adds a new meeting to the address book, ensuring that no duplicate meetings are added.
+ * A meeting is considered a duplicate if it has the same client, date, and description as an existing meeting.
+ */
+public class AddMeetingCommand extends Command {
+ public static final String COMMAND_WORD = "addMeeting";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a meeting to the "
+ + "client identified by the index number. \n"
+ + "Parameters: client/ CLIENT_INDEX dt/ DATE_TIME /d DESCRIPTION \n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_CLIENT_INDEX + "1 "
+ + PREFIX_DATETIME + "02-01-2024 12:00 "
+ + PREFIX_DESCRIPTION + "sign life plan";
+
+
+ public static final String MESSAGE_SUCCESS = "New meeting added: %1$s";
+ public static final String MESSAGE_DUPLICATE_MEETING = "This meeting already exists in the address book";
+
+ private final Index clientIndex;
+ private final LocalDateTime dateTime;
+ private final String description;
+
+ /**
+ * Creates an {@code AddMeetingCommand} to add the specified {@code Meeting}.
+ *
+ * @param dateTime The date and time of the meeting.
+ * @param description A description of the meeting.
+ * @param clientIndex The index of the client in the filtered person list to whom the meeting is to be added.
+ * @throws NullPointerException if any of the input parameters are null.
+ */
+
+ public AddMeetingCommand(LocalDateTime dateTime, String description, Index clientIndex) {
+ if (dateTime == null || description == null || clientIndex == null) {
+ throw new NullPointerException();
+ }
+ this.dateTime = dateTime;
+ this.description = description;
+ this.clientIndex = clientIndex;
+ }
+
+ /**
+ * Executes the AddMeeting command to add a new meeting associated with a client in the address book.
+ *
+ * The method retrieves the client based on the index provided, creates a new meeting with the specified date, time,
+ * and description, and then adds this meeting to the model if it does not already exist to ensure uniqueness.
+ *
+ * If the specified client index is invalid or the meeting already exists, it throws a CommandException.
+ *
+ * @param model The model in which the meeting will be added.
+ * @return A CommandResult object containing the success message.
+ * @throws CommandException If the client index is invalid or the meeting already exists in the model.
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredPersonList();
+
+ if (clientIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person client = lastShownList.get(clientIndex.getZeroBased());
+ Meeting meetingToAdd = new Meeting(description, dateTime, client);
+
+ if (model.hasMeeting(meetingToAdd) && client.hasExistingMeeting(meetingToAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_MEETING);
+ }
+ model.addMeeting(meetingToAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(meetingToAdd)));
+ }
+
+ /**
+ * Checks if another object is equal to this AddMeetingCommand instance.
+ *
+ * The equality check is based on whether the other object is an instance of AddMeetingCommand
+ * and whether the meetings to be added are the same in terms of client, date, time, and description.
+ * This ensures that two AddMeetingCommand objects are considered equal if they are attempting
+ * to add the same meeting.
+ *
+ * This method is crucial for command comparisons, especially when testing or when the application
+ * logic requires comparing different commands.
+ *
+ * @param other The object to compare this AddMeetingCommand against.
+ * @return true if the given object represents an AddMeetingCommand equivalent to this instance, false otherwise.
+ */
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddMeetingCommand)) {
+ return false;
+ }
+
+ AddMeetingCommand otherCommand = (AddMeetingCommand) other;
+ return dateTime.equals(otherCommand.dateTime)
+ && description.equals(otherCommand.description)
+ && clientIndex.equals(otherCommand.clientIndex);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteMeetingCommand.java b/src/main/java/seedu/address/logic/commands/DeleteMeetingCommand.java
index fb24b6219fa..6815e66f78c 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteMeetingCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteMeetingCommand.java
@@ -18,7 +18,7 @@
*/
public class DeleteMeetingCommand extends Command {
- public static final String COMMAND_WORD = "delete meeting";
+ public static final String COMMAND_WORD = "deleteMeeting";
public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Deletes the meeting of a particular client identified by the "
diff --git a/src/main/java/seedu/address/logic/parser/AddMeetingCommandParser.java b/src/main/java/seedu/address/logic/parser/AddMeetingCommandParser.java
new file mode 100644
index 00000000000..de7df31fe15
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddMeetingCommandParser.java
@@ -0,0 +1,52 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+
+import java.time.LocalDateTime;
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddMeetingCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new AddMeetingCommand object
+ */
+public class AddMeetingCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddMeetingCommand
+ * and returns an AddMeetingCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddMeetingCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION);
+ System.out.println(!arePrefixesPresent(argMultimap, PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION));
+ System.out.println(!argMultimap.getPreamble().isEmpty());
+ if (!arePrefixesPresent(argMultimap, PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddMeetingCommand.MESSAGE_USAGE));
+ }
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION);
+ Index clientIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_CLIENT_INDEX).get());
+ LocalDateTime dateTime = ParserUtil.parseDateTime(argMultimap.getValue(PREFIX_DATETIME).get());
+ String description = ParserUtil.parseDescription(argMultimap.getValue(PREFIX_DESCRIPTION).get());
+
+
+ return new AddMeetingCommand(dateTime, description, clientIndex);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 274d3689e85..d0eb657f93f 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -9,6 +9,7 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddMeetingCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.DeleteCommand;
@@ -18,7 +19,6 @@
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.commands.ViewCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -30,8 +30,6 @@ public class AddressBookParser {
* Used for initial separation of command word and args.
*/
private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
- private static final Pattern MEETING_COMMAND_TWO_ARGS_FORMAT = Pattern
- .compile("(?\\S+\\s+\\S+)(?:\\s+(?\\d+))(?:\\s+(?\\d+))");
private static final Logger logger = LogsCenter.getLogger(AddressBookParser.class);
/**
@@ -42,69 +40,53 @@ public class AddressBookParser {
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput) throws ParseException {
- final Matcher basicCommandMatcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
- final Matcher meetingCommandTwoArgsMatcher = MEETING_COMMAND_TWO_ARGS_FORMAT.matcher(userInput.trim());
-
- if (basicCommandMatcher.matches()) {
- final String commandWord = basicCommandMatcher.group("commandWord");
- final String arguments = basicCommandMatcher.group("arguments");
-
- // Note to developers: Change the log level in config.json to enable lower level
- // (i.e., FINE, FINER and lower)
- // log messages such as the one below.
- // Lower level log messages are used sparingly to minimize noise in the code.
- logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);
-
- switch (commandWord) {
+ final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
+ if (!matcher.matches()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
- case AddCommand.COMMAND_WORD:
- return new AddCommandParser().parse(arguments);
+ final String commandWord = matcher.group("commandWord");
+ final String arguments = matcher.group("arguments");
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
+ // Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
+ // log messages such as the one below.
+ // Lower level log messages are used sparingly to minimize noise in the code.
+ logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
+ switch (commandWord) {
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
+ case AddCommand.COMMAND_WORD:
+ return new AddCommandParser().parse(arguments);
- case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(arguments);
+ case EditCommand.COMMAND_WORD:
+ return new EditCommandParser().parse(arguments);
- case ListCommand.COMMAND_WORD:
- return new ListCommand();
+ case DeleteCommand.COMMAND_WORD:
+ return new DeleteCommandParser().parse(arguments);
- case ExitCommand.COMMAND_WORD:
- return new ExitCommand();
+ case ClearCommand.COMMAND_WORD:
+ return new ClearCommand();
- case HelpCommand.COMMAND_WORD:
- return new HelpCommand();
+ case FindCommand.COMMAND_WORD:
+ return new FindCommandParser().parse(arguments);
- case ViewCommand.COMMAND_WORD:
- return new ViewCommandParser().parse(arguments);
+ case ListCommand.COMMAND_WORD:
+ return new ListCommand();
- default:
- logger.finer("This user input caused a ParseException: " + userInput);
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- } else if (meetingCommandTwoArgsMatcher.matches()) {
- final String commandWord = basicCommandMatcher.group("commandWord");
- final String firstArgument = basicCommandMatcher.group("firstArgument");
- final String secondArgument = basicCommandMatcher.group("secondArgument");
+ case ExitCommand.COMMAND_WORD:
+ return new ExitCommand();
- switch (commandWord) {
- case DeleteMeetingCommand.COMMAND_WORD:
- return new DeleteMeetingCommandParser().parse(firstArgument, secondArgument);
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
- default:
- logger.finer("This user input caused a ParseException: " + userInput);
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- } else {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ case AddMeetingCommand.COMMAND_WORD:
+ return new AddMeetingCommandParser().parse(arguments);
+ case DeleteMeetingCommand.COMMAND_WORD:
+ return new DeleteMeetingCommandParser().parse(arguments);
+ default:
+ logger.finer("This user input caused a ParseException: " + userInput);
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
-
}
}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..0f962a52fd6 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -12,4 +12,10 @@ public class CliSyntax {
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_DATETIME = new Prefix("dt/");
+ public static final Prefix PREFIX_DESCRIPTION = new Prefix("d/");
+
+ public static final Prefix PREFIX_CLIENT_INDEX = new Prefix("client/");
+ public static final Prefix PREFIX_MEETING_INDEX = new Prefix("meeting/");
+
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteMeetingCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteMeetingCommandParser.java
index a6eadf1f2cb..8a8b8bacd28 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteMeetingCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteMeetingCommandParser.java
@@ -1,31 +1,46 @@
package seedu.address.logic.parser;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_MEETING_INDEX;
+
+import java.util.stream.Stream;
import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.DeleteMeetingCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
* Parses input arguments and creates a new DeleteCommand object
*/
-public class DeleteMeetingCommandParser implements MeetingCommandParser {
-
+public class DeleteMeetingCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the DeleteCommand
* and returns a DeleteCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
- public DeleteMeetingCommand parse(String firstArgs, String secondArgs) throws ParseException {
- try {
- Index clientIndex = ParserUtil.parseIndex(firstArgs);
- Index meetingIndex = ParserUtil.parseIndex(secondArgs);
- return new DeleteMeetingCommand(clientIndex, meetingIndex);
- } catch (ParseException pe) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+ public DeleteMeetingCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_CLIENT_INDEX, PREFIX_MEETING_INDEX);
+ System.out.println(!arePrefixesPresent(argMultimap, PREFIX_CLIENT_INDEX, PREFIX_MEETING_INDEX));
+ System.out.println(!argMultimap.getPreamble().isEmpty());
+ if (!arePrefixesPresent(argMultimap, PREFIX_CLIENT_INDEX, PREFIX_MEETING_INDEX)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteMeetingCommand.MESSAGE_USAGE));
}
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_CLIENT_INDEX, PREFIX_MEETING_INDEX);
+ Index clientIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_CLIENT_INDEX).get());
+ Index meetingIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_MEETING_INDEX).get());
+ return new DeleteMeetingCommand(clientIndex, meetingIndex);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
}
}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..3615d617b3c 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -2,6 +2,8 @@
import static java.util.Objects.requireNonNull;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -9,6 +11,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.meeting.Meeting;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
@@ -121,4 +124,32 @@ public static Set parseTags(Collection tags) throws ParseException
}
return tagSet;
}
+ /**
+ * Parses a {@code String dateTime} into a {@code LocalDateTime}.
+ */
+ public static LocalDateTime parseDateTime(String dateTime) throws ParseException {
+ requireNonNull(dateTime);
+ String trimmedDateTime = dateTime.trim();
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
+ if (!Meeting.isValidDateTime(trimmedDateTime)) {
+ throw new ParseException(Meeting.MESSAGE_INVALID_DATE_TIME);
+ }
+ LocalDateTime parsedDateTime = LocalDateTime.parse(trimmedDateTime, formatter);
+ return parsedDateTime;
+ }
+ /**
+ * Parses a {@code String description} into a {@code String}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code description} is invalid.
+ */
+ public static String parseDescription(String description) throws ParseException {
+ requireNonNull(description);
+ String trimmedDescription = description.trim();
+ if (!Meeting.isValidDescription(trimmedDescription)) {
+ throw new ParseException(Meeting.MESSAGE_CONSTRAINTS);
+ }
+ return trimmedDescription;
+ }
+
}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
index 7c0de053985..2dfd1cdc8fb 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/seedu/address/model/AddressBook.java
@@ -144,6 +144,7 @@ public void setMeetings(List meetings) {
public void deleteMeeting(Meeting meeting) {
meetings.delete(meeting);
}
+
@Override
public boolean equals(Object other) {
if (other == this) {
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index 29e6b1a8adc..3397602ba90 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -97,6 +97,17 @@ public interface Model {
*/
void updateFilteredPersonList(Predicate predicate);
+ /**
+ * Adds the given meeting.
+ * {@code meeting} must not already exist in the address book under the client.
+ */
+ void addMeeting(Meeting meeting);
+
+ /**
+ * Returns true if a meeting with the same description and dateTime {@code meeting} exists in the address book.
+ */
+ boolean hasMeeting(Meeting meeting);
+
void updateFilteredMeetingList(Predicate predicate);
/**
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 095fa317756..2c60d9a3092 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -19,6 +19,7 @@
/**
* Represents the in-memory model of the address book data.
*/
+@SuppressWarnings("checkstyle:Regexp")
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
@@ -116,7 +117,20 @@ public void setPerson(Person target, Person editedPerson) {
addressBook.setPerson(target, editedPerson);
}
- // =========== Filtered Person List Accessors =============================================================
+ //=========== Meeting Related =============================================================================
+ @Override
+ public void addMeeting(Meeting meeting) {
+ addressBook.addMeeting(meeting);
+ updateFilteredMeetingList(PREDICATE_SHOW_ALL_MEETINGS);
+ }
+
+ @Override
+ public boolean hasMeeting(Meeting meeting) {
+ requireNonNull(meeting);
+ return addressBook.hasMeeting(meeting);
+ }
+
+ //=========== Filtered Person List Accessors =============================================================
/**
* Returns an unmodifiable view of the list of {@code Person} backed by the
@@ -171,8 +185,10 @@ public void deleteAllMeetingsForClient(Index clientIndex) {
@Override
public void deleteSpecificMeetingForClient(Index clientIndex, Index meetingIndex) {
- Person targetClient = filteredPersons.get(clientIndex.getZeroBased());
+ Person targetClient = addressBook.getPersonList().get(clientIndex.getZeroBased());
ArrayList targetClientMeetings = targetClient.getMeetings();
+ Meeting targetMeeting = targetClientMeetings.get(meetingIndex.getZeroBased());
+ addressBook.deleteMeeting(targetMeeting);
targetClientMeetings.remove(meetingIndex.getZeroBased());
}
diff --git a/src/main/java/seedu/address/model/meeting/Meeting.java b/src/main/java/seedu/address/model/meeting/Meeting.java
index b8dd601f48f..92bdf36afc3 100644
--- a/src/main/java/seedu/address/model/meeting/Meeting.java
+++ b/src/main/java/seedu/address/model/meeting/Meeting.java
@@ -4,7 +4,6 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.time.LocalDateTime;
-import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Objects;
@@ -28,7 +27,7 @@ public class Meeting {
/*
* description must be alphanumeric
*/
- public static final String VALIDATION_REGEX = "[^\\s].*";
+ public static final String VALIDATION_REGEX = "^[\\p{Alnum}][\\p{Alnum} ]*$";
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd MMM yyyy hh.mma");
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
@@ -42,13 +41,28 @@ public class Meeting {
* Constructor for Meeting instance
* @param description Description of the meeting
* @param dateTime Time and Date of the meeting
+ * @param client Client of the meeting
*/
public Meeting(String description, LocalDateTime dateTime, Person client) {
requireAllNonNull(description, dateTime);
checkArgument(isValidDescription(description), MESSAGE_CONSTRAINTS);
+ checkArgument(isValidDateTime(dateTime.format(formatter)), MESSAGE_INVALID_DATE_TIME);
this.description = description;
this.dateTime = dateTime;
- this.client = client;
+ this.client = client.addMeeting(this);
+ }
+ /**
+ * Constructor for Meeting instance
+ * @param description Description of the meeting
+ * @param dateTime Time and Date of the meeting
+ */
+ public Meeting(String description, LocalDateTime dateTime) {
+ requireAllNonNull(description, dateTime);
+ checkArgument(isValidDescription(description), MESSAGE_CONSTRAINTS);
+ checkArgument(isValidDateTime(dateTime.format(formatter)), MESSAGE_INVALID_DATE_TIME);
+ this.description = description;
+ this.dateTime = dateTime;
+ this.client = null;
}
/**
@@ -66,18 +80,15 @@ public static boolean isValidDescription(String test) {
public static boolean isValidDateTime(String test) {
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
+ // Attempt to parse the date-time to check format. The result is not used if parsing is successful.
LocalDateTime parsedDateTime = LocalDateTime.parse(test, formatter);
- LocalDateTime currentDateTime = LocalDateTime.now();
-
- LocalTime startTime = LocalTime.of(8, 0);
- LocalTime endTime = LocalTime.of(18, 0);
-
- return parsedDateTime.isAfter(currentDateTime)
- && parsedDateTime.toLocalTime().isAfter(startTime)
- && parsedDateTime.toLocalTime().isBefore(endTime)
- && parsedDateTime.getMinute() == 0;
+ // Check if the parsed date-time is before the current system date-time.
+ if (parsedDateTime.isBefore(LocalDateTime.now())) {
+ return false; // The date-time is in the past.
+ }
+ return true; // The string is in the correct format.
} catch (DateTimeParseException e) {
- return false;
+ return false; // The string is not in the correct format.
}
}
diff --git a/src/main/java/seedu/address/model/meeting/UniqueMeetingList.java b/src/main/java/seedu/address/model/meeting/UniqueMeetingList.java
index a5af81d9304..f9d1afeb10a 100644
--- a/src/main/java/seedu/address/model/meeting/UniqueMeetingList.java
+++ b/src/main/java/seedu/address/model/meeting/UniqueMeetingList.java
@@ -16,12 +16,17 @@
import seedu.address.model.person.Person;
/**
- * A list of Meetings that enforces uniqueness between its elements and does not allow nulls.
- * A meeting is considered unique by comparing using {@code Meeting#isSameMeeting(Meeting)}.
- * As such, adding and updating of meetings uses Meeting#isSameMeeting(Meeting) for equality
- * so as to ensure that the meeting being added or updated is unique in the UniqueMeetingList.
- * However, the removal of a meeting uses Meeting#equals(Object) so as to ensure that the
- * meeting with exactly the same fields will be removed.
+ * Manages a list of meetings, ensuring each meeting is unique and nulls are not permitted.
+ * Uniqueness of a meeting is determined by the {@code Meeting#isSameMeeting(Meeting)} method. This ensures
+ * that when adding or updating meetings, each meeting is distinct based on its fields within the UniqueMeetingList.
+ * In contrast, the removal of meetings relies on the {@code Meeting#equals(Object)} method to ensure
+ * that a meeting is removed only if it matches exactly as a meeting object.
+ *
+ * This approach allows for nuanced control over meeting management:
+ * - When adding or updating, meetings are considered the same based on specific attributes,
+ * allowing for flexible uniqueness criteria.
+ * - When removing, the stricter {@code equals} method ensures that only an exact match is removed,
+ * preventing unintended deletions.
*
* Supports a minimal set of list operations.
*
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index 1c502600d59..c5629a4ed93 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -87,6 +87,27 @@ public void setMeetings(ArrayList meetings) {
this.meetings = meetings;
}
+ /**
+ * Adds a meeting to the person's list of meetings.
+ * @param meeting
+ * @return
+ */
+ public Person addMeeting(Meeting meeting) {
+ this.meetings.add(meeting);
+ return this;
+ }
+ /**
+ * Returns true if the person has existing meeting.
+ */
+ public boolean hasExistingMeeting(Meeting meeting) {
+ for (Meeting m : this.meetings) {
+ if (m.equals(meeting)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Returns true if both persons have the same name.
* This defines a weaker notion of equality between two persons.
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
index ac882fc50a4..85bd24ece2d 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
@@ -170,6 +170,16 @@ public void updateFilteredMeetingList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void addMeeting(Meeting meeting) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean hasMeeting(Meeting meeting) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void deleteAllMeetingsForClient(Index clientIndex) {
throw new AssertionError("This method should not be called.");
diff --git a/src/test/java/seedu/address/logic/commands/AddMeetingCommandTest.java b/src/test/java/seedu/address/logic/commands/AddMeetingCommandTest.java
new file mode 100644
index 00000000000..237beb0926d
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/AddMeetingCommandTest.java
@@ -0,0 +1,260 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+import java.nio.file.Path;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.function.Predicate;
+
+import org.junit.jupiter.api.Test;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.commons.core.GuiSettings;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyUserPrefs;
+import seedu.address.model.meeting.Meeting;
+import seedu.address.model.person.Person;
+import seedu.address.testutil.MeetingBuilder;
+
+public class AddMeetingCommandTest {
+
+ @Test
+ public void constructor_validMeeting_success() {
+ AddMeetingCommand meetingCommand = new AddMeetingCommand(
+ LocalDateTime.of(2024, 1, 1, 12, 0),
+ "Sell Insurance", INDEX_FIRST_PERSON);
+ assert(meetingCommand != null);
+ }
+ @Test
+ public void constructor_nullMeeting_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new AddMeetingCommand(LocalDateTime.of(2024, 1, 1, 12, 0),
+ null, null));
+ assertThrows(NullPointerException.class, () -> new AddMeetingCommand(null, "Sell Insurance", null));
+ assertThrows(NullPointerException.class, () -> new AddMeetingCommand(null, null, INDEX_FIRST_PERSON));
+ assertThrows(NullPointerException.class, () -> new AddMeetingCommand(null, null, null));
+ }
+ @Test
+ public void execute_duplicateMeeting_throwsCommandException() {
+ Person client = new MeetingBuilder().build();
+ Meeting validMeeting = new MeetingBuilder().build().getMeetings().get(0);
+ ModelStubWithMeeting modelStub = new ModelStubWithMeeting(validMeeting, client);
+
+ AddMeetingCommand addMeetingCommand = new AddMeetingCommand(validMeeting.getDateTime(),
+ validMeeting.getDescription(), INDEX_FIRST_PERSON);
+
+ assertThrows(CommandException.class,
+ AddMeetingCommand.MESSAGE_DUPLICATE_MEETING, () -> addMeetingCommand.execute(modelStub));
+ }
+
+ @Test
+ public void equals() {
+ AddMeetingCommand addMeetingCommand = new AddMeetingCommand(
+ LocalDateTime.of(2024, 1, 1, 12, 0), "Sell Insurance", INDEX_FIRST_PERSON);
+ AddMeetingCommand addMeetingCommandCopy = new AddMeetingCommand(
+ LocalDateTime.of(2024, 1, 1, 12, 0), "Sell Insurance", INDEX_FIRST_PERSON);
+ AddMeetingCommand addMeetingCommandDifferent = new AddMeetingCommand(
+ LocalDateTime.of(2024, 1, 1, 12, 0), "Sell Insurance", Index.fromZeroBased(1));
+
+ // same object -> returns true
+ assertEquals(addMeetingCommand, addMeetingCommand);
+
+ // same values -> returns true
+ assertEquals(addMeetingCommand, addMeetingCommandCopy);
+
+ // different types -> returns false
+ assert(!addMeetingCommand.equals(1));
+
+ // null -> returns false
+ assert(!addMeetingCommand.equals(null));
+
+ // different meeting -> returns false
+ assert(!addMeetingCommand.equals(addMeetingCommandDifferent));
+ }
+
+ @Test
+ public void execute_invalidClientIndex_throwsCommandException() {
+ ModelStubWithIndexedPerson modelStub = new ModelStubWithIndexedPerson();
+ Index outOfBoundIndex = Index.fromOneBased(modelStub.getFilteredPersonList().size() + 1);
+ AddMeetingCommand addMeetingCommand = new AddMeetingCommand(
+ LocalDateTime.of(2024, 1, 1, 12, 0), "Sell Insurance", outOfBoundIndex);
+
+ assertThrows(CommandException.class,
+ Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, () -> addMeetingCommand.execute(modelStub));
+ }
+
+ private class ModelStub implements Model {
+ @Override
+ public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ReadOnlyUserPrefs getUserPrefs() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public GuiSettings getGuiSettings() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setGuiSettings(GuiSettings guiSettings) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public Path getAddressBookFilePath() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setAddressBookFilePath(Path addressBookFilePath) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void addPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setAddressBook(ReadOnlyAddressBook newData) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ReadOnlyAddressBook getAddressBook() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean hasPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void deletePerson(Person target) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setPerson(Person target, Person editedPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredMeetingList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateFilteredPersonList(Predicate predicate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateFilteredMeetingList(Predicate predicate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void addMeeting(Meeting meeting) {
+ throw new AssertionError("This Meeting method should not be called.");
+ }
+
+ @Override
+ public boolean hasMeeting(Meeting meeting) {
+ throw new AssertionError("This Meeting method should not be called.");
+ }
+ @Override
+ public void deleteAllMeetingsForClient(Index clientIndex) {
+ throw new AssertionError("This Meeting method should not be called.");
+ }
+ @Override
+ public void deleteSpecificMeetingForClient(Index clientIndex, Index meetingIndex) {
+ throw new AssertionError("This method should not be called.");
+ }
+ }
+
+
+ /**
+ * A Model stub that to micmic the person list and meeting list.
+ */
+ private class ModelStubWithIndexedPerson extends ModelStub {
+ private ObservableList persons = FXCollections.observableArrayList();
+ private ObservableList meetings = FXCollections.observableArrayList();
+
+ ModelStubWithIndexedPerson(Person... persons) {
+ this.persons.addAll(Arrays.asList(persons)); // Correctly add the persons to the observable list
+ }
+
+ @Override
+ public ObservableList getFilteredPersonList() {
+ return persons;
+ }
+
+ @Override
+ public boolean hasMeeting(Meeting meeting) {
+ return meetings.stream().anyMatch(meeting::isSameMeeting);
+ }
+
+ @Override
+ public void addMeeting(Meeting meeting) {
+ meetings.add(meeting);
+ }
+
+ }
+
+
+ /**
+ * A Model stub that contains a single predefined meeting.
+ * This stub is designed for testing scenarios where the model is expected to already contain a specific meeting.
+ * It overrides the {@code hasMeeting} method to return true when checking for the predefined meeting,
+ * simulating the scenario where a meeting already exists in the model.
+ * Use this stub in tests that require the model to behave as if it already contains a certain meeting,
+ * such as when testing for duplicate meeting prevention.
+ */
+
+ private class ModelStubWithMeeting extends ModelStub {
+ private ObservableList meetings = FXCollections.observableArrayList();
+ private ObservableList persons = FXCollections.observableArrayList();
+
+ ModelStubWithMeeting(Meeting meeting, Person... persons) {
+ requireNonNull(meeting);
+ this.meetings.add(meeting);
+ this.persons.addAll(Arrays.asList(persons));
+ }
+
+ @Override
+ public boolean hasMeeting(Meeting meeting) {
+ return meetings.stream().anyMatch(meeting::isSameMeeting);
+ }
+ @Override
+ public void addMeeting(Meeting meeting) {
+ meetings.add(meeting);
+ }
+ @Override
+ public ObservableList getFilteredPersonList() {
+ return persons;
+ }
+
+
+ }
+
+
+}
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..c068d4619b8 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -3,7 +3,11 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_MEETING_INDEX;
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_TAG;
@@ -28,15 +32,29 @@ public class CommandTestUtil {
public static final String VALID_NAME_AMY = "Amy Bee";
public static final String VALID_NAME_BOB = "Bob Choo";
+ public static final String VALID_NAME_CHAD = "Chad Doo";
+ public static final String VALID_NAME_JAMAL = "Jamal Eee";
public static final String VALID_PHONE_AMY = "11111111";
public static final String VALID_PHONE_BOB = "22222222";
+ public static final String VALID_PHONE_CHAD = "33333333";
+ public static final String VALID_PHONE_JAMAL = "44444444";
public static final String VALID_EMAIL_AMY = "amy@example.com";
public static final String VALID_EMAIL_BOB = "bob@example.com";
+ public static final String VALID_EMAIL_CHAD = "chad@example.com";
+ public static final String VALID_EMAIL_JAMAL = "jamal@example.com";
public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
+ public static final String VALID_ADDRESS_CHAD = "Block 231, Chad Street 2";
+ public static final String VALID_ADDRESS_JAMAL = "Block 123, Jamal Street 3";
public static final String VALID_TAG_HUSBAND = "husband";
public static final String VALID_TAG_FRIEND = "friend";
+ public static final String VALID_DATETIME = "01-01-2030 17:00";
+ public static final String VALID_DESCRIPTION = "Project discussion";
+
+ public static final String VALID_CLIENT_INDEX = "1";
+ public static final String VALID_MEETING_INDEX = "1";
+
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
public static final String PHONE_DESC_AMY = " " + PREFIX_PHONE + VALID_PHONE_AMY;
@@ -48,7 +66,16 @@ public class CommandTestUtil {
public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String CLIENT_INDEX = " " + PREFIX_CLIENT_INDEX + VALID_CLIENT_INDEX;
+ public static final String MEETING_INDEX = " " + PREFIX_MEETING_INDEX + VALID_MEETING_INDEX;
+ public static final String DATETIME = " " + PREFIX_DATETIME + VALID_DATETIME;
+ public static final String DESCRIPTION = " " + PREFIX_DESCRIPTION + VALID_DESCRIPTION;
+
public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
+ public static final String INVALID_DATETIME_DESC = " " + PREFIX_DATETIME
+ + "not-a-datetime"; // 'string' not allowed in datetime
+ public static final String INVALID_DESCRIPTION_DESC = " "
+ + PREFIX_DESCRIPTION; // empty string not allowed for description
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
diff --git a/src/test/java/seedu/address/logic/commands/DeleteMeetingCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteMeetingCommandTest.java
index 7fde40880b2..a5f24cb0565 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteMeetingCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/DeleteMeetingCommandTest.java
@@ -9,11 +9,9 @@
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_MEETING;
import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.JAMAL;
+import static seedu.address.testutil.TypicalMeetings.JAMAL_WITH_MEETING;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
-import java.time.LocalDateTime;
-
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.index.Index;
@@ -29,75 +27,81 @@
*/
public class DeleteMeetingCommandTest {
- private static final Meeting testMeeting = new Meeting("test meeting", LocalDateTime.now(), JAMAL);
+ static {
+ System.out.println(JAMAL_WITH_MEETING.getMeetings().size());
+ }
+ private static final Meeting testMeeting = JAMAL_WITH_MEETING.getMeetings().get(0);
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
@Test
public void execute_validClientIndexValidMeetingIndex() {
- JAMAL.getMeetings().add(testMeeting);
- model.addPerson(JAMAL);
- int clientIndex = model.getAddressBook().getPersonList().indexOf(JAMAL);
+ System.out.println(JAMAL_WITH_MEETING.getMeetings());
+ JAMAL_WITH_MEETING.getMeetings().add(testMeeting);
+ System.out.println(JAMAL_WITH_MEETING.getMeetings().size());
+ model.addPerson(JAMAL_WITH_MEETING);
+ int clientIndex = model.getAddressBook().getPersonList().indexOf(JAMAL_WITH_MEETING);
Index testClientIndex = Index.fromOneBased(Index.fromZeroBased(clientIndex).getOneBased());
- Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(JAMAL.getMeetings().size() - 1).getOneBased());
+ Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(
+ JAMAL_WITH_MEETING.getMeetings().size() - 1).getOneBased());
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(testClientIndex,
testMeetingIndex);
- String expectedMessage = "Meeting 1 deleted successfully ";
+ String expectedMessage = "Meeting 2 deleted successfully ";
ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
-
assertCommandSuccess(deleteMeetingCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_invalidClientIndexValidMeetingIndex_throwsCommandException() {
- JAMAL.getMeetings().add(testMeeting);
- model.addPerson(JAMAL);
+ JAMAL_WITH_MEETING.getMeetings().add(testMeeting);
+ model.addPerson(JAMAL_WITH_MEETING);
int invalidClientIndex = model.getAddressBook().getPersonList().size();
Index testClientIndex = Index.fromOneBased(Index.fromZeroBased(invalidClientIndex).getOneBased());
- Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(JAMAL.getMeetings().size() - 1).getOneBased());
+ Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(
+ JAMAL_WITH_MEETING.getMeetings().size() - 1).getOneBased());
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(testClientIndex, testMeetingIndex);
String expectedMessage = Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
assertCommandFailure(deleteMeetingCommand, model, expectedMessage);
- model.deletePerson(JAMAL);
+ model.deletePerson(JAMAL_WITH_MEETING);
}
@Test
public void execute_validClientIndexInvalidMeetingIndex_throwsCommandException() {
- model.addPerson(JAMAL);
- // Do not add any meeting to JAMAL to ensure the meeting index is invalid
- int clientIndex = model.getAddressBook().getPersonList().indexOf(JAMAL);
-
+ model.addPerson(JAMAL_WITH_MEETING);
+ // Do not add any meeting to JAMAL_WITH_MEETING to ensure the meeting index is invalid
+ int clientIndex = model.getAddressBook().getPersonList().indexOf(JAMAL_WITH_MEETING);
Index testClientIndex = Index.fromOneBased(Index.fromZeroBased(clientIndex).getOneBased());
- Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(JAMAL.getMeetings().size()).getOneBased());
-
+ Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(
+ JAMAL_WITH_MEETING.getMeetings().size()).getOneBased());
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(testClientIndex, testMeetingIndex);
-
- String expectedMessage = "Error: Meeting 2 not found";
+ System.out.println(JAMAL_WITH_MEETING.getMeetings());
+ String expectedMessage = "Error: Meeting 3 not found";
assertCommandFailure(deleteMeetingCommand, model, expectedMessage);
- model.deletePerson(JAMAL);
+ model.deletePerson(JAMAL_WITH_MEETING);
}
@Test
public void execute_invalidClientIndexInvalidMeetingIndex_throwsCommandException() {
- model.addPerson(JAMAL);
+ model.addPerson(JAMAL_WITH_MEETING);
// No meeting added to ensure meeting index is also invalid
int invalidClientIndex = model.getAddressBook().getPersonList().size();
Index testClientIndex = Index.fromOneBased(Index.fromZeroBased(invalidClientIndex).getOneBased());
- Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(JAMAL.getMeetings().size()).getOneBased());
+ Index testMeetingIndex = Index.fromOneBased(Index.fromZeroBased(
+ JAMAL_WITH_MEETING.getMeetings().size()).getOneBased());
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(testClientIndex, testMeetingIndex);
// invalid client index should be caught before invalid meeting index
String expectedMessage = Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
assertCommandFailure(deleteMeetingCommand, model, expectedMessage);
- model.deletePerson(JAMAL);
+ model.deletePerson(JAMAL_WITH_MEETING);
}
diff --git a/src/test/java/seedu/address/logic/parser/AddMeetingCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddMeetingCommandParserTest.java
new file mode 100644
index 00000000000..d1ee1b3265a
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/AddMeetingCommandParserTest.java
@@ -0,0 +1,70 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.commands.CommandTestUtil.CLIENT_INDEX;
+import static seedu.address.logic.commands.CommandTestUtil.DATETIME;
+import static seedu.address.logic.commands.CommandTestUtil.DESCRIPTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddMeetingCommand;
+import seedu.address.model.meeting.Meeting;
+
+public class AddMeetingCommandParserTest {
+
+ private AddMeetingCommandParser parser = new AddMeetingCommandParser();
+ private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
+ @Test
+ public void parse_allFieldsPresent_success() {
+ Index targetIndex = Index.fromOneBased(1);
+ String description = "Project discussion";
+ String dateTimeStr = "01-01-2030 17:00";
+ LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, formatter);
+ String userInput = " " + CLIENT_INDEX + DATETIME + DESCRIPTION;
+
+ assertParseSuccess(parser, userInput, new AddMeetingCommand(dateTime, description, targetIndex));
+ }
+
+
+ @Test
+ public void parse_compulsoryFieldMissing_failure() {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddMeetingCommand.MESSAGE_USAGE);
+
+ // Missing client index
+ assertParseFailure(parser, DATETIME + DESCRIPTION, expectedMessage);
+
+ // Missing date time
+ assertParseFailure(parser, DESCRIPTION + CLIENT_INDEX, expectedMessage);
+
+ // Missing description
+ assertParseFailure(parser, DATETIME + CLIENT_INDEX, expectedMessage);
+ }
+
+ @Test
+ public void parse_invalidValue_failure() {
+ String userInput = " " + PREFIX_CLIENT_INDEX + "0 " + DATETIME + DESCRIPTION;
+ // Invalid client index
+ assertParseFailure(parser, userInput, MESSAGE_INVALID_INDEX);
+
+ String userInputDateTime = " " + CLIENT_INDEX + " " + PREFIX_DATETIME + "01-01-2024 17:00 " + DESCRIPTION;
+ // Invalid date time
+ assertParseFailure(parser, userInputDateTime, Meeting.MESSAGE_INVALID_DATE_TIME);
+
+ String userInputDescription = " " + CLIENT_INDEX + DATETIME + " " + PREFIX_DESCRIPTION + " ";
+ // Invalid description
+ assertParseFailure(parser, userInputDescription, Meeting.MESSAGE_CONSTRAINTS);
+
+ }
+
+ // Additional tests for other invalid scenarios, like invalid description, etc.
+}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteMeetingCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteMeetingCommandParserTest.java
index a33ea0d7a1f..b4fb9c61308 100644
--- a/src/test/java/seedu/address/logic/parser/DeleteMeetingCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/DeleteMeetingCommandParserTest.java
@@ -1,6 +1,8 @@
package seedu.address.logic.parser;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertMeetingParseSuccess;
+import static seedu.address.logic.commands.CommandTestUtil.CLIENT_INDEX;
+import static seedu.address.logic.commands.CommandTestUtil.MEETING_INDEX;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_MEETING;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
@@ -21,6 +23,7 @@ public class DeleteMeetingCommandParserTest {
@Test
public void parse_validArgs_returnsDeleteCommand() {
- assertMeetingParseSuccess(parser, "1", "1", new DeleteMeetingCommand(INDEX_FIRST_PERSON, INDEX_FIRST_MEETING));
+ String userInput = " " + CLIENT_INDEX + MEETING_INDEX;
+ assertParseSuccess(parser, userInput, new DeleteMeetingCommand(INDEX_FIRST_PERSON, INDEX_FIRST_MEETING));
}
}
diff --git a/src/test/java/seedu/address/model/meeting/MeetingBelongingToClientPredicateTest.java b/src/test/java/seedu/address/model/meeting/MeetingBelongingToClientPredicateTest.java
index 0d709788268..8d24754902d 100644
--- a/src/test/java/seedu/address/model/meeting/MeetingBelongingToClientPredicateTest.java
+++ b/src/test/java/seedu/address/model/meeting/MeetingBelongingToClientPredicateTest.java
@@ -14,6 +14,7 @@
import seedu.address.testutil.PersonBuilder;
public class MeetingBelongingToClientPredicateTest {
+
@Test
public void equals() {
MeetingBelongingToClientPredicate firstPredicate = new MeetingBelongingToClientPredicate(ALICE);
@@ -39,14 +40,13 @@ public void equals() {
// different person -> returns false
assertFalse(firstPredicate.equals(secondPredicate));
}
-
@Test
public void test_clientWithMeeting_returnsTrue() {
MeetingBelongingToClientPredicate predicate = new MeetingBelongingToClientPredicate(JAMAL);
assertTrue(predicate.test(new MeetingBuilder()
.withClient(JAMAL)
.withDescription("Financial Aid Document Submission")
- .withDateTime("05-02-2024 13:00").build()));
+ .withDateTime("05-02-2029 13:00").build().getMeetings().get(0)));
}
@Test
@@ -55,9 +55,8 @@ public void test_clientWithMeeting_returnsFalse() {
assertFalse(predicate.test(new MeetingBuilder()
.withClient(JAMAL)
.withDescription("Financial Aid Document Submission")
- .withDateTime("05-02-2024 13:00").build()));
+ .withDateTime("05-02-2029 13:00").build().getMeetings().get(0)));
}
-
@Test
public void toStringMethod() {
MeetingBelongingToClientPredicate predicate = new MeetingBelongingToClientPredicate(ALICE);
diff --git a/src/test/java/seedu/address/model/meeting/MeetingTest.java b/src/test/java/seedu/address/model/meeting/MeetingTest.java
index 126891b1961..f04b1d35d1a 100644
--- a/src/test/java/seedu/address/model/meeting/MeetingTest.java
+++ b/src/test/java/seedu/address/model/meeting/MeetingTest.java
@@ -6,7 +6,6 @@
import org.junit.jupiter.api.Test;
-import seedu.address.testutil.MeetingBuilder;
import seedu.address.testutil.TypicalMeetings;
public class MeetingTest {
@@ -14,36 +13,41 @@ public class MeetingTest {
@Test
public void isSameMeeting() {
// same object -> returns true
- assertTrue(TypicalMeetings.MEETING_WITH_ALICE.isSameMeeting(TypicalMeetings.MEETING_WITH_ALICE));
+ assertTrue(TypicalMeetings.ALICE_WITH_MEETING.hasExistingMeeting(TypicalMeetings
+ .ALICE_WITH_MEETING.getMeetings().get(0)));
// different meeting -> returns false
- assertFalse(TypicalMeetings.MEETING_WITH_ALICE.isSameMeeting(TypicalMeetings.MEETING_WITH_BENSON));
+ assertFalse(TypicalMeetings.ALICE_WITH_MEETING.hasExistingMeeting(TypicalMeetings
+ .BENSON_WITH_MEETING.getMeetings().get(0)));
}
@Test
public void equals() {
// same values -> returns true
- Meeting meetingWithAliceCopy = new MeetingBuilder(TypicalMeetings.MEETING_WITH_ALICE).build();
- assertTrue(TypicalMeetings.MEETING_WITH_ALICE.equals(meetingWithAliceCopy));
+ Meeting meetingWithAliceCopy = TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0);
+
+ assertTrue(TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0).equals(meetingWithAliceCopy));
// same object -> returns true
- assertTrue(TypicalMeetings.MEETING_WITH_ALICE.equals(TypicalMeetings.MEETING_WITH_ALICE));
+ assertTrue(TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0)
+ .equals(TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0)));
// null -> returns false
- assertFalse(TypicalMeetings.MEETING_WITH_ALICE.equals(null));
+ assertFalse(TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0).equals(null));
// different type -> returns false
- assertFalse(TypicalMeetings.MEETING_WITH_ALICE.equals(5));
+ assertFalse(TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0).equals(5));
// different meeting -> returns false
- assertFalse(TypicalMeetings.MEETING_WITH_ALICE.equals(TypicalMeetings.MEETING_WITH_BENSON));
+ assertFalse(TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0)
+ .equals(TypicalMeetings.BENSON_WITH_MEETING));
}
@Test
public void toStringMethod() {
String expected = Meeting.class.getCanonicalName()
- + "{description=Financial Aid Application Review, dateTime=2024-01-01T09:00, "
+ + "{description=Financial Aid Application Review, dateTime=2030-01-01T12:00, "
+ "client=Alice Pauline}";
- assertEquals(expected, TypicalMeetings.MEETING_WITH_ALICE.toString());
+ assertEquals(expected, TypicalMeetings.ALICE_WITH_MEETING.getMeetings().get(0).toString());
}
}
diff --git a/src/test/java/seedu/address/model/meeting/UniqueMeetingListTest.java b/src/test/java/seedu/address/model/meeting/UniqueMeetingListTest.java
index ae213e08db1..35231d4739d 100644
--- a/src/test/java/seedu/address/model/meeting/UniqueMeetingListTest.java
+++ b/src/test/java/seedu/address/model/meeting/UniqueMeetingListTest.java
@@ -1,20 +1,22 @@
+package seedu.address.model.meeting;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.TypicalMeetings.MEETING_WITH_ALICE;
-import static seedu.address.testutil.TypicalMeetings.MEETING_WITH_BENSON;
-import static seedu.address.testutil.TypicalMeetings.MEETING_WITH_CARL;
+//import static seedu.address.testutil.TypicalMeetings.ALICE_WITH_MEETING;
+import static seedu.address.testutil.TypicalMeetings.ALICE_WITH_MEETING;
+import static seedu.address.testutil.TypicalMeetings.BENSON_WITH_MEETING;
+import static seedu.address.testutil.TypicalMeetings.CARL_WITH_MEETING;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
-import seedu.address.model.meeting.Meeting;
-import seedu.address.model.meeting.UniqueMeetingList;
import seedu.address.model.meeting.exceptions.DuplicateMeetingException;
import seedu.address.model.meeting.exceptions.MeetingNotFoundException;
+import seedu.address.model.person.Person;
import seedu.address.testutil.MeetingBuilder;
public class UniqueMeetingListTest {
@@ -28,13 +30,13 @@ public void contains_nullMeeting_throwsNullPointerException() {
@Test
public void contains_meetingNotInList_returnsFalse() {
- assertFalse(uniqueMeetingList.contains(MEETING_WITH_ALICE));
+ assertFalse(uniqueMeetingList.contains(ALICE_WITH_MEETING.getMeetings().get(0)));
}
@Test
public void contains_meetingInList_returnsTrue() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- assertTrue(uniqueMeetingList.contains(MEETING_WITH_ALICE));
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ assertTrue(uniqueMeetingList.contains(ALICE_WITH_MEETING.getMeetings().get(0)));
}
@Test
@@ -44,62 +46,67 @@ public void add_nullMeeting_throwsNullPointerException() {
@Test
public void add_duplicateMeeting_throwsDuplicateMeetingException() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- assertThrows(DuplicateMeetingException.class, () -> uniqueMeetingList.add(MEETING_WITH_ALICE));
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ assertThrows(DuplicateMeetingException.class, () -> uniqueMeetingList
+ .add(ALICE_WITH_MEETING.getMeetings().get(0)));
}
@Test
public void setMeeting_nullTargetMeeting_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniqueMeetingList.setMeeting(null, MEETING_WITH_ALICE));
+ assertThrows(NullPointerException.class, () -> uniqueMeetingList.setMeeting(null,
+ ALICE_WITH_MEETING.getMeetings().get(0)));
}
@Test
public void setMeeting_nullEditedMeeting_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniqueMeetingList.setMeeting(MEETING_WITH_ALICE, null));
+ assertThrows(NullPointerException.class, () -> uniqueMeetingList.setMeeting(ALICE_WITH_MEETING
+ .getMeetings().get(0), null));
}
@Test
public void setMeeting_targetMeetingNotInList_throwsMeetingNotFoundException() {
- assertThrows(MeetingNotFoundException.class, () -> uniqueMeetingList.setMeeting(MEETING_WITH_ALICE,
- MEETING_WITH_ALICE));
+ assertThrows(MeetingNotFoundException.class, () -> uniqueMeetingList.setMeeting(ALICE_WITH_MEETING
+ .getMeetings().get(0),
+ ALICE_WITH_MEETING.getMeetings().get(0)));
}
@Test
public void setMeeting_editedMeetingIsSameMeeting_success() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- uniqueMeetingList.setMeeting(MEETING_WITH_ALICE, MEETING_WITH_ALICE);
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ uniqueMeetingList.setMeeting(ALICE_WITH_MEETING.getMeetings().get(0), ALICE_WITH_MEETING.getMeetings().get(0));
UniqueMeetingList expectedUniqueMeetingList = new UniqueMeetingList();
- expectedUniqueMeetingList.add(MEETING_WITH_ALICE);
+ expectedUniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
assertEquals(expectedUniqueMeetingList, uniqueMeetingList);
}
@Test
public void setMeeting_editedMeetingHasSameIdentity_success() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- Meeting editedAlice = new MeetingBuilder(MEETING_WITH_ALICE)
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ Person editedAlice = new MeetingBuilder(ALICE_WITH_MEETING.getMeetings().get(0))
.withDescription("Updated Description")
.build();
- uniqueMeetingList.setMeeting(MEETING_WITH_ALICE, editedAlice);
+ uniqueMeetingList.setMeeting(ALICE_WITH_MEETING.getMeetings().get(0), editedAlice.getMeetings().get(0));
UniqueMeetingList expectedUniqueMeetingList = new UniqueMeetingList();
- expectedUniqueMeetingList.add(editedAlice);
+ expectedUniqueMeetingList.add(editedAlice.getMeetings().get(0));
assertEquals(expectedUniqueMeetingList, uniqueMeetingList);
}
@Test
public void setMeeting_editedMeetingHasDifferentIdentity_success() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- uniqueMeetingList.setMeeting(MEETING_WITH_ALICE, MEETING_WITH_BENSON);
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ uniqueMeetingList.setMeeting(ALICE_WITH_MEETING.getMeetings().get(0), BENSON_WITH_MEETING.getMeetings().get(0));
UniqueMeetingList expectedUniqueMeetingList = new UniqueMeetingList();
- expectedUniqueMeetingList.add(MEETING_WITH_BENSON);
+ expectedUniqueMeetingList.add(BENSON_WITH_MEETING.getMeetings().get(0));
assertEquals(expectedUniqueMeetingList, uniqueMeetingList);
}
@Test
public void setMeeting_editedMeetingHasNonUniqueIdentity_throwsDuplicateMeetingException() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- uniqueMeetingList.add(MEETING_WITH_BENSON);
- assertThrows(DuplicateMeetingException.class, () -> uniqueMeetingList.setMeeting(MEETING_WITH_ALICE,
- MEETING_WITH_BENSON));
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ uniqueMeetingList.add(BENSON_WITH_MEETING.getMeetings().get(0));
+ assertThrows(DuplicateMeetingException.class, () -> uniqueMeetingList.setMeeting(
+ ALICE_WITH_MEETING.getMeetings().get(0),
+ BENSON_WITH_MEETING.getMeetings().get(0)));
}
@Test
@@ -109,13 +116,14 @@ public void remove_nullMeeting_throwsNullPointerException() {
@Test
public void remove_meetingDoesNotExist_throwsMeetingNotFoundException() {
- assertThrows(MeetingNotFoundException.class, () -> uniqueMeetingList.remove(MEETING_WITH_ALICE));
+ assertThrows(MeetingNotFoundException.class, () -> uniqueMeetingList.remove(
+ ALICE_WITH_MEETING.getMeetings().get(0)));
}
@Test
public void remove_existingMeeting_removesMeeting() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- uniqueMeetingList.remove(MEETING_WITH_ALICE);
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ uniqueMeetingList.remove(ALICE_WITH_MEETING.getMeetings().get(0));
UniqueMeetingList expectedUniqueMeetingList = new UniqueMeetingList();
assertEquals(expectedUniqueMeetingList, uniqueMeetingList);
}
@@ -127,9 +135,9 @@ public void setMeetings_nullUniqueMeetingList_throwsNullPointerException() {
@Test
public void setMeetings_uniqueMeetingList_replacesOwnListWithProvidedUniqueMeetingList() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
UniqueMeetingList expectedUniqueMeetingList = new UniqueMeetingList();
- expectedUniqueMeetingList.add(MEETING_WITH_BENSON);
+ expectedUniqueMeetingList.add(BENSON_WITH_MEETING.getMeetings().get(0));
uniqueMeetingList.setMeetings(expectedUniqueMeetingList);
assertEquals(expectedUniqueMeetingList, uniqueMeetingList);
}
@@ -141,18 +149,20 @@ public void setMeetings_nullList_throwsNullPointerException() {
@Test
public void setMeetings_list_replacesOwnListWithProvidedList() {
- uniqueMeetingList.add(MEETING_WITH_ALICE);
- List meetingList = Arrays.asList(MEETING_WITH_BENSON, MEETING_WITH_CARL);
+ uniqueMeetingList.add(ALICE_WITH_MEETING.getMeetings().get(0));
+ List meetingList = Arrays.asList(BENSON_WITH_MEETING.getMeetings().get(0),
+ CARL_WITH_MEETING.getMeetings().get(0));
uniqueMeetingList.setMeetings(meetingList);
UniqueMeetingList expectedUniqueMeetingList = new UniqueMeetingList();
- expectedUniqueMeetingList.add(MEETING_WITH_BENSON);
- expectedUniqueMeetingList.add(MEETING_WITH_CARL);
+ expectedUniqueMeetingList.add(BENSON_WITH_MEETING.getMeetings().get(0));
+ expectedUniqueMeetingList.add(CARL_WITH_MEETING.getMeetings().get(0));
assertEquals(expectedUniqueMeetingList, uniqueMeetingList);
}
@Test
public void setMeetings_listWithDuplicateMeetings_throwsDuplicateMeetingException() {
- List listWithDuplicateMeetings = Arrays.asList(MEETING_WITH_ALICE, MEETING_WITH_ALICE);
+ List listWithDuplicateMeetings = Arrays.asList(ALICE_WITH_MEETING.getMeetings().get(0),
+ ALICE_WITH_MEETING.getMeetings().get(0));
assertThrows(DuplicateMeetingException.class, () -> uniqueMeetingList.setMeetings(listWithDuplicateMeetings));
}
diff --git a/src/test/java/seedu/address/testutil/MeetingBuilder.java b/src/test/java/seedu/address/testutil/MeetingBuilder.java
index 958fea144c3..5f9efe30b71 100644
--- a/src/test/java/seedu/address/testutil/MeetingBuilder.java
+++ b/src/test/java/seedu/address/testutil/MeetingBuilder.java
@@ -12,7 +12,7 @@
public class MeetingBuilder {
public static final String DEFAULT_DESCRIPTION = "Description of Meeting";
- public static final String DEFAULT_DATE = "01-01-2024 00:00";
+ public static final String DEFAULT_DATE = "01-01-2030 17:00";
public static final Person DEFAULT_CLIENT = new PersonBuilder().build();
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
@@ -28,6 +28,14 @@ public MeetingBuilder() {
dateTime = LocalDateTime.parse(DEFAULT_DATE, formatter);
client = DEFAULT_CLIENT;
}
+ /**
+ * Creates a {@code MeetingBuilder} with the default details, but with the specified person.
+ */
+ public MeetingBuilder(Person person) {
+ description = DEFAULT_DESCRIPTION;
+ dateTime = LocalDateTime.parse(DEFAULT_DATE, formatter);
+ client = person;
+ }
/**
* Constructs a {@code MeetingBuilder} with the specified meeting to copy.
@@ -68,7 +76,8 @@ public MeetingBuilder withClient(Person client) {
/**
* Builds and returns a {@code Meeting} object with the specified details.
*/
- public Meeting build() {
- return new Meeting(description, dateTime, client);
+ public Person build() {
+ Meeting meeting = new Meeting(description, dateTime, client);
+ return client;
}
}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java
index e20160ba41f..0870df36928 100644
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ b/src/test/java/seedu/address/testutil/PersonBuilder.java
@@ -1,8 +1,5 @@
package seedu.address.testutil;
-import static seedu.address.testutil.TypicalPersons.CHAD;
-import static seedu.address.testutil.TypicalPersons.JAMAL;
-
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -19,6 +16,7 @@
/**
* A utility class to help with building Person objects.
*/
+@SuppressWarnings("checkstyle:Regexp")
public class PersonBuilder {
public static final String DEFAULT_NAME = "Amy Bee";
@@ -96,29 +94,16 @@ public PersonBuilder withEmail(String email) {
this.email = new Email(email);
return this;
}
-
/**
- * Sets the {@code Meeting} of the {@code Person} that we are building.
+ * Adds a meeting to the person that we are building.
*/
- public PersonBuilder withDefaultMeetingA() {
- this.meetings.add(new MeetingBuilder()
- .withClient(JAMAL)
- .withDescription("Financial Aid Document Submission")
- .withDateTime("05-02-2024 13:00").build());
+ public PersonBuilder withMeeting(Meeting meeting) {
+ this.meetings.add(meeting);
return this;
}
-
/**
- * Sets the {@code Meeting} of the {@code Person} that we are building.
+ * Builds the person with the meetings.
*/
- public PersonBuilder withDefaultMeetingB() {
- this.meetings.add(new MeetingBuilder()
- .withClient(CHAD)
- .withDescription("Financial Aid Application Review")
- .withDateTime("01-01-2024 09:00").build());
- return this;
- }
-
public Person build() {
return new Person(name, phone, email, address, tags);
}
diff --git a/src/test/java/seedu/address/testutil/TypicalMeetings.java b/src/test/java/seedu/address/testutil/TypicalMeetings.java
index b9170a1b466..733a4119b07 100644
--- a/src/test/java/seedu/address/testutil/TypicalMeetings.java
+++ b/src/test/java/seedu/address/testutil/TypicalMeetings.java
@@ -3,54 +3,67 @@
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.CHAD;
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.JAMAL;
import java.util.ArrayList;
import java.util.Arrays;
-import seedu.address.model.meeting.Meeting;
+import seedu.address.model.person.Person;
/**
* A utility class containing a list of {@code Meeting} objects to be used in tests.
*/
public class TypicalMeetings {
- public static final Meeting MEETING_WITH_ALICE = new MeetingBuilder()
+ public static final Person ALICE_WITH_MEETING = new MeetingBuilder()
.withClient(ALICE)
.withDescription("Financial Aid Application Review")
- .withDateTime("01-01-2024 09:00").build();
- public static final Meeting MEETING_WITH_BENSON = new MeetingBuilder()
+ .withDateTime("01-01-2030 12:00").build();
+ public static final Person BENSON_WITH_MEETING = new MeetingBuilder()
.withClient(BENSON)
.withDescription("Financial Aid Eligibility Check")
- .withDateTime("01-11-2023 11:00").build();
- public static final Meeting MEETING_WITH_CARL = new MeetingBuilder()
+ .withDateTime("01-11-2030 11:00").build();
+ public static final Person CARL_WITH_MEETING = new MeetingBuilder()
.withClient(CARL)
.withDescription("Financial Aid Document Submission")
- .withDateTime("05-02-2024 13:00").build();
- public static final Meeting MEETING_WITH_DANIEL = new MeetingBuilder()
+ .withDateTime("05-02-2030 13:00").build();
+ public static final Person DANIEL_WITH_MEETING = new MeetingBuilder()
.withClient(DANIEL)
.withDescription("Financial Aid Interview")
- .withDateTime("05-02-2024 15:00").build();
- public static final Meeting MEETING_WITH_ELLE = new MeetingBuilder()
+ .withDateTime("05-02-2030 15:00").build();
+ public static final Person ELLE_WITH_MEETING = new MeetingBuilder()
.withClient(ELLE)
.withDescription("Financial Aid Consultation")
- .withDateTime("05-02-2024 12:00").build();
- public static final Meeting MEETING_WITH_FIONA = new MeetingBuilder()
+ .withDateTime("05-02-2029 12:00").build();
+ public static final Person FIONA_WITH_MEETING = new MeetingBuilder()
.withClient(FIONA)
.withDescription("Financial Aid Application Review")
- .withDateTime("05-02-2024 11:00").build();
- public static final Meeting MEETING_WITH_GEORGE = new MeetingBuilder()
+ .withDateTime("05-02-2028 11:00").build();
+ public static final Person GEORGE_WITH_MEETING = new MeetingBuilder()
.withClient(GEORGE)
.withDescription("Financial Aid Document Submission")
- .withDateTime("05-02-2024 17:00").build();
+ .withDateTime("05-02-2029 17:00").build();
+
+ public static final Person JAMAL_WITH_MEETING = new MeetingBuilder()
+ .withClient(JAMAL)
+ .withDescription("Financial Support")
+ .withDateTime("05-02-2028 11:00").build();
+
+ public static final Person CHAD_WITH_MEETING = new MeetingBuilder()
+ .withClient(CHAD)
+ .withDescription("Financial Aid Application Review")
+ .withDateTime("05-02-2028 11:00").build();
private TypicalMeetings() {} // prevents instantiation
- public static ArrayList getTypicalMeetings() {
- return new ArrayList<>(Arrays.asList(MEETING_WITH_ALICE, MEETING_WITH_BENSON, MEETING_WITH_CARL,
- MEETING_WITH_DANIEL, MEETING_WITH_ELLE, MEETING_WITH_FIONA, MEETING_WITH_GEORGE));
+ public static ArrayList getTypicalMeetings() {
+ return new ArrayList<>(Arrays.asList(ALICE_WITH_MEETING, BENSON_WITH_MEETING, CARL_WITH_MEETING,
+ DANIEL_WITH_MEETING, ELLE_WITH_MEETING, FIONA_WITH_MEETING, GEORGE_WITH_MEETING,
+ JAMAL_WITH_MEETING, CHAD_WITH_MEETING));
}
}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
index 83082c5537e..eed362bfc2d 100644
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ b/src/test/java/seedu/address/testutil/TypicalPersons.java
@@ -2,12 +2,20 @@
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_CHAD;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_JAMAL;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_CHAD;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_JAMAL;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_CHAD;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_JAMAL;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_CHAD;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_JAMAL;
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
@@ -56,10 +64,10 @@ public class TypicalPersons {
.build();
// To for Clients with meetings
- public static final Person JAMAL = new PersonBuilder().withName("Jamal").withPhone("88888888")
- .withEmail("jamal@example.com").withAddress("little india").withDefaultMeetingA().build();
- public static final Person CHAD = new PersonBuilder().withName("Chad").withPhone("88888888")
- .withEmail("chad@example.com").withAddress("little india").withDefaultMeetingB().build();
+ public static final Person JAMAL = new PersonBuilder().withName(VALID_NAME_JAMAL).withPhone(VALID_PHONE_JAMAL)
+ .withEmail(VALID_EMAIL_JAMAL).withAddress(VALID_ADDRESS_JAMAL).build();
+ public static final Person CHAD = new PersonBuilder().withName(VALID_NAME_CHAD).withPhone(VALID_PHONE_CHAD)
+ .withEmail(VALID_EMAIL_CHAD).withAddress(VALID_ADDRESS_CHAD).build();
public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
private TypicalPersons() {} // prevents instantiation