From 8dc736ed77859c038eb0ad8ab7846aeca0cfb488 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 00:34:29 +0800 Subject: [PATCH 01/25] Add task classes --- .../seedu/address/model/task/Deadline.java | 61 +++++++ .../java/seedu/address/model/task/Event.java | 71 +++++++++ .../java/seedu/address/model/task/Task.java | 144 +++++++++++++++++ .../java/seedu/address/model/task/Todo.java | 47 ++++++ .../address/model/task/UniqueTaskList.java | 150 ++++++++++++++++++ .../exceptions/DuplicateTaskException.java | 12 ++ .../exceptions/TaskNotFoundException.java | 10 ++ 7 files changed, 495 insertions(+) create mode 100644 src/main/java/seedu/address/model/task/Deadline.java create mode 100644 src/main/java/seedu/address/model/task/Event.java create mode 100644 src/main/java/seedu/address/model/task/Task.java create mode 100644 src/main/java/seedu/address/model/task/Todo.java create mode 100644 src/main/java/seedu/address/model/task/UniqueTaskList.java create mode 100644 src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java create mode 100644 src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java diff --git a/src/main/java/seedu/address/model/task/Deadline.java b/src/main/java/seedu/address/model/task/Deadline.java new file mode 100644 index 00000000000..543f9b3c12e --- /dev/null +++ b/src/main/java/seedu/address/model/task/Deadline.java @@ -0,0 +1,61 @@ +package seedu.address.model.task; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * The Deadline class represents a task with a deadline. + * It extends the Task class and adds a LocalDate field to store the deadline date. + */ +public class Deadline extends Task { + + private LocalDate by; + + /** + * Constructs a Deadline task with the specified description and deadline date. + * + * @param description The description of the task. + * @param by The deadline date in the format "yyyy-MM-dd". + */ + public Deadline(String description, String by) { + super(description); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + this.by = LocalDate.parse(by, formatter); + } + + public LocalDate getBy() { + return by; + } + + /** + * Returns true if both deadline tasks have the same data fields. + * This defines a stronger notion of equality between two deadline tasks. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Deadline)) { + return false; + } + + Deadline otherDeadline = (Deadline) other; + return description.equals(otherDeadline.description) + && isDone == otherDeadline.isDone + && by.equals(otherDeadline.by); + } + + /** + * Returns a string representation of the Deadline task, including its deadline date. + * + * @return A string representation of the Deadline task. + */ + @Override + public String toString() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy"); + return "[D]" + super.toString() + " (by: " + this.by.format(formatter) + ")"; + } +} diff --git a/src/main/java/seedu/address/model/task/Event.java b/src/main/java/seedu/address/model/task/Event.java new file mode 100644 index 00000000000..af40b1dec9f --- /dev/null +++ b/src/main/java/seedu/address/model/task/Event.java @@ -0,0 +1,71 @@ +package seedu.address.model.task; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * The Event class represents a task that spans over a period of time. + * It extends the Task class and adds LocalDate fields to store the start and end dates of the event. + */ +public class Event extends Task { + + private LocalDate from; + private LocalDate to; + + /** + * Constructs an Event task with the specified description, start date, and end date. + * + * @param description The description of the event. + * @param from The start date of the event in the format "yyyy-MM-dd". + * @param to The end date of the event in the format "yyyy-MM-dd". + */ + public Event(String description, String from, String to) { + super(description); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + this.from = LocalDate.parse(from, formatter); + this.to = LocalDate.parse(to, formatter); + } + + public LocalDate getFrom() { + return from; + } + + public LocalDate getTo() { + return to; + } + + + /** + * Returns true if both event tasks have the same data fields. + * This defines a stronger notion of equality between two event tasks. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Event)) { + return false; + } + + Event otherEvent = (Event) other; + return description.equals(otherEvent.description) + && isDone == otherEvent.isDone + && from.equals(otherEvent.from) + && to.equals(equals(otherEvent.to)); + } + + /** + * Returns a string representation of the Event task, including its start and end dates. + * + * @return A string representation of the Event task. + */ + @Override + public String toString() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy"); + return "[E]" + super.toString() + " (from: " + this.from.format(formatter) + + " to: " + this.to.format(formatter) + ")"; + } +} diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java new file mode 100644 index 00000000000..37042e8541d --- /dev/null +++ b/src/main/java/seedu/address/model/task/Task.java @@ -0,0 +1,144 @@ +package seedu.address.model.task; + +/** + * The Task class represents a general task with a description and a completion status. + * It serves as the base class for more specific types of tasks such as Todo, Deadline, and Event. + */ +public class Task { + protected String description; + protected boolean isDone; + + /** + * Constructs a Task with the specified description. + * The task is initially marked as not done. + * + * @param description The description of the task. + */ + public Task(String description) { + this.description = description; + this.isDone = false; + } + + /** + * Returns the status icon of the task. + * "X" if the task is done, " " if the task is not done. + * + * @return The status icon of the task. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + /** + * Returns the description of the task. + * + * @return The description of the task as a String. + */ + public String getDescription() { + return this.description; + } + + /** + * Returns the isDone status the task. + * + * @return The completion status of the task as a Boolean. + */ + public Boolean getIsDone() { + return this.isDone; + } + + /** + * Marks the task as done. + */ + public void markAsDone() { + isDone = true; + } + + /** + * Marks the task as not done. + */ + public void markAsUndone() { + isDone = false; + } + + /** + * Returns the presence of the given keyword within the description. + * "true" if the keyword is present, "false" if the keyword is not. + * + * @param keyword The supplied keyword string. + * @return The boolean indicating presence of the keyword + */ + public boolean hasKeyword(String keyword) { + String[] descriptionArray = description.split(" "); + for (String word : descriptionArray) { + if (word.equals(keyword)) { + return true; + } + } + return false; + } + + /** + * Returns the presence of the given keyword if it is + * within a partial/full word in the description, case-insensitive. + * "true" if the keyword is present, "false" if the keyword is not. + * + * @param keyword The supplied keyword string. + * @return The boolean indicating presence of the keyword + */ + public boolean hasKeywordInPartialDescription(String keyword) { + String lowerCaseKeyword = keyword.toLowerCase(); + String[] descriptionArray = description.split(" "); + for (String word : descriptionArray) { + String lowerCaseWord = word.toLowerCase(); + if (lowerCaseWord.contains(lowerCaseKeyword)) { + return true; + } + } + return false; + } + + /** + * Returns true if both tasks have the same description. + * This defines a weaker notion of equality between two tasks. + */ + public boolean isSameTask(Task otherTask) { + if (otherTask == this) { + return true; + } + + return otherTask != null + && otherTask.getDescription().equals(getDescription()); + } + + /** + * Returns true if both tasks have the same data fields. + * This defines a stronger notion of equality between two tasks. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Task)) { + return false; + } + + Task otherTask = (Task) other; + return description.equals(otherTask.description) + && isDone == otherTask.isDone; + } + + /** + * Returns a string representation of the Task. + * + * @return A string representation of the Task, including its status and description. + */ + public String toString() { + return "[" + this.getStatusIcon() + "] " + this.description; + } +} + + diff --git a/src/main/java/seedu/address/model/task/Todo.java b/src/main/java/seedu/address/model/task/Todo.java new file mode 100644 index 00000000000..fb51bc4d632 --- /dev/null +++ b/src/main/java/seedu/address/model/task/Todo.java @@ -0,0 +1,47 @@ +package seedu.address.model.task; + +/** + * The Todo class represents a simple task with no specific date attached. + * It extends the Task class and does not add any additional fields. + */ +public class Todo extends Task { + /** + * Constructs a Todo task with the specified description. + * + * @param description The description of the todo task. + */ + public Todo(String description) { + super(description); + } + + + /** + * Returns true if both Todo tasks have the same data fields. + * This defines a stronger notion of equality between two Todo tasks. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Todo)) { + return false; + } + + Todo otherTodo = (Todo) other; + return description.equals(otherTodo.description) + && isDone == otherTodo.isDone; + } + + /** + * Returns a string representation of the Todo task. + * + * @return A string representation of the Todo task. + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } +} diff --git a/src/main/java/seedu/address/model/task/UniqueTaskList.java b/src/main/java/seedu/address/model/task/UniqueTaskList.java new file mode 100644 index 00000000000..6c1fb299d34 --- /dev/null +++ b/src/main/java/seedu/address/model/task/UniqueTaskList.java @@ -0,0 +1,150 @@ +package seedu.address.model.task; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Iterator; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.address.model.task.exceptions.DuplicateTaskException; +import seedu.address.model.task.exceptions.TaskNotFoundException; + +/** + * A list of tasks that enforces uniqueness between its elements and does not allow nulls. + * A task is considered unique by comparing using {@code Task#isSameTask(Task)}. As such, adding and updating of + * tasks uses Task#isSameTask(Task) for equality so as to ensure that the task being added or updated is + * unique in terms of identity in the UniqueTaskList. However, the removal of a task uses Task#equals(Object) so + * as to ensure that the task with exactly the same fields will be removed. + * + * Supports a minimal set of list operations. + * + * @see Task#isSameTask(Task) + */ +public class UniqueTaskList implements Iterable { + + private final ObservableList internalList = FXCollections.observableArrayList(); + private final ObservableList internalUnmodifiableList = + FXCollections.unmodifiableObservableList(internalList); + + /** + * Returns true if the list contains an equivalent task as the given argument. + */ + public boolean contains(Task toCheck) { + requireNonNull(toCheck); + return internalList.stream().anyMatch(toCheck::isSameTask); + } + + /** + * Adds a Task to the list. + * The Task must not already exist in the list. + */ + public void add(Task toAdd) { + requireNonNull(toAdd); + if (contains(toAdd)) { + throw new DuplicateTaskException(); + } + internalList.add(toAdd); + } + + /** + * Replaces the Task {@code target} in the list with {@code editedTask}. + * {@code target} must exist in the list. + * The task identity of {@code editedTask} must not be the same as another existing task in the list. + */ + public void setTask(Task target, Task editedTask) { + requireAllNonNull(target, editedTask); + + int index = internalList.indexOf(target); + if (index == -1) { + throw new TaskNotFoundException(); + } + + if (!target.isSameTask(editedTask) && contains(editedTask)) { + throw new DuplicateTaskException(); + } + + internalList.set(index, editedTask); + } + + /** + * Removes the equivalent Task from the list. + * The task must exist in the list. + */ + public void remove(Task toRemove) { + requireNonNull(toRemove); + if (!internalList.remove(toRemove)) { + throw new TaskNotFoundException(); + } + } + + public void setTasks(UniqueTaskList replacement) { + requireNonNull(replacement); + internalList.setAll(replacement.internalList); + } + + /** + * Replaces the contents of this list with {@code tasks}. + * {@code tasks} must not contain duplicate tasks. + */ + public void setTasks(List tasks) { + requireAllNonNull(tasks); + if (!tasksAreUnique(tasks)) { + throw new DuplicateTaskException(); + } + + internalList.setAll(tasks); + } + + /** + * Returns the backing list as an unmodifiable {@code ObservableList}. + */ + public ObservableList asUnmodifiableObservableList() { + return internalUnmodifiableList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof UniqueTaskList)) { + return false; + } + + UniqueTaskList otherUniqueTaskList = (UniqueTaskList) other; + return internalList.equals(otherUniqueTaskList.internalList); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + + @Override + public String toString() { + return internalList.toString(); + } + + /** + * Returns true if {@code persons} contains only unique persons. + */ + private boolean tasksAreUnique(List tasks) { + for (int i = 0; i < tasks.size() - 1; i++) { + for (int j = i + 1; j < tasks.size(); j++) { + if (tasks.get(i).isSameTask(tasks.get(j))) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java b/src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java new file mode 100644 index 00000000000..851d40b560b --- /dev/null +++ b/src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java @@ -0,0 +1,12 @@ +package seedu.address.model.task.exceptions; + + +/** + * Signals that the operation will result in duplicate Tasks (Tasks are considered duplicates if they have the same + * description). + */ +public class DuplicateTaskException extends RuntimeException { + public DuplicateTaskException() { + super("Operation would result in duplicate tasks"); + } +} diff --git a/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java b/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java new file mode 100644 index 00000000000..ecc8e354948 --- /dev/null +++ b/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java @@ -0,0 +1,10 @@ +package seedu.address.model.task.exceptions; + +/** + * Signals that the operation is unable to find the specified task. + */ +public class TaskNotFoundException extends RuntimeException { + public TaskNotFoundException() { + super("Task does not exist."); + } +} \ No newline at end of file From d00ad7ac3c51c8a31a6e28d727606b7e74935117 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 00:36:19 +0800 Subject: [PATCH 02/25] Add JsonAdapted classes for tasks --- .../address/storage/JsonAdaptedDeadline.java | 40 +++++++++++++++++ .../address/storage/JsonAdaptedEvent.java | 43 +++++++++++++++++++ .../address/storage/JsonAdaptedTask.java | 20 +++++++++ .../address/storage/JsonAdaptedTodo.java | 38 ++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 src/main/java/seedu/address/storage/JsonAdaptedDeadline.java create mode 100644 src/main/java/seedu/address/storage/JsonAdaptedEvent.java create mode 100644 src/main/java/seedu/address/storage/JsonAdaptedTask.java create mode 100644 src/main/java/seedu/address/storage/JsonAdaptedTodo.java diff --git a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java new file mode 100644 index 00000000000..460f10b5788 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java @@ -0,0 +1,40 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import seedu.address.model.task.Deadline; + +/** + * Jackson-friendly version of {@link Deadline}. + */ +public class JsonAdaptedDeadline extends JsonAdaptedTask { + + private final String by; + + /** + * Constructs a {@code JsonAdaptedDeadline} with the given {@code description} and {@code by}. + */ + @JsonCreator + public JsonAdaptedDeadline(@JsonProperty("description") String description, + @JsonProperty("isDone") Boolean isDone, + @JsonProperty("by") String by) { + super(description, isDone); + this.by = by; + } + + /** + * Converts a given {@code Deadline} into this class for Jackson use. + */ + public JsonAdaptedDeadline(Deadline source) { + super(source.getDescription(), source.getIsDone()); + by = source.getBy().toString(); + } + + /** + * Converts this Jackson-friendly adapted Deadline object into the model's {@code Deadline} object. + */ + public Deadline toModelType() { + return new Deadline(description, by); + } +} + diff --git a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java new file mode 100644 index 00000000000..8bfd7268cca --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java @@ -0,0 +1,43 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import seedu.address.model.task.Event; + +/** + * Jackson-friendly version of {@link Event}. + */ +public class JsonAdaptedEvent extends JsonAdaptedTask { + private final String from; + private final String to; + + /** + * Constructs a {@code JsonAdaptedEvent} with the given {@code description} and {@code from} and {@code to}. + */ + @JsonCreator + public JsonAdaptedEvent(@JsonProperty("description") String description, + @JsonProperty("isDone") boolean isDone, + @JsonProperty("from") String from, + @JsonProperty("to") String to) { + super(description, isDone); + this.from = from; + this.to = to; + } + + /** + * Converts a given {@code Event} into this class for Jackson use. + */ + public JsonAdaptedEvent(Event source) { + super(source.getDescription(), source.getIsDone()); + from = source.getFrom().toString(); + to = source.getTo().toString(); + } + + /** + * Converts this Jackson-friendly adapted Event object into the model's {@code Event} object. + */ + public Event toModelType() { + return new Event(description, from, to); + } +} + diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java new file mode 100644 index 00000000000..f9ac4979440 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java @@ -0,0 +1,20 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import seedu.address.model.task.Task; + +public abstract class JsonAdaptedTask { + + protected final String description; + protected final boolean isDone; + + @JsonCreator + public JsonAdaptedTask(@JsonProperty("description") String description, + @JsonProperty("isDone") boolean isDone) { + this.description = description; + this.isDone = isDone; + } + + public abstract Task toModelType(); +} \ No newline at end of file diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java new file mode 100644 index 00000000000..82e1ec027ab --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java @@ -0,0 +1,38 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Todo; + +/** + * Jackson-friendly version of {@link Todo}. + */ +public class JsonAdaptedTodo extends JsonAdaptedTask { + + /** + * Constructs a {@code JsonAdaptedTodo} with the given {@code description}. + */ + @JsonCreator + public JsonAdaptedTodo(@JsonProperty("description") String description, + @JsonProperty("isDone") boolean isDone) { + super(description, isDone); + } + + /** + * Converts a given {@code Todo} into this class for Jackson use. + */ + public JsonAdaptedTodo(Todo source) { + super(source.getDescription(), source.getIsDone()); + } + + /** + * Converts this Jackson-friendly adapted Todo object into the model's {@code Todo} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted todo task. + */ + public Todo toModelType() { + return new Todo(description); + } +} + From 04329c61b515ee89c8d0e0fa68a165f2e4984ae8 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:43:53 +0800 Subject: [PATCH 03/25] Create TaskCard, TaskListPanel and fxml files --- src/main/java/seedu/address/ui/TaskCard.java | 48 +++++++++++++++++++ .../java/seedu/address/ui/TaskListPanel.java | 48 +++++++++++++++++++ src/main/resources/view/TaskListCard.fxml | 47 ++++++++++++++++++ src/main/resources/view/TaskListPanel.fxml | 8 ++++ 4 files changed, 151 insertions(+) create mode 100644 src/main/java/seedu/address/ui/TaskCard.java create mode 100644 src/main/java/seedu/address/ui/TaskListPanel.java create mode 100644 src/main/resources/view/TaskListCard.fxml create mode 100644 src/main/resources/view/TaskListPanel.fxml diff --git a/src/main/java/seedu/address/ui/TaskCard.java b/src/main/java/seedu/address/ui/TaskCard.java new file mode 100644 index 00000000000..349fb2fedce --- /dev/null +++ b/src/main/java/seedu/address/ui/TaskCard.java @@ -0,0 +1,48 @@ +package seedu.address.ui; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.Task; + +/** + * A UI component that displays information of a {@code Task}. + */ +public class TaskCard extends UiPart { + + private static final String FXML = "TaskListCard.fxml"; + + public final Task task; + + @FXML + private HBox cardPane; + @FXML + private Label description; + @FXML + private Label id; + @FXML + private Label date; + @FXML + private Label isDone; + /** + * Creates a {@code TaskCard} with the given {@code Task} and index to display. + */ + public TaskCard(Task task, int displayedIndex) { + super(FXML); + this.task = task; + id.setText(displayedIndex + ". "); + description.setText(task.getDescription()); + + if (task instanceof Deadline) { + date.setText("By: " + ((Deadline) task).getBy().toString()); + } else if (task instanceof Event) { + date.setText(("From: " + ((Event) task).getFrom() + " to " + ((Event) task).getTo())); + } + + isDone.setText(task.getIsDone() ? "Completed" : "Incomplete"); + } +} + diff --git a/src/main/java/seedu/address/ui/TaskListPanel.java b/src/main/java/seedu/address/ui/TaskListPanel.java new file mode 100644 index 00000000000..1c4b2e2ffb9 --- /dev/null +++ b/src/main/java/seedu/address/ui/TaskListPanel.java @@ -0,0 +1,48 @@ +package seedu.address.ui; + +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.layout.Region; +import seedu.address.commons.core.LogsCenter; +import seedu.address.model.task.Task; + +/** + * Panel containing the list of tasks. + */ +public class TaskListPanel extends UiPart { + private static final String FXML = "TaskListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(TaskListPanel.class); + + @FXML + private ListView taskListView; + + /** + * Creates a {@code TaskListPanel} with the given {@code ObservableList}. + */ + public TaskListPanel(ObservableList taskList) { + super(FXML); + taskListView.setItems(taskList); + taskListView.setCellFactory(listView -> new TaskListViewCell()); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Task} using a {@code TaskCard}. + */ + class TaskListViewCell extends ListCell { + @Override + protected void updateItem(Task task, boolean empty) { + super.updateItem(task, empty); + + if (empty || task == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new TaskCard(task, getIndex() + 1).getRoot()); + } + } + } +} diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml new file mode 100644 index 00000000000..b7808532b03 --- /dev/null +++ b/src/main/resources/view/TaskListCard.fxml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/TaskListPanel.fxml b/src/main/resources/view/TaskListPanel.fxml new file mode 100644 index 00000000000..9753448ffdb --- /dev/null +++ b/src/main/resources/view/TaskListPanel.fxml @@ -0,0 +1,8 @@ + + + + + + + + From 111ea0265a92fca791da8e173be614dae59da576 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:46:12 +0800 Subject: [PATCH 04/25] Add parsing logic for Task related commands --- .../java/seedu/address/logic/Messages.java | 18 +++ .../logic/parser/CreateTaskCommandParser.java | 52 +++++++ .../logic/parser/DeleteTaskCommandParser.java | 29 ++++ .../address/logic/parser/ParserUtil.java | 132 ++++++++++++++++++ .../seedu/address/model/task/ParsedTask.java | 19 +++ 5 files changed, 250 insertions(+) create mode 100644 src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java create mode 100644 src/main/java/seedu/address/logic/parser/DeleteTaskCommandParser.java create mode 100644 src/main/java/seedu/address/model/task/ParsedTask.java diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java index 6d4eb530dd4..9630623ee42 100644 --- a/src/main/java/seedu/address/logic/Messages.java +++ b/src/main/java/seedu/address/logic/Messages.java @@ -8,6 +8,7 @@ import seedu.address.logic.parser.Prefix; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -18,6 +19,20 @@ 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 MESSAGE_INVALID_TASK_DISPLAYED_INDEX = "The task index provided is invalid"; + public static final String MESSAGE_INVALID_DATE_FORMAT = "Invalid date format. Expected format: yyyy-MM-dd"; + + public static final String MESSAGE_INVALID_TASK_TYPE = "Unknown task type: %1$s. " + + "Expected one of: todo, deadline, event."; + + public static final String MESSAGE_INVALID_DEADLINE_FORMAT = "Invalid deadline format. " + + "Usage: create-task tk/deadline [description] /by [date]"; + public static final String MESSAGE_INVALID_EVENT_FORMAT = "Invalid event format." + + " Usage: create-task tk/event [description] /from [start] /to [end]"; + + public static final String MESSAGE_INCOMPLETE_TASK_DESCRIPTION = "Task description is incomplete. " + + "Expected format: tk/[task type] [task details]."; + public static final String MESSAGE_TO_BEFORE_FROM_INVALID = "\"From\" date must be before \"To\" date."; public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; public static final String MESSAGE_DUPLICATE_FIELDS = "Multiple values specified for the following single-valued field(s): "; @@ -77,4 +92,7 @@ public static String format(Wedding wedding) { return wedding.getWeddingName().toString(); } + public static String format(Task task) { + return task.getDescription(); + } } diff --git a/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java new file mode 100644 index 00000000000..7c1e0c6da69 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.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_TASK; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import seedu.address.logic.commands.CreateTaskCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.task.Task; + +/** + * Parses input arguments and creates a new CreateTaskCommand object + */ +public class CreateTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the CreateTaskCommand + * and returns an CreateTaskCommand object for execution. + * @throws ParseException if the user input does not conform to the expected format + */ + public CreateTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_TASK); + + if (!arePrefixesPresent(argMultimap, PREFIX_TASK)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CreateTaskCommand.MESSAGE_USAGE)); + } + + List taskDescriptions = argMultimap.getAllValues(PREFIX_TASK); + if (taskDescriptions.isEmpty()|| taskDescriptions.stream().anyMatch(String::isBlank)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CreateTaskCommand.MESSAGE_USAGE)); + } + + // Parse the tasks from the task descriptions + Set tasks = ParserUtil.parseTasks(taskDescriptions); + + return new CreateTaskCommand(new HashSet<>(tasks)); + } + + /** + * 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/DeleteTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteTaskCommandParser.java new file mode 100644 index 00000000000..5839657bd80 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/DeleteTaskCommandParser.java @@ -0,0 +1,29 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.DeleteTaskCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new DeleteTaskCommand object + */ +public class DeleteTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the DeleteTaskCommand + * and returns a DeleteTaskCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteTaskCommand parse(String args) throws ParseException { + try { + Index index = ParserUtil.parseIndex(args); + return new DeleteTaskCommand(index); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTaskCommand.MESSAGE_USAGE), pe); + } + } + +} diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index aea1a72569d..588597ca40d 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -2,12 +2,17 @@ import static java.util.Objects.requireNonNull; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; import seedu.address.commons.core.index.Index; import seedu.address.commons.util.StringUtil; +import seedu.address.logic.Messages; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.person.Address; import seedu.address.model.person.Email; @@ -15,6 +20,11 @@ import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.ParsedTask; +import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; import seedu.address.model.wedding.Wedding; import seedu.address.model.wedding.WeddingName; @@ -24,6 +34,7 @@ public class ParserUtil { public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer."; + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); /** * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be @@ -122,6 +133,127 @@ public static Set parseTags(Collection tags) throws ParseException return tagSet; } + /** + * Parses a task description to determine the task type and details. + * + * @throws ParseException if the task format is invalid. + */ + public static Task parseTask(String taskDescription) throws ParseException { + requireNonNull(taskDescription); + ParsedTask parsedTask = parseTaskTypeAndDetails(taskDescription); + String taskType = parsedTask.getTaskType(); + String taskDetails = parsedTask.getTaskDetails(); + + switch (taskType) { + case "todo": + return parseTodoTask(taskDetails); + case "deadline": + return parseDeadlineTask(taskDetails); + case "event": + return parseEventTask(taskDetails); + default: + throw new ParseException(String.format(Messages.MESSAGE_INVALID_TASK_TYPE, taskType)); + } + } + + /** + * Parses {@code Collection tags} into a {@code Set}. + */ + public static Set parseTasks(List taskDescriptions) throws ParseException { + final Set taskSet = new HashSet<>(); + for (String taskDescription : taskDescriptions) { + taskSet.add(parseTask(taskDescription)); + } + return taskSet; + } + + /** + * Parses the task description to extract the task type and task details. + * + * @throws ParseException if the format is invalid. + */ + private static ParsedTask parseTaskTypeAndDetails(String taskDescription) throws ParseException { + requireNonNull(taskDescription); + String[] tokens = taskDescription.split("\\s+", 2); + + if (tokens.length < 2) { + throw new ParseException(Messages.MESSAGE_INCOMPLETE_TASK_DESCRIPTION); + } + + String taskType = tokens[0].toLowerCase(); + String taskDetails = tokens[1].trim(); + + return new ParsedTask(taskType, taskDetails); + } + + + private static Todo parseTodoTask(String taskDetails) { + return new Todo(taskDetails.trim()); + } + + private static Deadline parseDeadlineTask(String taskDetails) throws ParseException { + String[] deadlineParts = taskDetails.split("/by ", 2); + // Check if both description and deadline are present + if (deadlineParts.length < 2 || deadlineParts[0].trim().isEmpty()) { + throw new ParseException(Messages.MESSAGE_INVALID_DEADLINE_FORMAT); + } + String description = deadlineParts[0].trim(); + String byDate = deadlineParts[1].trim(); + + validateDateFormat(byDate); + return new Deadline(description, byDate); + } + + private static Event parseEventTask(String taskDetails) throws ParseException { + String[] eventParts = taskDetails.split("/from", 2); + if (eventParts.length < 2 || !eventParts[1].contains("/to")) { + throw new ParseException(Messages.MESSAGE_INVALID_EVENT_FORMAT); + } + String description = eventParts[0].trim(); + String[] dateParts = eventParts[1].split("/to", 2); + String startDateStr = dateParts[0].trim(); + String endDateStr = dateParts[1].trim(); + validateDateFormat(startDateStr, endDateStr); + + return new Event(description, startDateStr, endDateStr); + } + + /** + * Validates the date format against the predefined pattern (yyyy-MM-dd). + * + * @throws ParseException if the date format is invalid. + */ + private static void validateDateFormat(String date) throws ParseException { + try { + LocalDate.parse(date, DATE_FORMATTER); + } catch (DateTimeParseException e) { + throw new ParseException(Messages.MESSAGE_INVALID_DATE_FORMAT); + } + } + + /** + * Validates the date format for two dates and checks if the "from" date is before the "to" date. + * + * @throws ParseException if the date format is invalid or "from" date is not before "to" date. + */ + private static void validateDateFormat(String fromDate, String toDate) throws ParseException { + LocalDate from; + LocalDate to; + try { + from = LocalDate.parse(fromDate, DATE_FORMATTER); + to = LocalDate.parse(toDate, DATE_FORMATTER); + } catch (DateTimeParseException e) { + throw new ParseException(Messages.MESSAGE_INVALID_DATE_FORMAT); + } + + if (!from.isBefore(to)) { + throw new ParseException(Messages.MESSAGE_TO_BEFORE_FROM_INVALID); + } + } + + + + /** * Parses {@code String} wedding into {@code Wedding} object. * Leading and trailing whitespaces will be trimmed. diff --git a/src/main/java/seedu/address/model/task/ParsedTask.java b/src/main/java/seedu/address/model/task/ParsedTask.java new file mode 100644 index 00000000000..e384c8fe79b --- /dev/null +++ b/src/main/java/seedu/address/model/task/ParsedTask.java @@ -0,0 +1,19 @@ +package seedu.address.model.task; + +public class ParsedTask { + private final String taskType; + private final String taskDetails; + + public ParsedTask(String taskType, String taskDetails) { + this.taskType = taskType; + this.taskDetails = taskDetails; + } + + public String getTaskType() { + return taskType; + } + + public String getTaskDetails() { + return taskDetails; + } +} From 3215041c0e2d460fc085eaf0570de965afc2a3d8 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:47:30 +0800 Subject: [PATCH 05/25] Add create, delete and list Task command classees --- .../logic/commands/CreateTaskCommand.java | 79 +++++++++++++++++++ .../logic/commands/DeleteTaskCommand.java | 69 ++++++++++++++++ .../logic/commands/ListTaskCommand.java | 23 ++++++ 3 files changed, 171 insertions(+) create mode 100644 src/main/java/seedu/address/logic/commands/CreateTaskCommand.java create mode 100644 src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java create mode 100644 src/main/java/seedu/address/logic/commands/ListTaskCommand.java diff --git a/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java b/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java new file mode 100644 index 00000000000..8155259fc5c --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java @@ -0,0 +1,79 @@ +package seedu.address.logic.commands; + + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK; + +import java.util.HashSet; + +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.task.Task; + +/** + * Adds a Task to the address book. + */ +public class CreateTaskCommand extends Command { + + public static final String COMMAND_WORD = "create-task"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Creates a task in the address book. \n" + + "Parameters: " + + PREFIX_TASK + "TASK_TYPE TASK_DESCRIPTION [ADDITIONAL_FIELDS]\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_TASK + "todo Setup venue decorations\n" + + COMMAND_WORD + " " + + PREFIX_TASK + "deadline Submit proposal /by 2024-10-31"; + + public static final String MESSAGE_SUCCESS = "New task added: %1$s"; + + public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the address book"; + + private final HashSet tasksToAdd; + + /** + * Creates a CreateTaskCommand to add the specified {@code task} to the Wedlinker + * @param task The {@code task} to be added to the Wedlinker + */ + public CreateTaskCommand(HashSet task) { + requireNonNull(task); + tasksToAdd = task; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + for (Task task : tasksToAdd) { + if (model.hasTask(task)) { + throw new CommandException(MESSAGE_DUPLICATE_TASK); + } + model.addTask(task); + } + + return new CommandResult(String.format(MESSAGE_SUCCESS, tasksToAdd)); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + // null case handled by instanceof + if (!(obj instanceof CreateTaskCommand)) { + return false; + } + + CreateTaskCommand otherCreateTaskCommand = (CreateTaskCommand) obj; + return tasksToAdd.equals(otherCreateTaskCommand.tasksToAdd); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("taskToAdd", tasksToAdd) + .toString(); + } +} diff --git a/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java new file mode 100644 index 00000000000..a627dcc61a2 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java @@ -0,0 +1,69 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.task.Task; + +/** + * Deletes a task identified using it's displayed index from the address book. + */ +public class DeleteTaskCommand extends Command { + + public static final String COMMAND_WORD = "delete-task"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the task identified by the index number used in the displayed task list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted task: %1$s"; + + private final Index targetIndex; + + public DeleteTaskCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredTaskList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + Task taskToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteTask(taskToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, Messages.format(taskToDelete))); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof DeleteTaskCommand)) { + return false; + } + + DeleteTaskCommand otherDeleteTaskCommand = (DeleteTaskCommand) other; + return targetIndex.equals(otherDeleteTaskCommand.targetIndex); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("targetIndex", targetIndex) + .toString(); + } +} \ No newline at end of file diff --git a/src/main/java/seedu/address/logic/commands/ListTaskCommand.java b/src/main/java/seedu/address/logic/commands/ListTaskCommand.java new file mode 100644 index 00000000000..1310066a48b --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ListTaskCommand.java @@ -0,0 +1,23 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS; + +import seedu.address.model.Model; + +/** + * Lists all tasks in the address book to the user. + */ +public class ListTaskCommand extends Command { + + public static final String COMMAND_WORD = "list-task"; + + public static final String MESSAGE_SUCCESS = "Listed all tasks"; + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + return new CommandResult(MESSAGE_SUCCESS, false, false, false, true); + } +} From cb7f2e203000c641626fb0feedc832bcb8c3de18 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:49:17 +0800 Subject: [PATCH 06/25] Add methods for retrieving Task list in Logic --- src/main/java/seedu/address/logic/Logic.java | 4 ++++ src/main/java/seedu/address/logic/LogicManager.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java index 92cd8fa605a..5e1f29acc2b 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/address/logic/Logic.java @@ -9,6 +9,7 @@ import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.person.Person; +import seedu.address.model.task.Task; /** * API of the Logic component @@ -33,6 +34,9 @@ public interface Logic { /** Returns an unmodifiable view of the filtered list of persons */ ObservableList getFilteredPersonList(); + /** Returns an unmodifiable view of the filtered list of tasks */ + ObservableList getFilteredTaskList(); + /** * Returns the user prefs' address book file path. */ diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 5aa3b91c7d0..7f8e6e46399 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -16,6 +16,7 @@ import seedu.address.model.Model; import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.person.Person; +import seedu.address.model.task.Task; import seedu.address.storage.Storage; /** @@ -71,6 +72,11 @@ public ObservableList getFilteredPersonList() { return model.getFilteredPersonList(); } + @Override + public ObservableList getFilteredTaskList() { + return model.getFilteredTaskList(); + } + @Override public Path getAddressBookFilePath() { return model.getAddressBookFilePath(); From cc34e4623b1e9114dfadb5f68f8ac144cfc7c42c Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:54:11 +0800 Subject: [PATCH 07/25] Add support for saving, loading and listing Tasks --- .../address/logic/commands/CommandResult.java | 27 +++++-- .../address/logic/commands/ExitCommand.java | 2 +- .../address/logic/commands/HelpCommand.java | 2 +- .../address/logic/commands/ListCommand.java | 2 +- .../java/seedu/address/model/AddressBook.java | 72 +++++++++++++++++++ src/main/java/seedu/address/model/Model.java | 35 +++++++++ .../address/model/ReadOnlyAddressBook.java | 7 ++ .../java/seedu/address/ui/MainWindow.java | 26 +++++++ 8 files changed, 166 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java index 249b6072d0d..b8f84e900ca 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/address/logic/commands/CommandResult.java @@ -19,13 +19,21 @@ public class CommandResult { /** The application should exit. */ private final boolean exit; + /** The person list should be shown. */ + private final boolean showPersonList; + + /** The task list should be shown. */ + private final boolean showTaskList; + /** * Constructs a {@code CommandResult} with the specified fields. */ - public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) { + public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean showPersonList, boolean showTaskList) { this.feedbackToUser = requireNonNull(feedbackToUser); this.showHelp = showHelp; this.exit = exit; + this.showPersonList = showPersonList; + this.showTaskList = showTaskList; } /** @@ -33,7 +41,7 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) { * and other fields set to their default value. */ public CommandResult(String feedbackToUser) { - this(feedbackToUser, false, false); + this(feedbackToUser, false, false, false,false); } public String getFeedbackToUser() { @@ -44,6 +52,13 @@ public boolean isShowHelp() { return showHelp; } + public boolean isShowPersonList() { + return showPersonList; + } + + public boolean isShowTaskList() { + return showTaskList; + } public boolean isExit() { return exit; } @@ -62,12 +77,14 @@ public boolean equals(Object other) { CommandResult otherCommandResult = (CommandResult) other; return feedbackToUser.equals(otherCommandResult.feedbackToUser) && showHelp == otherCommandResult.showHelp - && exit == otherCommandResult.exit; + && exit == otherCommandResult.exit + && showPersonList == otherCommandResult.showPersonList + && showTaskList == otherCommandResult.showTaskList; } @Override public int hashCode() { - return Objects.hash(feedbackToUser, showHelp, exit); + return Objects.hash(feedbackToUser, showHelp, exit, showPersonList, showTaskList); } @Override @@ -76,6 +93,8 @@ public String toString() { .add("feedbackToUser", feedbackToUser) .add("showHelp", showHelp) .add("exit", exit) + .add("showPersonList", showPersonList) + .add("showTaskList", showTaskList) .toString(); } diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java index 3dd85a8ba90..7874f9ccfc1 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java @@ -13,7 +13,7 @@ public class ExitCommand extends Command { @Override public CommandResult execute(Model model) { - return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true); + return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false, false); } } diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java index bf824f91bd0..492a3633fbd 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java @@ -16,6 +16,6 @@ public class HelpCommand extends Command { @Override public CommandResult execute(Model model) { - return new CommandResult(SHOWING_HELP_MESSAGE, true, false); + return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false, false); } } diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java index 84be6ad2596..b67f21cf018 100644 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListCommand.java @@ -19,6 +19,6 @@ public class ListCommand extends Command { public CommandResult execute(Model model) { requireNonNull(model); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(MESSAGE_SUCCESS); + return new CommandResult(MESSAGE_SUCCESS, false, false, true, false); } } diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java index d7100716686..3f086281e1b 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/seedu/address/model/AddressBook.java @@ -11,6 +11,8 @@ import seedu.address.model.person.UniquePersonList; import seedu.address.model.tag.Tag; import seedu.address.model.tag.UniqueTagList; +import seedu.address.model.task.Task; +import seedu.address.model.task.UniqueTaskList; import seedu.address.model.wedding.UniqueWeddingList; import seedu.address.model.wedding.Wedding; @@ -22,6 +24,7 @@ public class AddressBook implements ReadOnlyAddressBook { private final UniquePersonList persons; private final UniqueTagList tags; + private final UniqueTaskList tasks; private final UniqueWeddingList weddings; /* @@ -34,6 +37,7 @@ public class AddressBook implements ReadOnlyAddressBook { { persons = new UniquePersonList(); tags = new UniqueTagList(); + tasks = new UniqueTaskList(); weddings = new UniqueWeddingList(); } @@ -47,6 +51,7 @@ public AddressBook(ReadOnlyAddressBook toBeCopied) { resetData(toBeCopied); initialiseTags(); initialiseWeddings(); + initialiseTasks(); } //// list overwrite operations @@ -60,6 +65,7 @@ public void resetData(ReadOnlyAddressBook newData) { setPersons(newData.getPersonList()); setTags(newData.getTagList()); setWeddings(newData.getWeddingList()); + setTasks(newData.getTaskList()); } /** @@ -78,6 +84,14 @@ public void setWeddings(List weddings) { this.weddings.setWeddings(weddings); } + /** + * Replaces the contents of the task list with {@code tasks}. + * {@code tasks} must not contain duplicate tasks. + */ + public void setTasks (List tasks) { + this.tasks.setTasks(tasks); + } + //// person-level operations /** @@ -134,6 +148,43 @@ public boolean hasTag(Tag tag) { return tags.contains(tag); } + + /** + * Adds a task to the Wedlinker. + * The task must not already exist in the Wedlinker. + * @param task A {@code Task} object to be added. + */ + public void addTask(Task task) { + tasks.add(task); + } + + /** + * Returns true if a task with the same description as {@code task} exists in the Wedlinker. + */ + public boolean hasTask(Task task) { + requireNonNull(task); + return tasks.contains(task); + } + + /** + * Replaces the given task {@code target} in the list with {@code editedTask}. + * {@code target} must exist in the address book. + * The tag identity of {@code editedTask} must not be the same as another existing task in the address book. + */ + public void setTask(Task target, Task editedTask) { + requireNonNull(editedTask); + tasks.setTask(target, editedTask); + } + + + /** + * Removes {@code key} from this {@code AddressBook}. + * {@code key} must exist in the address book. + */ + public void removeTask(Task key) { + tasks.remove(key); + } + /** * Adds a wedding to the Wedlinker * The wedding must not already exist in the Wedlinker @@ -143,6 +194,7 @@ public void addWedding(Wedding wedding) { weddings.add(wedding); } + /** * Replaces the given wedding {@code target} in the list with {@code editedWedding}. * {@code target} must exist in the address book. @@ -212,6 +264,21 @@ public void initialiseTags() { } } + /** + * Creates any tasks that is attached to a person but not initialised. + * This function is only to be used when loading from Storage. + */ + public void initialiseTasks() { + for (Person person : persons) { + Set taskForPerson = person.getTasks(); + for (Task task : taskForPerson) { + if (!this.hasTask(task)) { + this.addTask(task); + } + } + } + } + /** * Creates any weddings attached to a person but not initialised. * This function is only to be used when loading from Storage. @@ -246,6 +313,11 @@ public ObservableList getTagList() { return tags.asUnmodifiableObservableList(); } + @Override + public ObservableList getTaskList() { + return tasks.asUnmodifiableObservableList(); + } + @Override public ObservableList getWeddingList() { return weddings.asUnmodifiableObservableList(); diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 5899df510bb..daa3afc407d 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -7,6 +7,7 @@ import seedu.address.commons.core.GuiSettings; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -17,6 +18,7 @@ public interface Model { Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true; Predicate PREDICATE_SHOW_ALL_TAGS = unused -> true; Predicate PREDICATE_SHOW_ALL_WEDDINGS = unused -> true; + Predicate PREDICATE_SHOW_ALL_TASKS = unused -> true; /** * Replaces user prefs data with the data in {@code userPrefs}. @@ -123,6 +125,39 @@ public interface Model { */ void deleteTag(Tag toDelete); + /** + * Returns true if a task with the same name as {@code toAdd} exists in the Wedlinker. + */ + boolean hasTask(Task toAdd); + + /** + * Adds the given task. + * {@code task} must not already exist in the address book. + */ + void addTask(Task toAdd); + + /** Returns an unmodifiable view of the filtered task list */ + ObservableList getFilteredTaskList(); + + /** + * Replaces the given Task {@code target} with {@code editedTask}. + * {@code target} must exist in the address book. + * The task identity of {@code editedTask} must not be the same as another existing Task in the address book. + */ + void setTask(Task target, Task editedTask); + + /** + * Deletes the given task. + * The task must exist in the Wedlinker. + */ + void deleteTask(Task toDelete); + + /** + * Updates the filter of the filtered task list to filter by the given {@code predicate}. + * @throws NullPointerException if {@code predicate} is null. + */ + void updateFilteredTaskList(Predicate predicate); + /** * Returns true if a wedding with the same name as {@code toAdd} exists in the Wedlinker. * @param toAdd A {@code Wedding} object, will be checked to see if the model already has this. diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java index d0b216efe1c..f6e53267d2f 100644 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java @@ -3,6 +3,7 @@ import javafx.collections.ObservableList; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -22,6 +23,12 @@ public interface ReadOnlyAddressBook { */ ObservableList getTagList(); + /** + * Returns an unmodifiable view of the tasks list. + * This list will not contain any duplicate tasks. + */ + ObservableList getTaskList(); + /** * Returns an unmodifiable view of the weddings list. * This list will not contain any duplicate weddings. diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 79e74ef37c0..dc91ab2f3b3 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -32,6 +32,7 @@ public class MainWindow extends UiPart { // Independent Ui parts residing in this Ui container private PersonListPanel personListPanel; + private TaskListPanel taskListPanel; private ResultDisplay resultDisplay; private HelpWindow helpWindow; @@ -113,6 +114,8 @@ void fillInnerParts() { personListPanel = new PersonListPanel(logic.getFilteredPersonList()); personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + taskListPanel = new TaskListPanel(logic.getFilteredTaskList()); + resultDisplay = new ResultDisplay(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); @@ -123,6 +126,22 @@ void fillInnerParts() { commandBoxPlaceholder.getChildren().add(commandBox.getRoot()); } + /** + * Shows the person list panel. + */ + public void showPersonList() { + personListPanelPlaceholder.getChildren().clear(); + personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + } + + /** + * Shows the task list panel. + */ + public void showTaskList() { + personListPanelPlaceholder.getChildren().clear(); + personListPanelPlaceholder.getChildren().add(taskListPanel.getRoot()); + } + /** * Sets the default size based on {@code guiSettings}. */ @@ -186,6 +205,13 @@ private CommandResult executeCommand(String commandText) throws CommandException handleExit(); } + // Switch panels based on the command result + if (commandResult.isShowPersonList()) { + showPersonList(); + } else if (commandResult.isShowTaskList()) { + showTaskList(); + } + return commandResult; } catch (CommandException | ParseException e) { logger.info("An error occurred while executing command: " + commandText); From 722e001dc23ce99f9b1670f80dab4e9e315c25f6 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:55:48 +0800 Subject: [PATCH 08/25] Added tasks as field in Json --- .../address/storage/JsonAdaptedPerson.java | 38 ++++++++++++++-- .../address/storage/JsonAdaptedTask.java | 13 ++++++ .../storage/JsonSerializableAddressBook.java | 45 ++++++++++++++++++- 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index 989b6914e56..44d86d62cdc 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -8,7 +8,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.person.Address; import seedu.address.model.person.Email; @@ -16,6 +15,10 @@ import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; import seedu.address.model.wedding.Wedding; /** @@ -31,6 +34,7 @@ class JsonAdaptedPerson { private final String address; private final List tags = new ArrayList<>(); private final List weddings = new ArrayList<>(); + private final List tasks = new ArrayList<>(); /** * Constructs a {@code JsonAdaptedPerson} with the given person details. @@ -38,7 +42,7 @@ class JsonAdaptedPerson { @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tags") List tags, + @JsonProperty("tags") List tags, @JsonProperty("tasks") List tasks, @JsonProperty("weddings") List weddings) { this.name = name; this.phone = phone; @@ -47,9 +51,13 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone if (tags != null) { this.tags.addAll(tags); } + if (tasks != null) { + this.tasks.addAll(tasks); + } if (weddings != null) { this.weddings.addAll(weddings); } + } /** @@ -66,6 +74,24 @@ public JsonAdaptedPerson(Person source) { weddings.addAll(source.getWeddings().stream() .map(JsonAdaptedWedding::new) .collect(Collectors.toList())); + tasks.addAll(source.getTasks().stream() + .map(this::mapToJsonAdaptedTask) + .collect(Collectors.toList())); + } + + /** + * Helper function to map a Task to its corresponding JsonAdaptedTask subclass. + */ + private JsonAdaptedTask mapToJsonAdaptedTask(Task task) { + if (task instanceof Todo) { + return new JsonAdaptedTodo((Todo) task); + } else if (task instanceof Deadline) { + return new JsonAdaptedDeadline((Deadline) task); + } else if (task instanceof Event) { + return new JsonAdaptedEvent((Event) task); + } else { + throw new IllegalArgumentException("Unknown task type"); + } } /** @@ -76,11 +102,16 @@ public JsonAdaptedPerson(Person source) { public Person toModelType() throws IllegalValueException { final List personTags = new ArrayList<>(); final List personWeddings = new ArrayList<>(); + final List personTasks = new ArrayList<>(); for (JsonAdaptedTag tag : tags) { personTags.add(tag.toModelType()); } + for (JsonAdaptedTask task : tasks) { + personTasks.add(task.toModelType()); + } + for (JsonAdaptedWedding wedding : weddings) { if (!Wedding.isValidWeddingName(wedding.getWeddingName())) { throw new IllegalValueException(Wedding.MESSAGE_CONSTRAINTS); @@ -119,8 +150,9 @@ public Person toModelType() throws IllegalValueException { final Set modelTags = new HashSet<>(personTags); final Set modelWeddings = new HashSet<>(personWeddings); + final Set modelTasks = new HashSet<>(personTasks); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags, modelWeddings); + return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags, modelWeddings, modelTasks); } } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java index f9ac4979440..c948e148b10 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTask.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java @@ -2,8 +2,21 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import seedu.address.model.task.Task; + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, // Use the name of the class to differentiate types + include = JsonTypeInfo.As.PROPERTY, // Include type info as a property in the JSON + property = "type" // The name of the property in the JSON that will hold the type information +) +@JsonSubTypes({ + @JsonSubTypes.Type(value = JsonAdaptedTodo.class, name = "todo"), + @JsonSubTypes.Type(value = JsonAdaptedDeadline.class, name = "deadline"), + @JsonSubTypes.Type(value = JsonAdaptedEvent.class, name = "event") +}) public abstract class JsonAdaptedTask { protected final String description; diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java index 1ef393cc6a6..9d02a953fa8 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java @@ -8,12 +8,15 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; - import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.AddressBook; import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; import seedu.address.model.wedding.Wedding; /** @@ -25,10 +28,12 @@ class JsonSerializableAddressBook { public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; public static final String MESSAGE_DUPLICATE_TAG = "Tags list contains duplicate tag(s)."; public static final String MESSAGE_DUPLICATE_WEDDING = "Weddings list contains duplicate wedding(s)."; + public static final String MESSAGE_DUPLICATE_TASK = "Tasks list contains duplicate task(s)."; private final List persons = new ArrayList<>(); private final List tags = new ArrayList<>(); private final List weddings = new ArrayList<>(); + private final List tasks = new ArrayList<>(); /** * Constructs a {@code JsonSerializableAddressBook} with the given persons, tag, and weddings. @@ -37,10 +42,12 @@ class JsonSerializableAddressBook { public JsonSerializableAddressBook( @JsonProperty("persons") List persons, @JsonProperty("tags") List tags, - @JsonProperty("weddings") List weddings) { + @JsonProperty("weddings") List weddings, + @JsonProperty("tasks") List tasks) { this.persons.addAll(persons); this.tags.addAll(tags); this.weddings.addAll(weddings); + this.tasks.addAll(tasks); } /** @@ -52,6 +59,7 @@ public JsonSerializableAddressBook(ReadOnlyAddressBook source) { persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList())); tags.addAll(source.getTagList().stream().map(JsonAdaptedTag::new).collect(Collectors.toList())); weddings.addAll(source.getWeddingList().stream().map(JsonAdaptedWedding::new).collect(Collectors.toList())); + tasks.addAll(source.getTaskList().stream().map(this::mapToJsonAdaptedTask).collect(Collectors.toList()));; } /** @@ -75,6 +83,13 @@ public AddressBook toModelType() throws IllegalValueException { } addressBook.addTag(tag); } + for (JsonAdaptedTask jsonAdaptedTask : tasks) { + Task task = jsonAdaptedTask.toModelType(); + if (addressBook.hasTask(task)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_TASK); + } + addressBook.addTask(task); + } for (JsonAdaptedWedding jsonAdaptedWedding : weddings) { Wedding wedding = jsonAdaptedWedding.toModelType(); if (addressBook.hasWedding(wedding)) { @@ -88,6 +103,7 @@ public AddressBook toModelType() throws IllegalValueException { Person person = jsonAdaptedPerson.toModelType(); loadTags(addressBook, person); loadWeddings(addressBook, person); + loadTasks(addressBook, person); } return addressBook; } @@ -111,4 +127,29 @@ private void loadWeddings(AddressBook addressBook, Person person) { addressBook.addWedding(wedding); } } + + private void loadTasks(AddressBook addressBook, Person person) { + Set taskList = person.getTasks(); + for (Task task : taskList) { + if (addressBook.hasTask(task)) { + continue; + } + addressBook.addTask(task); + } + } + + /** + * Maps a given Task to its corresponding JsonAdaptedTask subclass. + */ + private JsonAdaptedTask mapToJsonAdaptedTask(Task task) { + if (task instanceof Todo) { + return new JsonAdaptedTodo((Todo) task); + } else if (task instanceof Deadline) { + return new JsonAdaptedDeadline((Deadline) task); + } else if (task instanceof Event) { + return new JsonAdaptedEvent((Event) task); + } else { + throw new IllegalArgumentException("Unknown task type"); + } + } } From ec4717fa5e2e4982a180ed0e59fc094f12d62f7d Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:56:43 +0800 Subject: [PATCH 09/25] Add task methods in ModelManager --- .../seedu/address/model/ModelManager.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index fd1eae552f4..ab093f222dd 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -13,6 +13,7 @@ import seedu.address.commons.core.LogsCenter; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -27,6 +28,8 @@ public class ModelManager implements Model { private final FilteredList filteredTags; private final FilteredList filteredWeddings; + private final FilteredList filteredTasks; + /** * Initializes a ModelManager with the given addressBook and userPrefs. */ @@ -40,6 +43,7 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); filteredTags = new FilteredList<>(this.addressBook.getTagList()); filteredWeddings = new FilteredList<>(this.addressBook.getWeddingList()); + filteredTasks = new FilteredList<>(this.addressBook.getTaskList()); } public ModelManager() { @@ -139,6 +143,28 @@ public void deleteTag(Tag target) { addressBook.removeTag(target); } + @Override + public void addTask(Task task) { + addressBook.addTask(task); + updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + } + @Override + public boolean hasTask(Task task) { + requireNonNull(task); + return addressBook.hasTask(task); + } + + @Override + public void setTask(Task target, Task editedTask) { + requireAllNonNull(target, editedTask); + addressBook.setTask(target, editedTask); + } + + @Override + public void deleteTask(Task target) { + addressBook.removeTask(target); + } + @Override public void addWedding(Wedding toAdd) { addressBook.addWedding(toAdd); @@ -196,6 +222,16 @@ public void updateFilteredTagList(Predicate predicate) { filteredTags.setPredicate(predicate); } + @Override + public ObservableList getFilteredTaskList() { + return filteredTasks; + } + + @Override + public void updateFilteredTaskList(Predicate predicate) { + requireNonNull(predicate); + filteredTasks.setPredicate(predicate); + } @Override public ObservableList getFilteredWeddingList() { return filteredWeddings; @@ -223,6 +259,7 @@ public boolean equals(Object other) { && userPrefs.equals(otherModelManager.userPrefs) && filteredPersons.equals(otherModelManager.filteredPersons) && filteredTags.equals(otherModelManager.filteredTags) + && filteredTasks.equals(otherModelManager.filteredTasks) && filteredWeddings.equals(otherModelManager.filteredWeddings); } } From e190ae4ead640eac8c3e0e5fff6b7ee642b61eb9 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:57:55 +0800 Subject: [PATCH 10/25] Modify other classes to ensure compatibility --- .../logic/commands/AssignWeddingCommand.java | 3 +- .../address/logic/commands/EditCommand.java | 23 ++++++++++++++- .../address/logic/commands/TagCommand.java | 3 +- .../commands/UnassignWeddingCommand.java | 3 +- .../address/logic/commands/UntagCommand.java | 3 +- .../logic/parser/AddCommandParser.java | 5 +++- .../seedu/address/model/person/Person.java | 21 +++++++++++--- .../address/model/util/SampleDataUtil.java | 28 +++++++++++++++---- 8 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/AssignWeddingCommand.java b/src/main/java/seedu/address/logic/commands/AssignWeddingCommand.java index 3c775dc0905..7c810bf251b 100644 --- a/src/main/java/seedu/address/logic/commands/AssignWeddingCommand.java +++ b/src/main/java/seedu/address/logic/commands/AssignWeddingCommand.java @@ -103,7 +103,8 @@ public CommandResult execute(Model model) throws CommandException { personToEdit.getEmail(), personToEdit.getAddress(), personToEdit.getTags(), - updatedWeddings); + updatedWeddings, + personToEdit.getTasks()); model.setPerson(personToEdit, editedPerson); model.updateFilteredPersonList(Model.PREDICATE_SHOW_ALL_PERSONS); diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index e20b0132d1f..9e543fe0c0d 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -28,6 +28,7 @@ import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -104,8 +105,9 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); Set updatedWeddings = editPersonDescriptor.getWeddings().orElse(personToEdit.getWeddings()); + Set updatedTasks = editPersonDescriptor.getTasks().orElse(personToEdit.getTasks()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags, updatedWeddings); + return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags, updatedWeddings, updatedTasks); } @Override @@ -143,6 +145,7 @@ public static class EditPersonDescriptor { private Address address; private Set tags; private Set weddings; + private Set tasks; public EditPersonDescriptor() {} @@ -157,6 +160,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { setAddress(toCopy.address); setTags(toCopy.tags); setWeddings(toCopy.weddings); + setTasks(toCopy.tasks); } /** @@ -206,6 +210,23 @@ public void setTags(Set tags) { this.tags = (tags != null) ? new HashSet<>(tags) : null; } + /** + * Returns an unmodifiable task set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + * Returns {@code Optional#empty()} if {@code tasks} is null. + */ + public Optional> getTasks() { + return (tasks != null) ? Optional.of(Collections.unmodifiableSet(tasks)) : Optional.empty(); + } + + /** + * Sets {@code tasks} to this object's {@code tasks}. + * A defensive copy of {@code tasks} is used internally. + */ + public void setTasks(Set tasks) { + this.tasks = (tasks != null) ? new HashSet<>(tasks) : null; + } + /** * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} * if modification is attempted. diff --git a/src/main/java/seedu/address/logic/commands/TagCommand.java b/src/main/java/seedu/address/logic/commands/TagCommand.java index 372b0b331bb..7719c444d6a 100644 --- a/src/main/java/seedu/address/logic/commands/TagCommand.java +++ b/src/main/java/seedu/address/logic/commands/TagCommand.java @@ -91,7 +91,8 @@ public CommandResult execute(Model model) throws CommandException { personToEdit.getEmail(), personToEdit.getAddress(), updatedTags, - personToEdit.getWeddings()); + personToEdit.getWeddings(), + personToEdit.getTasks()); model.setPerson(personToEdit, editedPerson); model.updateFilteredPersonList(Model.PREDICATE_SHOW_ALL_PERSONS); diff --git a/src/main/java/seedu/address/logic/commands/UnassignWeddingCommand.java b/src/main/java/seedu/address/logic/commands/UnassignWeddingCommand.java index 666783c5775..fa2f7c9fd3d 100644 --- a/src/main/java/seedu/address/logic/commands/UnassignWeddingCommand.java +++ b/src/main/java/seedu/address/logic/commands/UnassignWeddingCommand.java @@ -88,7 +88,8 @@ public CommandResult execute(Model model) throws CommandException { personToEdit.getEmail(), personToEdit.getAddress(), personToEdit.getTags(), - updatedWeddings); + updatedWeddings, + personToEdit.getTasks()); model.setPerson(personToEdit, editedPerson); model.updateFilteredPersonList(Model.PREDICATE_SHOW_ALL_PERSONS); diff --git a/src/main/java/seedu/address/logic/commands/UntagCommand.java b/src/main/java/seedu/address/logic/commands/UntagCommand.java index 8a40a94b062..513ff0ba5e0 100644 --- a/src/main/java/seedu/address/logic/commands/UntagCommand.java +++ b/src/main/java/seedu/address/logic/commands/UntagCommand.java @@ -92,7 +92,8 @@ public CommandResult execute(Model model) throws CommandException { personToEdit.getEmail(), personToEdit.getAddress(), updatedTags, - personToEdit.getWeddings()); + personToEdit.getWeddings(), + personToEdit.getTasks()); model.setPerson(personToEdit, editedPerson); model.updateFilteredPersonList(Model.PREDICATE_SHOW_ALL_PERSONS); diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java index 5eb7e572b60..479eac4ff3e 100644 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java @@ -6,6 +6,7 @@ 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; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK; import static seedu.address.logic.parser.CliSyntax.PREFIX_WEDDING; import java.util.Set; @@ -19,6 +20,7 @@ import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -48,8 +50,9 @@ public AddCommand parse(String args) throws ParseException { Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).orElse("")); Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); Set weddingList = ParserUtil.parseWeddings(argMultimap.getAllValues(PREFIX_WEDDING)); + Set taskList = ParserUtil.parseTasks(argMultimap.getAllValues(PREFIX_TASK)); - Person person = new Person(name, phone, email, address, tagList, weddingList); + Person person = new Person(name, phone, email, address, tagList, weddingList, taskList); return new AddCommand(person); } diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index e30bc76a0d2..7fbf67c453f 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -9,6 +9,7 @@ import seedu.address.commons.util.ToStringBuilder; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; /** @@ -25,19 +26,21 @@ public class Person { // Data fields private final Address address; private final Set tags = new HashSet<>(); + private final Set tasks = new HashSet<>(); private final Set weddings = new HashSet<>(); /** * Every field must be present and not null. */ - public Person(Name name, Phone phone, Email email, Address address, Set tags, Set weddings) { - requireAllNonNull(name, phone, email, address, tags, weddings); + public Person(Name name, Phone phone, Email email, Address address, Set tags, Set weddings, Set tasks) { + requireAllNonNull(name, phone, email, address, tags, weddings, tasks); this.name = name; this.phone = phone; this.email = email; this.address = address; this.tags.addAll(tags); this.weddings.addAll(weddings); + this.tasks.addAll(tasks); } public Name getName() { @@ -64,6 +67,14 @@ public Set getTags() { return Collections.unmodifiableSet(tags); } + /** + * Returns an immutable task set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + */ + public Set getTasks() { + return Collections.unmodifiableSet(tasks); + } + /** * Returns an immutable wedding set, which throws {@code UnsupportedOperationException} * if modification is attempted. @@ -106,13 +117,14 @@ public boolean equals(Object other) { && email.equals(otherPerson.email) && address.equals(otherPerson.address) && tags.equals(otherPerson.tags) - && weddings.equals((otherPerson.weddings)); + && weddings.equals(otherPerson.weddings) + && tasks.equals((otherPerson.tasks)); } @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags, weddings); + return Objects.hash(name, phone, email, address, tags, weddings, tasks); } @Override @@ -124,6 +136,7 @@ public String toString() { .add("address", address) .add("tags", tags) .add("weddings", weddings) + .add("tasks", tasks) .toString(); } diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 76b473de94e..94933bd1204 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -13,6 +13,7 @@ import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; import seedu.address.model.wedding.WeddingName; @@ -25,27 +26,33 @@ public static Person[] getSamplePersons() { new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), new Address("Blk 30 Geylang Street 29, #06-40"), getTagSet("friends"), - getWeddingSet("Casey's Wedding")), + getWeddingSet("Casey's Wedding"), + getTaskSet("Finalize Catering Menu")), new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), getTagSet("colleagues", "friends"), - getWeddingSet()), + getWeddingSet(), + getTaskSet("Set Up Venue Decorations")), new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), getTagSet("neighbours"), - getWeddingSet("Wedding August 2029", "Wedding 2")), + getWeddingSet("Wedding August 2029", "Wedding 2"), + getTaskSet("Send invitations")), new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), getTagSet("family"), - getWeddingSet()), + getWeddingSet(), + getTaskSet("Order wedding cake")), new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), new Address("Blk 47 Tampines Street 20, #17-35"), getTagSet("classmates"), - getWeddingSet("Casey's Wedding")), + getWeddingSet("Casey's Wedding"), + getTaskSet("Schedule Hair and Makeup Trials")), new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), new Address("Blk 45 Aljunied Street 85, #11-31"), getTagSet("colleagues"), - getWeddingSet("Wedding 10")) + getWeddingSet("Wedding 10"), + getTaskSet("Schedule Hair and Makeup Trials")) }; } @@ -67,6 +74,15 @@ public static Set getTagSet(String... strings) { .collect(Collectors.toSet()); } + /** + * Returns a task set containing the list of tasks given. + */ + public static Set getTaskSet(String... strings) { + return Arrays.stream(strings) + .map(Task::new) + .collect(Collectors.toSet()); + } + /** * Returns a wedding set containing the list of weddings given. From b0a0a31b4379b590f9b0c0e683560f1808f0dc63 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 19:58:28 +0800 Subject: [PATCH 11/25] Add addressBook parsing logic for Task commands --- .../java/seedu/address/logic/parser/AddressBookParser.java | 6 ++++++ src/main/java/seedu/address/logic/parser/CliSyntax.java | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index b3561e4b9de..685b9ff9607 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -13,14 +13,17 @@ import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.CreateTagCommand; +import seedu.address.logic.commands.CreateTaskCommand; import seedu.address.logic.commands.CreateWeddingCommand; import seedu.address.logic.commands.DeleteCommand; import seedu.address.logic.commands.DeleteTagCommand; +import seedu.address.logic.commands.DeleteTaskCommand; import seedu.address.logic.commands.DeleteWeddingCommand; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.ListTaskCommand; import seedu.address.logic.commands.TagCommand; import seedu.address.logic.commands.UnassignWeddingCommand; import seedu.address.logic.commands.UntagCommand; @@ -76,6 +79,9 @@ public Command parseCommand(String userInput) throws ParseException { case UntagCommand.COMMAND_WORD -> new UntagCommandParser().parse(arguments); case AssignWeddingCommand.COMMAND_WORD -> new AssignWeddingCommandParser().parse(arguments); case UnassignWeddingCommand.COMMAND_WORD -> new UnassignWeddingCommandParser().parse(arguments); + case CreateTaskCommand.COMMAND_WORD -> new CreateTaskCommandParser().parse(arguments); + case ListTaskCommand.COMMAND_WORD -> new ListTaskCommand(); + case DeleteTaskCommand.COMMAND_WORD -> new DeleteTaskCommandParser().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 adc6af7988a..420835193f6 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -10,7 +10,10 @@ public class CliSyntax { public static final Prefix PREFIX_PHONE = new Prefix("p/"); public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); + public static final Prefix PREFIX_TAG = new Prefix("t/"); + public static final Prefix PREFIX_TASK = new Prefix("tk/"); + public static final Prefix PREFIX_WEDDING = new Prefix("w/"); public static final Prefix PREFIX_FORCE = new Prefix("f/"); } From 0dc26008eb711b784945e089077b4a72e9fb6ee7 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Tue, 22 Oct 2024 21:01:39 +0800 Subject: [PATCH 12/25] Modify Ui logic to be compatible with other pull request --- .../address/logic/commands/CommandResult.java | 54 +++++++++++++------ .../address/logic/commands/ExitCommand.java | 2 +- .../address/logic/commands/HelpCommand.java | 2 +- .../address/logic/commands/ListCommand.java | 3 +- .../logic/commands/ListTaskCommand.java | 4 +- .../java/seedu/address/ui/MainWindow.java | 46 +++++++++++----- .../seedu/address/ui/PersonListPanel.java | 7 +++ .../java/seedu/address/ui/TaskListPanel.java | 7 +++ src/main/resources/view/MainWindow.fxml | 4 +- 9 files changed, 92 insertions(+), 37 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java index b8f84e900ca..e024b092fd7 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/address/logic/commands/CommandResult.java @@ -19,21 +19,26 @@ public class CommandResult { /** The application should exit. */ private final boolean exit; - /** The person list should be shown. */ - private final boolean showPersonList; + /** + * Enum to indicate which view to switch to. + */ + public enum SwitchView { + PERSON, + WEDDING, + TASK, + NONE + } - /** The task list should be shown. */ - private final boolean showTaskList; + private final SwitchView switchView; /** * Constructs a {@code CommandResult} with the specified fields. */ - public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean showPersonList, boolean showTaskList) { + public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, SwitchView switchView) { this.feedbackToUser = requireNonNull(feedbackToUser); this.showHelp = showHelp; this.exit = exit; - this.showPersonList = showPersonList; - this.showTaskList = showTaskList; + this.switchView = switchView; } /** @@ -41,7 +46,21 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, bool * and other fields set to their default value. */ public CommandResult(String feedbackToUser) { - this(feedbackToUser, false, false, false,false); + this(feedbackToUser, false, false, SwitchView.NONE); + } + + /** + * Constructs a {@code CommandResult} with feedback and view to switch to, with default help and exit values. + */ + public CommandResult(String feedbackToUser, SwitchView view) { + this(feedbackToUser, false, false, view); + } + + /** + * Constructs a {@code CommandResult} with specified feedback, help, and exit status but with no view switch. + */ + public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) { + this(feedbackToUser, showHelp, exit, SwitchView.NONE); } public String getFeedbackToUser() { @@ -52,12 +71,15 @@ public boolean isShowHelp() { return showHelp; } - public boolean isShowPersonList() { - return showPersonList; + /** + * Checks if the command requires switching views. + */ + public boolean isSwitchView() { + return switchView != SwitchView.NONE; } - public boolean isShowTaskList() { - return showTaskList; + public SwitchView getView() { + return switchView; } public boolean isExit() { return exit; @@ -78,13 +100,12 @@ public boolean equals(Object other) { return feedbackToUser.equals(otherCommandResult.feedbackToUser) && showHelp == otherCommandResult.showHelp && exit == otherCommandResult.exit - && showPersonList == otherCommandResult.showPersonList - && showTaskList == otherCommandResult.showTaskList; + && switchView == otherCommandResult.switchView; } @Override public int hashCode() { - return Objects.hash(feedbackToUser, showHelp, exit, showPersonList, showTaskList); + return Objects.hash(feedbackToUser, showHelp, exit, switchView); } @Override @@ -93,8 +114,7 @@ public String toString() { .add("feedbackToUser", feedbackToUser) .add("showHelp", showHelp) .add("exit", exit) - .add("showPersonList", showPersonList) - .add("showTaskList", showTaskList) + .add("switchView", switchView) .toString(); } diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java index 7874f9ccfc1..3dd85a8ba90 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java @@ -13,7 +13,7 @@ public class ExitCommand extends Command { @Override public CommandResult execute(Model model) { - return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false, false); + return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true); } } diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java index 492a3633fbd..bf824f91bd0 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java @@ -16,6 +16,6 @@ public class HelpCommand extends Command { @Override public CommandResult execute(Model model) { - return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false, false); + return new CommandResult(SHOWING_HELP_MESSAGE, true, false); } } diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java index b67f21cf018..2403697c3a2 100644 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListCommand.java @@ -4,6 +4,7 @@ import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; import seedu.address.model.Model; +import seedu.address.logic.commands.CommandResult.SwitchView; /** * Lists all persons in the address book to the user. @@ -19,6 +20,6 @@ public class ListCommand extends Command { public CommandResult execute(Model model) { requireNonNull(model); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(MESSAGE_SUCCESS, false, false, true, false); + return new CommandResult(MESSAGE_SUCCESS, SwitchView.PERSON); } } diff --git a/src/main/java/seedu/address/logic/commands/ListTaskCommand.java b/src/main/java/seedu/address/logic/commands/ListTaskCommand.java index 1310066a48b..765b11e3b8a 100644 --- a/src/main/java/seedu/address/logic/commands/ListTaskCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListTaskCommand.java @@ -3,8 +3,10 @@ import static java.util.Objects.requireNonNull; import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS; +import seedu.address.logic.commands.CommandResult.SwitchView; import seedu.address.model.Model; + /** * Lists all tasks in the address book to the user. */ @@ -18,6 +20,6 @@ public class ListTaskCommand extends Command { public CommandResult execute(Model model) { requireNonNull(model); model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); - return new CommandResult(MESSAGE_SUCCESS, false, false, false, true); + return new CommandResult(MESSAGE_SUCCESS, SwitchView.TASK); } } diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index dc91ab2f3b3..6be10f0dba9 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -2,6 +2,7 @@ import java.util.logging.Logger; + import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.MenuItem; @@ -14,6 +15,7 @@ import seedu.address.commons.core.LogsCenter; import seedu.address.logic.Logic; import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.CommandResult.SwitchView; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; @@ -43,7 +45,7 @@ public class MainWindow extends UiPart { private MenuItem helpMenuItem; @FXML - private StackPane personListPanelPlaceholder; + private StackPane listPanelPlaceholder; @FXML private StackPane resultDisplayPlaceholder; @@ -112,7 +114,7 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) { */ void fillInnerParts() { personListPanel = new PersonListPanel(logic.getFilteredPersonList()); - personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + listPanelPlaceholder.getChildren().add(personListPanel.getRoot()); taskListPanel = new TaskListPanel(logic.getFilteredTaskList()); @@ -127,19 +129,38 @@ void fillInnerParts() { } /** - * Shows the person list panel. + * Switches the view shown to the user. + * @param switchView The view that should be shown. + */ + public void switchView(SwitchView switchView) { + switch (switchView) { + case PERSON: + changeToPersonView(); + break; + case TASK: + changeToTaskView(); + break; + default: + throw new UnsupportedOperationException("Invalid view selected."); + } + } + + /** + * Changes the list panel to show the {@code Person} list. */ - public void showPersonList() { - personListPanelPlaceholder.getChildren().clear(); - personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + public void changeToPersonView() { + personListPanel.updatePersonList(logic.getFilteredPersonList()); + listPanelPlaceholder.getChildren().clear(); + listPanelPlaceholder.getChildren().add(personListPanel.getRoot()); } /** * Shows the task list panel. */ - public void showTaskList() { - personListPanelPlaceholder.getChildren().clear(); - personListPanelPlaceholder.getChildren().add(taskListPanel.getRoot()); + public void changeToTaskView() { + taskListPanel.updatePersonList(logic.getFilteredTaskList()); + listPanelPlaceholder.getChildren().clear(); + listPanelPlaceholder.getChildren().add(taskListPanel.getRoot()); } /** @@ -205,11 +226,8 @@ private CommandResult executeCommand(String commandText) throws CommandException handleExit(); } - // Switch panels based on the command result - if (commandResult.isShowPersonList()) { - showPersonList(); - } else if (commandResult.isShowTaskList()) { - showTaskList(); + if (commandResult.isSwitchView()) { + switchView(commandResult.getView()); } return commandResult; diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java index f4c501a897b..55495949246 100644 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ b/src/main/java/seedu/address/ui/PersonListPanel.java @@ -29,6 +29,13 @@ public PersonListPanel(ObservableList personList) { personListView.setCellFactory(listView -> new PersonListViewCell()); } + /** + * Updates the {@code PersonListView} with an updated list of persons. + */ + public void updatePersonList(ObservableList personList) { + personListView.setItems(personList); + } + /** * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. */ diff --git a/src/main/java/seedu/address/ui/TaskListPanel.java b/src/main/java/seedu/address/ui/TaskListPanel.java index 1c4b2e2ffb9..5dcb00021ad 100644 --- a/src/main/java/seedu/address/ui/TaskListPanel.java +++ b/src/main/java/seedu/address/ui/TaskListPanel.java @@ -29,6 +29,13 @@ public TaskListPanel(ObservableList taskList) { taskListView.setCellFactory(listView -> new TaskListViewCell()); } + /** + * Updates the {@code TaskListView} with an updated list of tasks. + */ + public void updatePersonList(ObservableList taskList) { + taskListView.setItems(taskList); + } + /** * Custom {@code ListCell} that displays the graphics of a {@code Task} using a {@code TaskCard}. */ diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 0fb778a8560..87ed871fc4b 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -46,11 +46,11 @@ - + - + From 924a8d1e84f52f96990ed4606ac1c0bc8e7f5fe9 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 01:19:15 +0800 Subject: [PATCH 13/25] Fix checkstyle and test compatibility --- .../java/seedu/address/logic/Messages.java | 16 +++--- .../logic/commands/DeleteTaskCommand.java | 2 +- .../address/logic/commands/EditCommand.java | 3 +- .../address/logic/commands/ListCommand.java | 2 +- .../logic/parser/CreateTaskCommandParser.java | 2 +- .../address/logic/parser/ParserUtil.java | 2 +- .../java/seedu/address/model/AddressBook.java | 2 +- .../seedu/address/model/person/Person.java | 3 +- .../seedu/address/model/task/Deadline.java | 24 ++++++++- .../java/seedu/address/model/task/Event.java | 29 ++++++++-- .../seedu/address/model/task/ParsedTask.java | 9 ++++ .../java/seedu/address/model/task/Task.java | 7 +++ .../java/seedu/address/model/task/Todo.java | 17 ++++++ .../exceptions/TaskNotFoundException.java | 2 +- .../address/model/util/SampleDataUtil.java | 24 ++++++++- .../address/storage/JsonAdaptedDeadline.java | 1 + .../address/storage/JsonAdaptedEvent.java | 1 + .../address/storage/JsonAdaptedPerson.java | 6 ++- .../address/storage/JsonAdaptedTask.java | 27 +++++++--- .../address/storage/JsonAdaptedTodo.java | 1 + .../storage/JsonSerializableAddressBook.java | 1 + .../java/seedu/address/ui/MainWindow.java | 1 - .../invalidAndValidPersonAddressBook.json | 3 +- .../invalidPersonAddressBook.json | 3 +- .../invalidTagAddressBook.json | 3 +- .../invalidTaskAddressBook.json | 11 ++++ .../invalidWeddingAddressBook.json | 3 +- .../duplicatePersonAddressBook.json | 3 +- .../duplicateTagAddressBook.json | 3 +- .../duplicateWeddingAddressBook.json | 3 +- .../invalidPersonAddressBook.json | 3 +- .../invalidTagAddressBook.json | 3 +- .../invalidWeddingAddressBook.json | 3 +- .../typicalPersonsAddressBook.json | 19 ++++++- .../logic/commands/AddCommandTest.java | 31 +++++++++++ .../commands/AssignWeddingCommandTest.java | 3 +- .../logic/commands/CommandResultTest.java | 29 ++++++++-- .../logic/commands/CreateTagCommandTest.java | 31 +++++++++++ .../commands/CreateWeddingCommandTest.java | 31 +++++++++++ .../logic/commands/ListCommandTest.java | 6 ++- .../logic/commands/TagCommandTest.java | 7 ++- .../commands/UnassignWeddingCommandTest.java | 3 +- .../logic/commands/UntagCommandTest.java | 10 ++-- .../seedu/address/model/AddressBookTest.java | 15 +++++- .../address/model/person/PersonTest.java | 2 +- .../storage/JsonAdaptedPersonTest.java | 53 +++++++++++++++---- .../storage/JsonAddressBookStorageTest.java | 1 + .../JsonSerializableAddressBookTest.java | 5 ++ .../seedu/address/testutil/PersonBuilder.java | 17 +++++- .../address/testutil/TypicalPersons.java | 6 ++- .../seedu/address/testutil/TypicalTasks.java | 37 +++++++++++++ 51 files changed, 456 insertions(+), 73 deletions(-) create mode 100644 src/test/data/JsonAddressBookStorageTest/invalidTaskAddressBook.json create mode 100644 src/test/java/seedu/address/testutil/TypicalTasks.java diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java index 9630623ee42..828342dd40e 100644 --- a/src/main/java/seedu/address/logic/Messages.java +++ b/src/main/java/seedu/address/logic/Messages.java @@ -22,16 +22,16 @@ public class Messages { public static final String MESSAGE_INVALID_TASK_DISPLAYED_INDEX = "The task index provided is invalid"; public static final String MESSAGE_INVALID_DATE_FORMAT = "Invalid date format. Expected format: yyyy-MM-dd"; - public static final String MESSAGE_INVALID_TASK_TYPE = "Unknown task type: %1$s. " + - "Expected one of: todo, deadline, event."; + public static final String MESSAGE_INVALID_TASK_TYPE = "Unknown task type: %1$s. " + + "Expected one of: todo, deadline, event."; - public static final String MESSAGE_INVALID_DEADLINE_FORMAT = "Invalid deadline format. " + - "Usage: create-task tk/deadline [description] /by [date]"; - public static final String MESSAGE_INVALID_EVENT_FORMAT = "Invalid event format." + - " Usage: create-task tk/event [description] /from [start] /to [end]"; + public static final String MESSAGE_INVALID_DEADLINE_FORMAT = "Invalid deadline format. " + + "Usage: create-task tk/deadline [description] /by [date]"; + public static final String MESSAGE_INVALID_EVENT_FORMAT = "Invalid event format." + + " Usage: create-task tk/event [description] /from [start] /to [end]"; - public static final String MESSAGE_INCOMPLETE_TASK_DESCRIPTION = "Task description is incomplete. " + - "Expected format: tk/[task type] [task details]."; + public static final String MESSAGE_INCOMPLETE_TASK_DESCRIPTION = "Task description is incomplete. " + + "Expected format: tk/[task type] [task details]."; public static final String MESSAGE_TO_BEFORE_FROM_INVALID = "\"From\" date must be before \"To\" date."; public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; public static final String MESSAGE_DUPLICATE_FIELDS = diff --git a/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java index a627dcc61a2..de96f40f662 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java @@ -66,4 +66,4 @@ public String toString() { .add("targetIndex", targetIndex) .toString(); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 9e543fe0c0d..7a4cc344749 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -107,7 +107,8 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Set updatedWeddings = editPersonDescriptor.getWeddings().orElse(personToEdit.getWeddings()); Set updatedTasks = editPersonDescriptor.getTasks().orElse(personToEdit.getTasks()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags, updatedWeddings, updatedTasks); + return new Person(updatedName, updatedPhone, updatedEmail, + updatedAddress, updatedTags, updatedWeddings, updatedTasks); } @Override diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java index 2403697c3a2..825b1e07343 100644 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListCommand.java @@ -3,8 +3,8 @@ import static java.util.Objects.requireNonNull; import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; -import seedu.address.model.Model; import seedu.address.logic.commands.CommandResult.SwitchView; +import seedu.address.model.Model; /** * Lists all persons in the address book to the user. diff --git a/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java index 7c1e0c6da69..3c69228c44e 100644 --- a/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/CreateTaskCommandParser.java @@ -31,7 +31,7 @@ public CreateTaskCommand parse(String args) throws ParseException { } List taskDescriptions = argMultimap.getAllValues(PREFIX_TASK); - if (taskDescriptions.isEmpty()|| taskDescriptions.stream().anyMatch(String::isBlank)) { + if (taskDescriptions.isEmpty() || taskDescriptions.stream().anyMatch(String::isBlank)) { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CreateTaskCommand.MESSAGE_USAGE)); } diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 588597ca40d..96028adb377 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -225,7 +225,7 @@ private static Event parseEventTask(String taskDetails) throws ParseException { */ private static void validateDateFormat(String date) throws ParseException { try { - LocalDate.parse(date, DATE_FORMATTER); + LocalDate.parse(date, DATE_FORMATTER); } catch (DateTimeParseException e) { throw new ParseException(Messages.MESSAGE_INVALID_DATE_FORMAT); } diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java index 3f086281e1b..7cacb8c6e9a 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/seedu/address/model/AddressBook.java @@ -88,7 +88,7 @@ public void setWeddings(List weddings) { * Replaces the contents of the task list with {@code tasks}. * {@code tasks} must not contain duplicate tasks. */ - public void setTasks (List tasks) { + public void setTasks(List tasks) { this.tasks.setTasks(tasks); } diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index 7fbf67c453f..a8b74a1d43e 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -32,7 +32,8 @@ public class Person { /** * Every field must be present and not null. */ - public Person(Name name, Phone phone, Email email, Address address, Set tags, Set weddings, Set tasks) { + public Person(Name name, Phone phone, Email email, Address address, + Set tags, Set weddings, Set tasks) { requireAllNonNull(name, phone, email, address, tags, weddings, tasks); this.name = name; this.phone = phone; diff --git a/src/main/java/seedu/address/model/task/Deadline.java b/src/main/java/seedu/address/model/task/Deadline.java index 543f9b3c12e..f7e9c8cccd7 100644 --- a/src/main/java/seedu/address/model/task/Deadline.java +++ b/src/main/java/seedu/address/model/task/Deadline.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.Objects; /** * The Deadline class represents a task with a deadline. @@ -9,8 +10,10 @@ */ public class Deadline extends Task { + public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private LocalDate by; + /** * Constructs a Deadline task with the specified description and deadline date. * @@ -19,8 +22,20 @@ public class Deadline extends Task { */ public Deadline(String description, String by) { super(description); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - this.by = LocalDate.parse(by, formatter); + this.by = LocalDate.parse(by, FORMATTER); + } + + /** + * Constructs a Deadline task with the specified description, deadline date and isDone status. + * + * @param description The description of the task. + * @param by The deadline date in the format "yyyy-MM-dd". + * @param isDone The completion status of the event. + */ + public Deadline(String description, String by, boolean isDone) { + super(description); + this.by = LocalDate.parse(by, FORMATTER); + this.isDone = isDone; } public LocalDate getBy() { @@ -48,6 +63,11 @@ public boolean equals(Object other) { && by.equals(otherDeadline.by); } + @Override + public int hashCode() { + return Objects.hash(description, isDone, by); + } + /** * Returns a string representation of the Deadline task, including its deadline date. * diff --git a/src/main/java/seedu/address/model/task/Event.java b/src/main/java/seedu/address/model/task/Event.java index af40b1dec9f..1acded32f8a 100644 --- a/src/main/java/seedu/address/model/task/Event.java +++ b/src/main/java/seedu/address/model/task/Event.java @@ -2,16 +2,18 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.Objects; /** * The Event class represents a task that spans over a period of time. * It extends the Task class and adds LocalDate fields to store the start and end dates of the event. */ public class Event extends Task { - + public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private LocalDate from; private LocalDate to; + /** * Constructs an Event task with the specified description, start date, and end date. * @@ -21,9 +23,23 @@ public class Event extends Task { */ public Event(String description, String from, String to) { super(description); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - this.from = LocalDate.parse(from, formatter); - this.to = LocalDate.parse(to, formatter); + this.from = LocalDate.parse(from, FORMATTER); + this.to = LocalDate.parse(to, FORMATTER); + } + + /** + * Constructs an Event task with the specified description, start date, and end date. + * + * @param description The description of the event. + * @param from The start date of the event in the format "yyyy-MM-dd". + * @param to The end date of the event in the format "yyyy-MM-dd". + * @param isDone The completion status of the event. + */ + public Event(String description, String from, String to, boolean isDone) { + super(description); + this.from = LocalDate.parse(from, FORMATTER); + this.to = LocalDate.parse(to, FORMATTER); + this.isDone = isDone; } public LocalDate getFrom() { @@ -57,6 +73,11 @@ public boolean equals(Object other) { && to.equals(equals(otherEvent.to)); } + @Override + public int hashCode() { + return Objects.hash(description, isDone, from, to); + } + /** * Returns a string representation of the Event task, including its start and end dates. * diff --git a/src/main/java/seedu/address/model/task/ParsedTask.java b/src/main/java/seedu/address/model/task/ParsedTask.java index e384c8fe79b..b50cdfec03f 100644 --- a/src/main/java/seedu/address/model/task/ParsedTask.java +++ b/src/main/java/seedu/address/model/task/ParsedTask.java @@ -1,9 +1,18 @@ package seedu.address.model.task; +/** + * Represents a task that has been parsed into its type and details. + */ public class ParsedTask { private final String taskType; private final String taskDetails; + /** + * Constructs a {@code ParsedTask} with the specified task type and task details. + * + * @param taskType The type of the task (e.g., todo, deadline, event). + * @param taskDetails The details of the task (e.g., description, date). + */ public ParsedTask(String taskType, String taskDetails) { this.taskType = taskType; this.taskDetails = taskDetails; diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java index 37042e8541d..53d50dad379 100644 --- a/src/main/java/seedu/address/model/task/Task.java +++ b/src/main/java/seedu/address/model/task/Task.java @@ -1,5 +1,7 @@ package seedu.address.model.task; +import java.util.Objects; + /** * The Task class represents a general task with a description and a completion status. * It serves as the base class for more specific types of tasks such as Todo, Deadline, and Event. @@ -139,6 +141,11 @@ public boolean equals(Object other) { public String toString() { return "[" + this.getStatusIcon() + "] " + this.description; } + + @Override + public int hashCode() { + return Objects.hash(description, isDone); + } } diff --git a/src/main/java/seedu/address/model/task/Todo.java b/src/main/java/seedu/address/model/task/Todo.java index fb51bc4d632..2680a1aa099 100644 --- a/src/main/java/seedu/address/model/task/Todo.java +++ b/src/main/java/seedu/address/model/task/Todo.java @@ -1,5 +1,7 @@ package seedu.address.model.task; +import java.util.Objects; + /** * The Todo class represents a simple task with no specific date attached. * It extends the Task class and does not add any additional fields. @@ -14,6 +16,16 @@ public Todo(String description) { super(description); } + /** + * Constructs a Todo task with the specified description and isDone status. + * + * @param description The description of the todo task. + * @param isDone The completion status of the event. + */ + public Todo(String description, boolean isDone) { + super(description); + this.isDone = isDone; + } /** * Returns true if both Todo tasks have the same data fields. @@ -35,6 +47,11 @@ public boolean equals(Object other) { && isDone == otherTodo.isDone; } + @Override + public int hashCode() { + return Objects.hash(description, isDone); + } + /** * Returns a string representation of the Todo task. * diff --git a/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java b/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java index ecc8e354948..7c437784b47 100644 --- a/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java +++ b/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java @@ -7,4 +7,4 @@ public class TaskNotFoundException extends RuntimeException { public TaskNotFoundException() { super("Task does not exist."); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 94933bd1204..4725a16a52b 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -13,7 +13,10 @@ import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; import seedu.address.model.wedding.Wedding; import seedu.address.model.wedding.WeddingName; @@ -75,14 +78,31 @@ public static Set getTagSet(String... strings) { } /** - * Returns a task set containing the list of tasks given. + * Returns a task set containing the list of tasks given as strings. + * Strings should follow a format like: "todo: Buy cake", "deadline: Submit report by Monday", "event: Meeting" */ public static Set getTaskSet(String... strings) { return Arrays.stream(strings) - .map(Task::new) + .map(SampleDataUtil::parseTaskFromString) .collect(Collectors.toSet()); } + /** + * Parses a string to return a specific Task instance (e.g., Todo, Deadline, or Event). + */ + private static Task parseTaskFromString(String taskString) { + if (taskString.startsWith("todo:")) { + return new Todo(taskString.substring(5).trim()); + } else if (taskString.startsWith("deadline:")) { + return new Deadline(taskString.substring(9).trim(), "2022-12-22"); + } else if (taskString.startsWith("event:")) { + return new Event(taskString.substring(6).trim(), "2022-12-22", "2022-12-23"); + } else { + throw new IllegalArgumentException("Unknown task type in string: " + taskString); + } + } + + /** * Returns a wedding set containing the list of weddings given. diff --git a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java index 460f10b5788..118c38c58fb 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.model.task.Deadline; /** diff --git a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java index 8bfd7268cca..ccbeb5d424a 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.model.task.Event; /** diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index 44d86d62cdc..db399d67f79 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.person.Address; import seedu.address.model.person.Email; @@ -42,8 +43,9 @@ class JsonAdaptedPerson { @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tags") List tags, @JsonProperty("tasks") List tasks, - @JsonProperty("weddings") List weddings) { + @JsonProperty("tags") List tags, + @JsonProperty("weddings") List weddings, + @JsonProperty("tasks") List tasks) { this.name = name; this.phone = phone; this.email = email; diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java index c948e148b10..6000a47edc5 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTask.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java @@ -4,24 +4,35 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import seedu.address.model.task.Task; +import seedu.address.model.task.Task; +/** + * A Jackson-friendly abstract class for a task. + * This class serves as a base for JSON adaptations of specific task types + * (e.g., Todo, Deadline, Event), which are represented as subclasses. + */ @JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, // Use the name of the class to differentiate types - include = JsonTypeInfo.As.PROPERTY, // Include type info as a property in the JSON - property = "type" // The name of the property in the JSON that will hold the type information + use = JsonTypeInfo.Id.NAME, // Use the name of the class to differentiate types + include = JsonTypeInfo.As.PROPERTY, // Include type info as a property in the JSON + property = "type" // The name of the property in the JSON that will hold the type information ) @JsonSubTypes({ - @JsonSubTypes.Type(value = JsonAdaptedTodo.class, name = "todo"), - @JsonSubTypes.Type(value = JsonAdaptedDeadline.class, name = "deadline"), - @JsonSubTypes.Type(value = JsonAdaptedEvent.class, name = "event") + @JsonSubTypes.Type(value = JsonAdaptedTodo.class, name = "todo"), + @JsonSubTypes.Type(value = JsonAdaptedDeadline.class, name = "deadline"), + @JsonSubTypes.Type(value = JsonAdaptedEvent.class, name = "event") }) public abstract class JsonAdaptedTask { protected final String description; protected final boolean isDone; + /** + * Constructs a {@code JsonAdaptedTask} with the given description and completion status. + * + * @param description A string representing the task's description. + * @param isDone A boolean indicating if the task is completed. + */ @JsonCreator public JsonAdaptedTask(@JsonProperty("description") String description, @JsonProperty("isDone") boolean isDone) { @@ -30,4 +41,4 @@ public JsonAdaptedTask(@JsonProperty("description") String description, } public abstract Task toModelType(); -} \ No newline at end of file +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java index 82e1ec027ab..cdd6ee4248d 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.task.Todo; diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java index 9d02a953fa8..138e90f8974 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.AddressBook; import seedu.address.model.ReadOnlyAddressBook; diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 6be10f0dba9..a642876bb78 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -2,7 +2,6 @@ import java.util.logging.Logger; - import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.MenuItem; diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json index b95a76c2fb8..a7ca0ae1bb6 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json @@ -11,5 +11,6 @@ "address": "4th street" } ], "tags": [], - "weddings": [] + "weddings": [], + "tasks": [] } diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json index 6281db4c10c..b5634c6b6d9 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json @@ -6,5 +6,6 @@ "address": "4th street" } ], "tags": [], - "weddings": [] + "weddings": [], + "tasks": [] } diff --git a/src/test/data/JsonAddressBookStorageTest/invalidTagAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidTagAddressBook.json index bec5f5644c7..6bd597519d4 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidTagAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidTagAddressBook.json @@ -6,5 +6,6 @@ "address": "4th street" }], "tags": ["Valid Tag", " "], - "weddings": ["Valid Wedding"] + "weddings": ["Valid Wedding"], + "tasks": [] } diff --git a/src/test/data/JsonAddressBookStorageTest/invalidTaskAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidTaskAddressBook.json new file mode 100644 index 00000000000..1dc8fced0d4 --- /dev/null +++ b/src/test/data/JsonAddressBookStorageTest/invalidTaskAddressBook.json @@ -0,0 +1,11 @@ +{ + "persons": [ { + "name": "Valid Person", + "phone": "9482424", + "email": "hans@example.com", + "address": "4th street" + }], + "tags": ["Valid Tag"], + "weddings": ["valid wedding"], + "tasks": [" "] +} diff --git a/src/test/data/JsonAddressBookStorageTest/invalidWeddingAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidWeddingAddressBook.json index 630f41d70d6..3c028bf4b86 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidWeddingAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidWeddingAddressBook.json @@ -6,5 +6,6 @@ "address": "4th street" }], "tags": ["Valid Tag"], - "weddings": [" "] + "weddings": [" "], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json index 6b1dbae9aae..6783df0832a 100644 --- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json @@ -12,5 +12,6 @@ "address": "4th street" } ], "tags": ["florist"], - "weddings": [] + "weddings": [], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicateTagAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicateTagAddressBook.json index 536f1968239..c9e85eb0c00 100644 --- a/src/test/data/JsonSerializableAddressBookTest/duplicateTagAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/duplicateTagAddressBook.json @@ -7,5 +7,6 @@ "tags": [ "friends" ] }], "tags": ["florist", "chef", "florist"], - "weddings": ["Wedding July 2026"] + "weddings": ["Wedding July 2026"], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicateWeddingAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicateWeddingAddressBook.json index df1376a4bba..21a7941565e 100644 --- a/src/test/data/JsonSerializableAddressBookTest/duplicateWeddingAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/duplicateWeddingAddressBook.json @@ -7,5 +7,6 @@ "tags": [ "friends" ] }], "tags": ["florist", "chef"], - "weddings": ["Wedding July 2026", "Wedding 1", "Wedding July 2026", "Paula's Wedding"] + "weddings": ["Wedding July 2026", "Wedding 1", "Wedding July 2026", "Paula's Wedding"], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json index 3278e110d29..752bd7986d6 100644 --- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json @@ -6,5 +6,6 @@ "address": "4th street" } ], "tags": ["florist"], - "weddings": [] + "weddings": [], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidTagAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidTagAddressBook.json index 037d42b390b..26be9a263c2 100644 --- a/src/test/data/JsonSerializableAddressBookTest/invalidTagAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/invalidTagAddressBook.json @@ -6,5 +6,6 @@ "address": "4th street" } ], "tags": ["florist", " "], - "weddings": ["Wedding 19"] + "weddings": ["Wedding 19"], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidWeddingAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidWeddingAddressBook.json index ef459b24c63..0bc6f671ada 100644 --- a/src/test/data/JsonSerializableAddressBookTest/invalidWeddingAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/invalidWeddingAddressBook.json @@ -6,5 +6,6 @@ "address": "4th street" } ], "tags": ["florist", "musician"], - "weddings": ["Wedding 19", " "] + "weddings": ["Wedding 19", " "], + "tasks": [] } diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index 323f6d95174..dd57b0fe532 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -18,7 +18,12 @@ "phone" : "95352563", "email" : "heinz@example.com", "address" : "wall street", - "tags" : [ ] + "tags" : [ ], + "tasks": [{ + "type" : "todo", + "description" : "Buy cake", + "isDone" : false + }] }, { "name" : "Daniel Meier", "phone" : "87652533", @@ -45,5 +50,15 @@ "tags" : [ ] } ], "tags": ["florist"], - "weddings": ["Wedding 2", "Carla's Wedding"] + "weddings": ["Wedding 2", "Carla's Wedding"], + "tasks": [{ + "type" : "todo", + "description" : "Buy groceries", + "isDone" : false + }, { + "type" : "deadline", + "description" : "Submit report", + "isDone" : false, + "by" : "2024-12-31" + } ] } diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java index adb3bf47ed1..1775a4ae716 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java @@ -24,6 +24,7 @@ import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; import seedu.address.testutil.PersonBuilder; @@ -185,6 +186,36 @@ public ObservableList getFilteredTagList() { throw new AssertionError("This method should not be called."); } + @Override + public boolean hasTask(Task toAdd) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addTask(Task toAdd) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteTask(Task toDelete) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setTask(Task target, Task editedTask) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredTaskList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getFilteredTaskList() { + throw new AssertionError("This method should not be called."); + } + @Override public boolean hasWedding(Wedding toAdd) { throw new AssertionError("This method should not be called."); diff --git a/src/test/java/seedu/address/logic/commands/AssignWeddingCommandTest.java b/src/test/java/seedu/address/logic/commands/AssignWeddingCommandTest.java index 80b93ccc7bc..f1865a6d7a3 100644 --- a/src/test/java/seedu/address/logic/commands/AssignWeddingCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AssignWeddingCommandTest.java @@ -45,7 +45,8 @@ public void assignWedding_success() { personToEdit.getEmail(), personToEdit.getAddress(), personToEdit.getTags(), - updatedWeddings); + updatedWeddings, + personToEdit.getTasks()); expectedModel.setPerson(personToEdit, editedPerson); CommandTestUtil.assertCommandSuccess(assignWeddingCommand, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/address/logic/commands/CommandResultTest.java index 7b8c7cd4546..096cfa690af 100644 --- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java +++ b/src/test/java/seedu/address/logic/commands/CommandResultTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; +import seedu.address.logic.commands.CommandResult.SwitchView; public class CommandResultTest { @Test public void equals() { @@ -15,6 +16,12 @@ public void equals() { // same values -> returns true assertTrue(commandResult.equals(new CommandResult("feedback"))); assertTrue(commandResult.equals(new CommandResult("feedback", false, false))); + assertTrue(commandResult.equals(new CommandResult("feedback", false, false, + SwitchView.NONE))); + + // same object -> returns true + assertEquals(commandResult.isSwitchView(), new CommandResult("feedback", false, false, + SwitchView.NONE).isSwitchView()); // same object -> returns true assertTrue(commandResult.equals(commandResult)); @@ -29,10 +36,22 @@ public void equals() { assertFalse(commandResult.equals(new CommandResult("different"))); // different showHelp value -> returns false - assertFalse(commandResult.equals(new CommandResult("feedback", true, false))); + assertFalse(commandResult.equals(new CommandResult("feedback", true, false, + SwitchView.NONE))); // different exit value -> returns false - assertFalse(commandResult.equals(new CommandResult("feedback", false, true))); + assertFalse(commandResult.equals(new CommandResult("feedback", false, true, + SwitchView.NONE))); + + // different switchView value -> returns false + assertFalse(commandResult.equals(new CommandResult("feedback", false, false, + SwitchView.TASK))); + assertFalse(commandResult.equals(new CommandResult("feedback", false, false, + SwitchView.PERSON))); + + // different switchView value -> returns false + assertNotEquals(commandResult.isSwitchView(), new CommandResult("feedback", false, false, + SwitchView.PERSON).isSwitchView()); } @Test @@ -50,6 +69,10 @@ public void hashcode() { // different exit value -> returns different hashcode assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true).hashCode()); + + // different exit value -> returns different hashcode + assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, false, + SwitchView.PERSON).hashCode()); } @Test @@ -57,7 +80,7 @@ public void toStringMethod() { CommandResult commandResult = new CommandResult("feedback"); String expected = CommandResult.class.getCanonicalName() + "{feedbackToUser=" + commandResult.getFeedbackToUser() + ", showHelp=" + commandResult.isShowHelp() - + ", exit=" + commandResult.isExit() + "}"; + + ", exit=" + commandResult.isExit() + ", switchView=" + commandResult.getView() + "}"; assertEquals(expected, commandResult.toString()); } } diff --git a/src/test/java/seedu/address/logic/commands/CreateTagCommandTest.java b/src/test/java/seedu/address/logic/commands/CreateTagCommandTest.java index dffdf3c9864..7af84756bc4 100644 --- a/src/test/java/seedu/address/logic/commands/CreateTagCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/CreateTagCommandTest.java @@ -25,6 +25,7 @@ import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; public class CreateTagCommandTest { @@ -173,6 +174,36 @@ public void addTag(Tag toAdd) { throw new AssertionError("This method should not be called."); } + @Override + public boolean hasTask(Task toAdd) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addTask(Task toAdd) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteTask(Task toDelete) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setTask(Task target, Task editedTask) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredTaskList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getFilteredTaskList() { + throw new AssertionError("This method should not be called."); + } + @Override public boolean hasWedding(Wedding toAdd) { throw new AssertionError("This method should not be called."); diff --git a/src/test/java/seedu/address/logic/commands/CreateWeddingCommandTest.java b/src/test/java/seedu/address/logic/commands/CreateWeddingCommandTest.java index 1a013326843..975ad4bd8be 100644 --- a/src/test/java/seedu/address/logic/commands/CreateWeddingCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/CreateWeddingCommandTest.java @@ -24,6 +24,7 @@ import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; public class CreateWeddingCommandTest { @@ -177,6 +178,36 @@ public void updateFilteredTagList(Predicate predicate) { throw new AssertionError("This method should not be called."); } + @Override + public boolean hasTask(Task toAdd) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addTask(Task toAdd) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteTask(Task toDelete) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setTask(Task target, Task editedTask) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredTaskList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getFilteredTaskList() { + throw new AssertionError("This method should not be called."); + } + @Override public boolean hasWedding(Wedding toAdd) { throw new AssertionError("This method should not be called."); diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java index 435ff1f7275..90c22ea7c28 100644 --- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ListCommandTest.java @@ -28,12 +28,14 @@ public void setUp() { @Test public void execute_listIsNotFiltered_showsSameList() { - assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel); + CommandResult actualCommandResult = new ListCommand().execute(model); + assertCommandSuccess(new ListCommand(), model, actualCommandResult, expectedModel); } @Test public void execute_listIsFiltered_showsEverything() { showPersonAtIndex(model, INDEX_FIRST_PERSON); - assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel); + CommandResult actualCommandResult = new ListCommand().execute(model); + assertCommandSuccess(new ListCommand(), model, actualCommandResult, expectedModel); } } diff --git a/src/test/java/seedu/address/logic/commands/TagCommandTest.java b/src/test/java/seedu/address/logic/commands/TagCommandTest.java index 4ca3098af1b..a5a179a39cd 100644 --- a/src/test/java/seedu/address/logic/commands/TagCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/TagCommandTest.java @@ -48,7 +48,8 @@ public void execute_validTagsUnfilteredList_success() { personToEdit.getEmail(), personToEdit.getAddress(), updatedTags, - personToEdit.getWeddings()); + personToEdit.getWeddings(), + personToEdit.getTasks()); expectedModel.setPerson(personToEdit, editedPerson); CommandTestUtil.assertCommandSuccess(tagCommand, model, expectedMessage, expectedModel); @@ -63,6 +64,7 @@ public void execute_validMultipleTagsUnfilteredList_success() { new Email("test@example.com"), new Address("123, Test Street"), new HashSet<>(Arrays.asList(new Tag(new TagName("family")))), + new HashSet<>(), new HashSet<>() ); model.addTag(new Tag(new TagName("family"))); @@ -85,7 +87,8 @@ public void execute_validMultipleTagsUnfilteredList_success() { personWithTags.getEmail(), personWithTags.getAddress(), updatedTags, - personWithTags.getWeddings()); + personWithTags.getWeddings(), + personWithTags.getTasks()); expectedModel.setPerson(personWithTags, editedPerson); CommandTestUtil.assertCommandSuccess(tagCommand, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/logic/commands/UnassignWeddingCommandTest.java b/src/test/java/seedu/address/logic/commands/UnassignWeddingCommandTest.java index df0793a5819..90b4f7b44d7 100644 --- a/src/test/java/seedu/address/logic/commands/UnassignWeddingCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/UnassignWeddingCommandTest.java @@ -45,7 +45,8 @@ public void unassignWedding_success() { personToEdit.getEmail(), personToEdit.getAddress(), personToEdit.getTags(), - updatedWeddings); + updatedWeddings, + personToEdit.getTasks()); expectedModel.setPerson(personToEdit, editedPerson); CommandTestUtil.assertCommandSuccess(unassignWeddingCommand, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/logic/commands/UntagCommandTest.java b/src/test/java/seedu/address/logic/commands/UntagCommandTest.java index 657a2d63b19..5db51b6a18c 100644 --- a/src/test/java/seedu/address/logic/commands/UntagCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/UntagCommandTest.java @@ -49,7 +49,8 @@ public void execute_validTagsUnfilteredList_success() { personToEdit.getEmail(), personToEdit.getAddress(), updatedTags, - personToEdit.getWeddings()); + personToEdit.getWeddings(), + personToEdit.getTasks()); expectedModel.setPerson(personToEdit, editedPerson); CommandTestUtil.assertCommandSuccess(untagCommand, model, expectedMessage, expectedModel); @@ -64,6 +65,7 @@ public void execute_validMultipleTagsUnfilteredList_success() { new seedu.address.model.person.Email("test@example.com"), new seedu.address.model.person.Address("123, Test Street"), new HashSet<>(Arrays.asList(new Tag(new TagName("friends")), new Tag(new TagName("owesMoney")))), + new HashSet<>(), new HashSet<>() ); model.setPerson(model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()), personWithTags); @@ -83,7 +85,8 @@ public void execute_validMultipleTagsUnfilteredList_success() { personWithTags.getEmail(), personWithTags.getAddress(), updatedTags, - personWithTags.getWeddings()); + personWithTags.getWeddings(), + personWithTags.getTasks()); expectedModel.setPerson(personWithTags, editedPerson); CommandTestUtil.assertCommandSuccess(untagCommand, model, expectedMessage, expectedModel); @@ -135,7 +138,8 @@ public void execute_personWithoutTags_failure() { new seedu.address.model.person.Address("123, Test Street"), new HashSet<>(), // No tags new HashSet<>(Arrays.asList(new Wedding(new WeddingName("Jiazhen's Wedding")), - new Wedding(new WeddingName("Wedding 29th August")))) + new Wedding(new WeddingName("Wedding 29th August")))), + new HashSet<>() ); model.setPerson(model.getFilteredPersonList().get(INDEX_SECOND_PERSON.getZeroBased()), personWithoutTags); diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java index ac39fe90f7d..94d3ef0caeb 100644 --- a/src/test/java/seedu/address/model/AddressBookTest.java +++ b/src/test/java/seedu/address/model/AddressBookTest.java @@ -9,6 +9,7 @@ import static seedu.address.testutil.TypicalPersons.ALICE; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; import static seedu.address.testutil.TypicalTags.FLORIST; +import static seedu.address.testutil.TypicalTasks.TODO_TASK; import static seedu.address.testutil.TypicalWeddings.AMY_WEDDING; import java.util.Arrays; @@ -23,6 +24,7 @@ import seedu.address.model.person.Person; import seedu.address.model.person.exceptions.DuplicatePersonException; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; import seedu.address.testutil.PersonBuilder; @@ -55,7 +57,8 @@ public void resetData_withDuplicatePersons_throwsDuplicatePersonException() { List newPersons = Arrays.asList(ALICE, editedAlice); List tags = Arrays.asList(FLORIST); List weddings = Arrays.asList(AMY_WEDDING); - AddressBookStub newData = new AddressBookStub(newPersons, tags, weddings); + List tasks = Arrays.asList(TODO_TASK); + AddressBookStub newData = new AddressBookStub(newPersons, tags, weddings, tasks); assertThrows(DuplicatePersonException.class, () -> addressBook.resetData(newData)); } @@ -102,11 +105,14 @@ private static class AddressBookStub implements ReadOnlyAddressBook { private final ObservableList persons = FXCollections.observableArrayList(); private final ObservableList tags = FXCollections.observableArrayList(); private final ObservableList weddings = FXCollections.observableArrayList(); + private final ObservableList tasks = FXCollections.observableArrayList(); - AddressBookStub(Collection persons, Collection tags, Collection weddings) { + AddressBookStub(Collection persons, Collection tags, + Collection weddings, Collection tasks) { this.persons.setAll(persons); this.tags.setAll(tags); this.weddings.setAll(weddings); + this.tasks.setAll(tasks); } @Override @@ -123,6 +129,11 @@ public ObservableList getTagList() { public ObservableList getWeddingList() { return weddings; } + + @Override + public ObservableList getTaskList() { + return tasks; + } } } diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java index 91f778b01aa..9c8fd9f688f 100644 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ b/src/test/java/seedu/address/model/person/PersonTest.java @@ -94,7 +94,7 @@ public void equals() { public void toStringMethod() { String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone() + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() - + ", weddings=" + ALICE.getWeddings() + "}"; + + ", weddings=" + ALICE.getWeddings() + ", tasks=" + ALICE.getTasks() + "}"; assertEquals(expected, ALICE.toString()); } } diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java index 48f6ee04866..9a3646dcbc3 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java @@ -4,6 +4,7 @@ import static seedu.address.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalPersons.BENSON; +import static seedu.address.testutil.TypicalPersons.CARL; import static seedu.address.testutil.TypicalPersons.CLIVE; import java.util.ArrayList; @@ -17,6 +18,9 @@ import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.Todo; public class JsonAdaptedPersonTest { private static final String INVALID_NAME = "R@chel"; @@ -34,6 +38,21 @@ public class JsonAdaptedPersonTest { private static final List VALID_WEDDINGS = BENSON.getWeddings().stream() .map(JsonAdaptedWedding::new) .collect(Collectors.toList()); + + private static final List VALID_TASKS = CARL.getTasks().stream() + .map(task -> { + if (task instanceof Todo) { + return new JsonAdaptedTodo((Todo) task); + } else if (task instanceof Deadline) { + return new JsonAdaptedDeadline((Deadline) task); + } else if (task instanceof Event) { + return new JsonAdaptedEvent((Event) task); + } else { + throw new IllegalArgumentException("Unknown task type"); + } + }) + .collect(Collectors.toList()); + private static final String BLANK_ADDRESS = ""; private static final String CLIVE_NAME = CLIVE.getName().toString(); private static final String CLIVE_PHONE = CLIVE.getPhone().toString(); @@ -45,6 +64,20 @@ public class JsonAdaptedPersonTest { .map(JsonAdaptedWedding::new) .collect(Collectors.toList()); + private static final List CLIVE_TASKS = CLIVE.getTasks().stream() + .map(task -> { + if (task instanceof Todo) { + return new JsonAdaptedTodo((Todo) task); + } else if (task instanceof Deadline) { + return new JsonAdaptedDeadline((Deadline) task); + } else if (task instanceof Event) { + return new JsonAdaptedEvent((Event) task); + } else { + throw new IllegalArgumentException("Unknown task type"); + } + }) + .collect(Collectors.toList()); + @Test public void toModelType_validPersonDetails_returnsPerson() throws Exception { JsonAdaptedPerson person = new JsonAdaptedPerson(BENSON); @@ -55,7 +88,7 @@ public void toModelType_validPersonDetails_returnsPerson() throws Exception { public void toModelType_invalidName_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS, - VALID_WEDDINGS); + VALID_WEDDINGS, VALID_TASKS); String expectedMessage = Name.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -63,7 +96,7 @@ public void toModelType_invalidName_throwsIllegalValueException() { @Test public void toModelType_nullName_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, - VALID_TAGS, VALID_WEDDINGS); + VALID_TAGS, VALID_WEDDINGS, VALID_TASKS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -72,7 +105,7 @@ public void toModelType_nullName_throwsIllegalValueException() { public void toModelType_invalidPhone_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS, - VALID_WEDDINGS); + VALID_WEDDINGS, VALID_TASKS); String expectedMessage = Phone.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -80,7 +113,7 @@ public void toModelType_invalidPhone_throwsIllegalValueException() { @Test public void toModelType_nullPhone_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, - VALID_TAGS, VALID_WEDDINGS); + VALID_TAGS, VALID_WEDDINGS, VALID_TASKS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -89,7 +122,7 @@ public void toModelType_nullPhone_throwsIllegalValueException() { public void toModelType_invalidEmail_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS, - VALID_WEDDINGS); + VALID_WEDDINGS, VALID_TASKS); String expectedMessage = Email.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -97,7 +130,7 @@ public void toModelType_invalidEmail_throwsIllegalValueException() { @Test public void toModelType_nullEmail_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS, - VALID_WEDDINGS); + VALID_WEDDINGS, VALID_TASKS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -105,14 +138,15 @@ public void toModelType_nullEmail_throwsIllegalValueException() { @Test public void toModelType_blankAddress_returnsPerson() throws IllegalValueException { JsonAdaptedPerson person = - new JsonAdaptedPerson(CLIVE_NAME, CLIVE_PHONE, CLIVE_EMAIL, BLANK_ADDRESS, CLIVE_TAGS, CLIVE_WEDDINGS); + new JsonAdaptedPerson(CLIVE_NAME, CLIVE_PHONE, CLIVE_EMAIL, BLANK_ADDRESS, + CLIVE_TAGS, CLIVE_WEDDINGS, CLIVE_TASKS); assertEquals(CLIVE, person.toModelType()); } @Test public void toModelType_nullAddress_throwsIllegalValueException() { JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS, - VALID_WEDDINGS); + VALID_WEDDINGS, CLIVE_TASKS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -122,7 +156,8 @@ public void toModelType_invalidTags_throwsIllegalValueException() { List invalidTags = new ArrayList<>(VALID_TAGS); invalidTags.add(new JsonAdaptedTag(INVALID_TAG)); JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags, VALID_WEDDINGS); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags, + VALID_WEDDINGS, CLIVE_TASKS); assertThrows(IllegalValueException.class, person::toModelType); } diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java index 70d3dc93478..32da626798c 100644 --- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java +++ b/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java @@ -79,6 +79,7 @@ public void readAndSaveAddressBook_allInOrder_success() throws Exception { // Save in new file and read back jsonAddressBookStorage.saveAddressBook(original, filePath); ReadOnlyAddressBook readBack = jsonAddressBookStorage.readAddressBook(filePath).get(); + assertEquals(original, new AddressBook(readBack)); // Modify data, overwrite exiting file, and read back diff --git a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java index 8b61ff4f90f..4149796ddbb 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java @@ -20,9 +20,12 @@ public class JsonSerializableAddressBookTest { private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json"); private static final Path INVALID_TAG_FILE = TEST_DATA_FOLDER.resolve("invalidTagAddressBook.json"); private static final Path INVALID_WEDDING_FILE = TEST_DATA_FOLDER.resolve("invalidWeddingAddressBook.json"); + + private static final Path INVALID_TASK_FILE = TEST_DATA_FOLDER.resolve("invalidTaskAddressBook.json"); private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json"); private static final Path DUPLICATE_TAG_FILE = TEST_DATA_FOLDER.resolve("duplicateTagAddressBook.json"); private static final Path DUPLICATE_WEDDING_FILE = TEST_DATA_FOLDER.resolve("duplicateWeddingAddressBook.json"); + private static final Path DUPLICATE_TASK_FILE = TEST_DATA_FOLDER.resolve("duplicateTaskAddressBook.json"); @Test public void toModelType_typicalPersonsFile_success() throws Exception { @@ -30,6 +33,8 @@ public void toModelType_typicalPersonsFile_success() throws Exception { JsonSerializableAddressBook.class).get(); AddressBook addressBookFromFile = dataFromFile.toModelType(); AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook(); + System.out.println(addressBookFromFile); + System.out.println(typicalPersonsAddressBook); assertEquals(addressBookFromFile, typicalPersonsAddressBook); } diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java index 3a1a9802f8d..e962eb0cdd7 100644 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ b/src/test/java/seedu/address/testutil/PersonBuilder.java @@ -9,6 +9,7 @@ import seedu.address.model.person.Person; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.task.Task; import seedu.address.model.util.SampleDataUtil; import seedu.address.model.wedding.Wedding; @@ -32,6 +33,8 @@ public class PersonBuilder { private Set tags; private Set weddings; + private Set tasks; + /** * Creates a {@code PersonBuilder} with the default details. */ @@ -42,6 +45,7 @@ public PersonBuilder() { address = new Address(DEFAULT_ADDRESS); tags = new HashSet<>(); weddings = new HashSet<>(); + tasks = new HashSet<>(); } /** @@ -54,6 +58,7 @@ public PersonBuilder(Person personToCopy) { address = personToCopy.getAddress(); tags = new HashSet<>(personToCopy.getTags()); weddings = new HashSet<>(personToCopy.getWeddings()); + tasks = new HashSet<>(personToCopy.getTasks()); } /** @@ -104,8 +109,18 @@ public PersonBuilder withEmail(String email) { return this; } + /** + * Sets the {@code Task} objects to the {@code Person} that we are building. + * You can either modify this method to accept specific tasks like Todo, Deadline, or Event + * or adapt the SampleDataUtil to properly convert them. + */ + public PersonBuilder withTasks(String ... tasks) { + this.tasks = SampleDataUtil.getTaskSet(tasks); + return this; + } + public Person build() { - return new Person(name, phone, email, address, tags, weddings); + return new Person(name, phone, email, address, tags, weddings, tasks); } } diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java index 712f733df21..8a13de862bb 100644 --- a/src/test/java/seedu/address/testutil/TypicalPersons.java +++ b/src/test/java/seedu/address/testutil/TypicalPersons.java @@ -25,6 +25,8 @@ import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_NEIGHBOR; import static seedu.address.testutil.TypicalTags.FLORIST; import static seedu.address.testutil.TypicalTags.PHOTOGRAPHER; +import static seedu.address.testutil.TypicalTasks.DEADLINE_TASK; +import static seedu.address.testutil.TypicalTasks.TODO_TASK; import static seedu.address.testutil.TypicalWeddings.AMY_WEDDING; import static seedu.address.testutil.TypicalWeddings.BOB_WEDDING; @@ -49,7 +51,7 @@ public class TypicalPersons { .withEmail("johnd@example.com").withPhone("98765432") .withTags("owesMoney", "friends").withWeddings("Wedding 2", "Carla's Wedding").build(); public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563") - .withEmail("heinz@example.com").withAddress("wall street").build(); + .withEmail("heinz@example.com").withAddress("wall street").withTasks("todo: Buy cake").build(); public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533") .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build(); public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224") @@ -91,6 +93,8 @@ public static AddressBook getTypicalAddressBook() { ab.addTag(PHOTOGRAPHER); ab.addWedding(AMY_WEDDING); ab.addWedding(BOB_WEDDING); + ab.addTask(TODO_TASK); + ab.addTask(DEADLINE_TASK); for (Person person : getTypicalPersons()) { ab.addPerson(person); diff --git a/src/test/java/seedu/address/testutil/TypicalTasks.java b/src/test/java/seedu/address/testutil/TypicalTasks.java new file mode 100644 index 00000000000..2dcf86fccbd --- /dev/null +++ b/src/test/java/seedu/address/testutil/TypicalTasks.java @@ -0,0 +1,37 @@ +package seedu.address.testutil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; + +/** + * A utility class containing a list of {@code Task} objects to be used in tests. + */ +public class TypicalTasks { + + // Strings for Task Descriptions + public static final String VALID_TODO_DESCRIPTION = "Buy groceries"; + public static final String VALID_DEADLINE_DESCRIPTION = "Submit report"; + public static final String VALID_EVENT_DESCRIPTION = "Project meeting"; + + // Dates for Deadline and Event tasks + public static final String VALID_DEADLINE_DATE = "2024-12-31"; + public static final String VALID_EVENT_START_DATE = "2024-10-10"; + public static final String VALID_EVENT_END_DATE = "2024-10-11"; + + // Sample Tasks + public static final Todo TODO_TASK = new Todo(VALID_TODO_DESCRIPTION); + public static final Deadline DEADLINE_TASK = new Deadline(VALID_DEADLINE_DESCRIPTION, VALID_DEADLINE_DATE); + public static final Event EVENT_TASK = new Event(VALID_EVENT_DESCRIPTION, + VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + + // Returns a list of all typical tasks + public static List getTypicalTasks() { + return new ArrayList<>(Arrays.asList(TODO_TASK, DEADLINE_TASK, EVENT_TASK)); + } +} From b74920551d9d1a3b857fb6d7aab25be55f981bcd Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 15:06:32 +0800 Subject: [PATCH 14/25] Resolve comments in pull request --- .../logic/commands/CreateTaskCommand.java | 1 - .../address/logic/parser/ParserUtil.java | 43 ++++++++++++++++--- .../java/seedu/address/model/AddressBook.java | 2 +- .../java/seedu/address/model/task/Task.java | 17 -------- .../address/model/task/UniqueTaskList.java | 2 +- .../address/model/util/SampleDataUtil.java | 10 ++--- 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java b/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java index 8155259fc5c..051c33f480e 100644 --- a/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java +++ b/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java @@ -27,7 +27,6 @@ public class CreateTaskCommand extends Command { + PREFIX_TASK + "deadline Submit proposal /by 2024-10-31"; public static final String MESSAGE_SUCCESS = "New task added: %1$s"; - public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the address book"; private final HashSet tasksToAdd; diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 96028adb377..d5ae462db8f 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -49,6 +49,10 @@ public static Index parseIndex(String oneBasedIndex) throws ParseException { return Index.fromOneBased(Integer.parseInt(trimmedIndex)); } + // ======================================================================= + // Person Parsing Methods + // ======================================================================= + /** * Parses a {@code String name} into a {@code Name}. * Leading and trailing whitespaces will be trimmed. @@ -133,6 +137,10 @@ public static Set parseTags(Collection tags) throws ParseException return tagSet; } + // ======================================================================= + // Task Parsing Methods + // ======================================================================= + /** * Parses a task description to determine the task type and details. * @@ -174,6 +182,7 @@ public static Set parseTasks(List taskDescriptions) throws ParseEx */ private static ParsedTask parseTaskTypeAndDetails(String taskDescription) throws ParseException { requireNonNull(taskDescription); + // Splits the descriptions into a maximum of 2 tokens, based on first whitespace present String[] tokens = taskDescription.split("\\s+", 2); if (tokens.length < 2) { @@ -186,11 +195,23 @@ private static ParsedTask parseTaskTypeAndDetails(String taskDescription) throws return new ParsedTask(taskType, taskDetails); } - + /** + * Parses the task details for a "Todo" task and returns a {@code Todo} object. + * + * @param taskDetails The task details to parse. + * @return A Todo object. + */ private static Todo parseTodoTask(String taskDetails) { return new Todo(taskDetails.trim()); } + /** + * Parses the task details for a "Deadline" task and returns a {@code Deadline} object. + * + * @param taskDetails The task details to parse. + * @return A Deadline object. + * @throws ParseException if the format is invalid. + */ private static Deadline parseDeadlineTask(String taskDetails) throws ParseException { String[] deadlineParts = taskDetails.split("/by ", 2); // Check if both description and deadline are present @@ -204,6 +225,13 @@ private static Deadline parseDeadlineTask(String taskDetails) throws ParseExcept return new Deadline(description, byDate); } + /** + * Parses the task details for an "Event" task and returns an {@code Event} object. + * + * @param taskDetails The task details to parse. + * @return An Event object. + * @throws ParseException if the format is invalid. + */ private static Event parseEventTask(String taskDetails) throws ParseException { String[] eventParts = taskDetails.split("/from", 2); if (eventParts.length < 2 || !eventParts[1].contains("/to")) { @@ -211,11 +239,11 @@ private static Event parseEventTask(String taskDetails) throws ParseException { } String description = eventParts[0].trim(); String[] dateParts = eventParts[1].split("/to", 2); - String startDateStr = dateParts[0].trim(); - String endDateStr = dateParts[1].trim(); - validateDateFormat(startDateStr, endDateStr); + String startDate = dateParts[0].trim(); + String endDate = dateParts[1].trim(); + validateDateFormat(startDate, endDate); - return new Event(description, startDateStr, endDateStr); + return new Event(description, startDate, endDate); } /** @@ -251,8 +279,9 @@ private static void validateDateFormat(String fromDate, String toDate) throws Pa } } - - + // ======================================================================= + // Wedding Parsing Methods + // ======================================================================= /** * Parses {@code String} wedding into {@code Wedding} object. diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java index 7cacb8c6e9a..8b5c133014d 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/seedu/address/model/AddressBook.java @@ -169,7 +169,7 @@ public boolean hasTask(Task task) { /** * Replaces the given task {@code target} in the list with {@code editedTask}. * {@code target} must exist in the address book. - * The tag identity of {@code editedTask} must not be the same as another existing task in the address book. + * The task identity of {@code editedTask} must not be the same as another existing task in the address book. */ public void setTask(Task target, Task editedTask) { requireNonNull(editedTask); diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java index 53d50dad379..6dd50814529 100644 --- a/src/main/java/seedu/address/model/task/Task.java +++ b/src/main/java/seedu/address/model/task/Task.java @@ -63,23 +63,6 @@ public void markAsUndone() { isDone = false; } - /** - * Returns the presence of the given keyword within the description. - * "true" if the keyword is present, "false" if the keyword is not. - * - * @param keyword The supplied keyword string. - * @return The boolean indicating presence of the keyword - */ - public boolean hasKeyword(String keyword) { - String[] descriptionArray = description.split(" "); - for (String word : descriptionArray) { - if (word.equals(keyword)) { - return true; - } - } - return false; - } - /** * Returns the presence of the given keyword if it is * within a partial/full word in the description, case-insensitive. diff --git a/src/main/java/seedu/address/model/task/UniqueTaskList.java b/src/main/java/seedu/address/model/task/UniqueTaskList.java index 6c1fb299d34..fa485116e85 100644 --- a/src/main/java/seedu/address/model/task/UniqueTaskList.java +++ b/src/main/java/seedu/address/model/task/UniqueTaskList.java @@ -135,7 +135,7 @@ public String toString() { } /** - * Returns true if {@code persons} contains only unique persons. + * Returns true if {@code tasks} contains only unique tasks. */ private boolean tasksAreUnique(List tasks) { for (int i = 0; i < tasks.size() - 1; i++) { diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 4725a16a52b..d609ab386b8 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -30,17 +30,17 @@ public static Person[] getSamplePersons() { new Address("Blk 30 Geylang Street 29, #06-40"), getTagSet("friends"), getWeddingSet("Casey's Wedding"), - getTaskSet("Finalize Catering Menu")), + getTaskSet("todo: Finalize Catering Menu")), new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), getTagSet("colleagues", "friends"), getWeddingSet(), - getTaskSet("Set Up Venue Decorations")), + getTaskSet("todo: Set Up Venue Decorations")), new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), getTagSet("neighbours"), getWeddingSet("Wedding August 2029", "Wedding 2"), - getTaskSet("Send invitations")), + getTaskSet("todo: Send invitations")), new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), getTagSet("family"), @@ -50,12 +50,12 @@ public static Person[] getSamplePersons() { new Address("Blk 47 Tampines Street 20, #17-35"), getTagSet("classmates"), getWeddingSet("Casey's Wedding"), - getTaskSet("Schedule Hair and Makeup Trials")), + getTaskSet("deadline: Schedule Hair and Makeup Trials")), new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), new Address("Blk 45 Aljunied Street 85, #11-31"), getTagSet("colleagues"), getWeddingSet("Wedding 10"), - getTaskSet("Schedule Hair and Makeup Trials")) + getTaskSet("event: Schedule Hair and Makeup Trials")) }; } From a49e78ddc1ca6fa609113071af55ccafa9d07b2b Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 17:40:37 +0800 Subject: [PATCH 15/25] Modify how date and description is stored --- .../java/seedu/address/model/task/Date.java | 73 +++++++++++++++++++ .../seedu/address/model/task/Deadline.java | 9 +-- .../seedu/address/model/task/Description.java | 62 ++++++++++++++++ .../java/seedu/address/model/task/Event.java | 20 +++-- .../java/seedu/address/model/task/Task.java | 11 ++- .../java/seedu/address/model/task/Todo.java | 9 +++ .../storage/JsonAdaptedDeadlineTest.java | 2 + .../address/storage/JsonAdaptedEventTest.java | 2 + .../address/storage/JsonAdaptedTaskTest.java | 2 + .../address/storage/JsonAdaptedTodoTest.java | 2 + 10 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 src/main/java/seedu/address/model/task/Date.java create mode 100644 src/main/java/seedu/address/model/task/Description.java create mode 100644 src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java create mode 100644 src/test/java/seedu/address/storage/JsonAdaptedEventTest.java create mode 100644 src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java create mode 100644 src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java diff --git a/src/main/java/seedu/address/model/task/Date.java b/src/main/java/seedu/address/model/task/Date.java new file mode 100644 index 00000000000..cb77c259770 --- /dev/null +++ b/src/main/java/seedu/address/model/task/Date.java @@ -0,0 +1,73 @@ +package seedu.address.model.task; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +/** + * Represents a Task's date (either start or end date). + * Guarantees: immutable; is valid as declared in {@link #isValidDate(String)}. + */ +public class Date { + public static final String MESSAGE_CONSTRAINTS = "Date should be in the format yyyy-MM-dd."; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + private final LocalDate date; + + /** + * Constructs a {@code TaskDate}. + * + * @param date A valid date string in the format "yyyy-MM-dd". + */ + public Date(String date) { + Objects.requireNonNull(date); + this.date = LocalDate.parse(date, FORMATTER); + } + + /** + * Checks if the given string is a valid date in the format "yyyy-MM-dd". + */ + public static boolean isValidDate(String test) { + try { + LocalDate.parse(test, FORMATTER); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * Returns the formatted date. + */ + public String format(DateTimeFormatter formatter) { + return date.format(formatter); + } + + public LocalDate getDate() { + return date; + } + + @Override + public String toString() { + return date.format(FORMATTER); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof Date)) { + return false; + } + + Date otherDate = (Date) other; + return date.equals(otherDate.date); + } + + @Override + public int hashCode() { + return Objects.hash(date); + } +} diff --git a/src/main/java/seedu/address/model/task/Deadline.java b/src/main/java/seedu/address/model/task/Deadline.java index f7e9c8cccd7..9304310818e 100644 --- a/src/main/java/seedu/address/model/task/Deadline.java +++ b/src/main/java/seedu/address/model/task/Deadline.java @@ -1,6 +1,5 @@ package seedu.address.model.task; -import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Objects; @@ -11,7 +10,7 @@ public class Deadline extends Task { public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private LocalDate by; + private Date by; /** @@ -22,7 +21,7 @@ public class Deadline extends Task { */ public Deadline(String description, String by) { super(description); - this.by = LocalDate.parse(by, FORMATTER); + this.by = new Date(by); } /** @@ -34,11 +33,11 @@ public Deadline(String description, String by) { */ public Deadline(String description, String by, boolean isDone) { super(description); - this.by = LocalDate.parse(by, FORMATTER); + this.by = new Date(by); this.isDone = isDone; } - public LocalDate getBy() { + public Date getBy() { return by; } diff --git a/src/main/java/seedu/address/model/task/Description.java b/src/main/java/seedu/address/model/task/Description.java new file mode 100644 index 00000000000..f75eb6e1311 --- /dev/null +++ b/src/main/java/seedu/address/model/task/Description.java @@ -0,0 +1,62 @@ +package seedu.address.model.task; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a Task's description in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidDescription(String)}. + */ +public class Description { + + public static final String MESSAGE_CONSTRAINTS = "Descriptions should not be blank"; + + /* + * The description must not be blank. + */ + public static final String VALIDATION_REGEX = "[^\\s].*"; + + public final String value; + + /** + * Constructs a {@code Description}. + * + * @param description A valid description. + */ + public Description(String description) { + requireNonNull(description); + checkArgument(isValidDescription(description), MESSAGE_CONSTRAINTS); + value = description; + } + + /** + * Returns true if a given string is a valid description. + */ + public static boolean isValidDescription(String test) { + return test.matches(VALIDATION_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof Description)) { + return false; + } + + Description otherDescription = (Description) other; + return value.equals(otherDescription.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/task/Event.java b/src/main/java/seedu/address/model/task/Event.java index 1acded32f8a..7b20f2f4b55 100644 --- a/src/main/java/seedu/address/model/task/Event.java +++ b/src/main/java/seedu/address/model/task/Event.java @@ -1,6 +1,5 @@ package seedu.address.model.task; -import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Objects; @@ -9,9 +8,8 @@ * It extends the Task class and adds LocalDate fields to store the start and end dates of the event. */ public class Event extends Task { - public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private LocalDate from; - private LocalDate to; + private Date from; + private Date to; /** @@ -23,8 +21,8 @@ public class Event extends Task { */ public Event(String description, String from, String to) { super(description); - this.from = LocalDate.parse(from, FORMATTER); - this.to = LocalDate.parse(to, FORMATTER); + this.from = new Date(from); + this.to = new Date(to); } /** @@ -37,16 +35,16 @@ public Event(String description, String from, String to) { */ public Event(String description, String from, String to, boolean isDone) { super(description); - this.from = LocalDate.parse(from, FORMATTER); - this.to = LocalDate.parse(to, FORMATTER); + this.from = new Date(from); + this.to = new Date(to); this.isDone = isDone; } - public LocalDate getFrom() { + public Date getFrom() { return from; } - public LocalDate getTo() { + public Date getTo() { return to; } @@ -70,7 +68,7 @@ public boolean equals(Object other) { return description.equals(otherEvent.description) && isDone == otherEvent.isDone && from.equals(otherEvent.from) - && to.equals(equals(otherEvent.to)); + && to.equals(otherEvent.to); } @Override diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java index 6dd50814529..c88c3d0e265 100644 --- a/src/main/java/seedu/address/model/task/Task.java +++ b/src/main/java/seedu/address/model/task/Task.java @@ -7,7 +7,7 @@ * It serves as the base class for more specific types of tasks such as Todo, Deadline, and Event. */ public class Task { - protected String description; + protected Description description; protected boolean isDone; /** @@ -17,6 +17,11 @@ public class Task { * @param description The description of the task. */ public Task(String description) { + this.description = new Description(description); + this.isDone = false; + } + + public Task(Description description) { this.description = description; this.isDone = false; } @@ -37,7 +42,7 @@ public String getStatusIcon() { * @return The description of the task as a String. */ public String getDescription() { - return this.description; + return this.description.toString(); } /** @@ -73,7 +78,7 @@ public void markAsUndone() { */ public boolean hasKeywordInPartialDescription(String keyword) { String lowerCaseKeyword = keyword.toLowerCase(); - String[] descriptionArray = description.split(" "); + String[] descriptionArray = description.toString().split(" "); for (String word : descriptionArray) { String lowerCaseWord = word.toLowerCase(); if (lowerCaseWord.contains(lowerCaseKeyword)) { diff --git a/src/main/java/seedu/address/model/task/Todo.java b/src/main/java/seedu/address/model/task/Todo.java index 2680a1aa099..b6be90f1647 100644 --- a/src/main/java/seedu/address/model/task/Todo.java +++ b/src/main/java/seedu/address/model/task/Todo.java @@ -16,6 +16,10 @@ public Todo(String description) { super(description); } + public Todo(Description description) { + super(description); + } + /** * Constructs a Todo task with the specified description and isDone status. * @@ -27,6 +31,11 @@ public Todo(String description, boolean isDone) { this.isDone = isDone; } + public Todo(Description description, boolean isDone) { + super(description); + this.isDone = isDone; + } + /** * Returns true if both Todo tasks have the same data fields. * This defines a stronger notion of equality between two Todo tasks. diff --git a/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java b/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java new file mode 100644 index 00000000000..67defd05f93 --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java @@ -0,0 +1,2 @@ +package seedu.address.storage;public class JsonAdaptedDeadlineTest { +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java b/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java new file mode 100644 index 00000000000..1b24178cf50 --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java @@ -0,0 +1,2 @@ +package seedu.address.storage;public class JsonAdaptedEventTest { +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java new file mode 100644 index 00000000000..396ab1b63c2 --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java @@ -0,0 +1,2 @@ +package seedu.address.storage;public class JsonAdaptedTaskTest { +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java new file mode 100644 index 00000000000..1f7ca5522be --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java @@ -0,0 +1,2 @@ +package seedu.address.storage;public class JsonAdaptedTodoTest { +} From 669f2b5a6c87cb607c590f45d1f20c6cff594a44 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 17:41:20 +0800 Subject: [PATCH 16/25] Add tests for JsonAdapted task classes --- .../address/storage/JsonAdaptedDeadline.java | 28 ++++++- .../address/storage/JsonAdaptedEvent.java | 30 +++++++- .../address/storage/JsonAdaptedTask.java | 22 +++++- .../address/storage/JsonAdaptedTodo.java | 15 ++-- .../storage/JsonAdaptedDeadlineTest.java | 55 +++++++++++++- .../address/storage/JsonAdaptedEventTest.java | 71 ++++++++++++++++- .../address/storage/JsonAdaptedTaskTest.java | 76 ++++++++++++++++++- .../address/storage/JsonAdaptedTodoTest.java | 45 ++++++++++- 8 files changed, 323 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java index 118c38c58fb..9324c96ff07 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java @@ -1,9 +1,15 @@ package seedu.address.storage; +import java.time.LocalDate; +import java.time.format.DateTimeParseException; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Date; import seedu.address.model.task.Deadline; +import seedu.address.model.task.Description; +import seedu.address.model.task.Task; /** * Jackson-friendly version of {@link Deadline}. @@ -32,10 +38,24 @@ public JsonAdaptedDeadline(Deadline source) { } /** - * Converts this Jackson-friendly adapted Deadline object into the model's {@code Deadline} object. + * Converts this Jackson-friendly adapted deadline object into the model's {@code Deadline} object. + * + * @throws IllegalValueException if there are any data constraints violated in the adapted deadline. */ - public Deadline toModelType() { - return new Deadline(description, by); + @Override + public Task toModelType() throws IllegalValueException { + Description modelDescription = toModelDescription(); // Convert string to Description + if (by == null || by.isEmpty()) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "Deadline")); + } + + try { + LocalDate.parse(by, Deadline.FORMATTER); + } catch (DateTimeParseException e) { + throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS); + } + + return new Deadline(modelDescription.toString(), by, isDone); } } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java index ccbeb5d424a..8fb480d876d 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java @@ -1,9 +1,17 @@ package seedu.address.storage; + +import java.time.LocalDate; +import java.time.format.DateTimeParseException; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Date; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Description; import seedu.address.model.task.Event; +import seedu.address.model.task.Task; /** * Jackson-friendly version of {@link Event}. @@ -35,10 +43,24 @@ public JsonAdaptedEvent(Event source) { } /** - * Converts this Jackson-friendly adapted Event object into the model's {@code Event} object. + * Converts this Jackson-friendly adapted event object into the model's {@code Event} object. + * + * @throws IllegalValueException if there are any data constraints violated in the adapted event. */ - public Event toModelType() { - return new Event(description, from, to); + @Override + public Task toModelType() throws IllegalValueException { + Description modelDescription = toModelDescription(); // Convert string to Description + if (from == null || to == null || from.isEmpty() || to.isEmpty()) { + throw new IllegalValueException(String.format(JsonAdaptedTask.MISSING_FIELD_MESSAGE_FORMAT, "Event dates")); + } + + try { + LocalDate.parse(from, Deadline.FORMATTER); + LocalDate.parse(to, Deadline.FORMATTER); + } catch (DateTimeParseException e) { + throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS); + } + return new Event(modelDescription.toString(), from, to, isDone); } } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java index 6000a47edc5..739b1481e70 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTask.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java @@ -4,7 +4,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; - +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Description; import seedu.address.model.task.Task; /** @@ -24,6 +25,8 @@ }) public abstract class JsonAdaptedTask { + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Task's %s field is missing!"; + protected final String description; protected final boolean isDone; @@ -40,5 +43,20 @@ public JsonAdaptedTask(@JsonProperty("description") String description, this.isDone = isDone; } - public abstract Task toModelType(); + public abstract Task toModelType() throws IllegalValueException; + + /** + * Converts the description string into a {@code Description} object, validating it in the process. + * + * @throws IllegalValueException if the description is invalid. + */ + protected Description toModelDescription() throws IllegalValueException { + if (description == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "Description")); + } + if (!Description.isValidDescription(description)) { + throw new IllegalValueException(Description.MESSAGE_CONSTRAINTS); + } + return new Description(description); + } } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java index cdd6ee4248d..daddc2c1fb8 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java @@ -2,8 +2,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Description; +import seedu.address.model.task.Task; import seedu.address.model.task.Todo; /** @@ -27,13 +28,17 @@ public JsonAdaptedTodo(Todo source) { super(source.getDescription(), source.getIsDone()); } + + /** - * Converts this Jackson-friendly adapted Todo object into the model's {@code Todo} object. + * Converts this Jackson-friendly adapted todo object into the model's {@code Todo} object. * - * @throws IllegalValueException if there were any data constraints violated in the adapted todo task. + * @throws IllegalValueException if there are any data constraints violated in the adapted todo. */ - public Todo toModelType() { - return new Todo(description); + @Override + public Task toModelType() throws IllegalValueException { + Description modelDescription = toModelDescription(); + return new Todo(modelDescription.toString(), isDone); } } diff --git a/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java b/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java index 67defd05f93..e2985293398 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedDeadlineTest.java @@ -1,2 +1,55 @@ -package seedu.address.storage;public class JsonAdaptedDeadlineTest { +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Description; + +public class JsonAdaptedDeadlineTest { + + private static final String VALID_DESCRIPTION = "Submit assignment"; + private static final String VALID_BY = "2023-12-31"; + private static final boolean IS_DONE = false; + + private static final String INVALID_DESCRIPTION = ""; + private static final String INVALID_BY = "32-12-2023"; + + @Test + public void toModelType_validDeadlineDetails_returnsDeadline() throws Exception { + JsonAdaptedDeadline jsonAdaptedDeadline = new JsonAdaptedDeadline(VALID_DESCRIPTION, IS_DONE, VALID_BY); + Deadline expectedDeadline = new Deadline(VALID_DESCRIPTION, VALID_BY, IS_DONE); + assertEquals(expectedDeadline, jsonAdaptedDeadline.toModelType()); + } + + @Test + public void toModelType_invalidDescription_throwsIllegalValueException() { + JsonAdaptedDeadline jsonAdaptedDeadline = new JsonAdaptedDeadline(INVALID_DESCRIPTION, IS_DONE, VALID_BY); + String expectedMessage = Description.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedDeadline::toModelType); + } + + @Test + public void toModelType_invalidByDate_throwsIllegalValueException() { + JsonAdaptedDeadline jsonAdaptedDeadline = new JsonAdaptedDeadline(VALID_DESCRIPTION, IS_DONE, INVALID_BY); + String expectedMessage = seedu.address.model.task.Date.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedDeadline::toModelType); + } + + @Test + public void toModelType_nullByDate_throwsIllegalValueException() { + JsonAdaptedDeadline jsonAdaptedDeadline = new JsonAdaptedDeadline(VALID_DESCRIPTION, IS_DONE, null); + String expectedMessage = String.format(JsonAdaptedTask.MISSING_FIELD_MESSAGE_FORMAT, "Deadline"); + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedDeadline::toModelType); + } + + @Test + public void toModelType_validDeadlineWithDone_returnsCorrectly() throws Exception { + JsonAdaptedDeadline jsonAdaptedDeadline = new JsonAdaptedDeadline(VALID_DESCRIPTION, true, VALID_BY); + Deadline expectedDeadline = new Deadline(VALID_DESCRIPTION, VALID_BY, true); + assertEquals(expectedDeadline, jsonAdaptedDeadline.toModelType()); + } } diff --git a/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java b/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java index 1b24178cf50..4ef009722fb 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedEventTest.java @@ -1,2 +1,71 @@ -package seedu.address.storage;public class JsonAdaptedEventTest { +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Description; +import seedu.address.model.task.Event; + +public class JsonAdaptedEventTest { + + private static final String VALID_DESCRIPTION = "Team meeting"; + private static final String VALID_FROM = "2023-10-01"; + private static final String VALID_TO = "2023-10-02"; + private static final boolean IS_DONE = false; + + private static final String INVALID_DESCRIPTION = ""; + private static final String INVALID_FROM = "invalid-date"; + private static final String INVALID_TO = "invalid-date"; + + @Test + public void toModelType_validEventDetails_returnsEvent() throws Exception { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(VALID_DESCRIPTION, IS_DONE, VALID_FROM, VALID_TO); + Event expectedEvent = new Event(VALID_DESCRIPTION, VALID_FROM, VALID_TO, IS_DONE); + assertEquals(expectedEvent, jsonAdaptedEvent.toModelType()); + } + + @Test + public void toModelType_invalidDescription_throwsIllegalValueException() { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(INVALID_DESCRIPTION, IS_DONE, VALID_FROM, VALID_TO); + String expectedMessage = Description.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedEvent::toModelType); + } + + @Test + public void toModelType_invalidFromDate_throwsIllegalValueException() { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(VALID_DESCRIPTION, IS_DONE, INVALID_FROM, VALID_TO); + String expectedMessage = seedu.address.model.task.Date.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedEvent::toModelType); + } + + @Test + public void toModelType_invalidToDate_throwsIllegalValueException() { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(VALID_DESCRIPTION, IS_DONE, VALID_FROM, INVALID_TO); + String expectedMessage = seedu.address.model.task.Date.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedEvent::toModelType); + } + + @Test + public void toModelType_nullFromDate_throwsIllegalValueException() { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(VALID_DESCRIPTION, IS_DONE, null, VALID_TO); + String expectedMessage = String.format(JsonAdaptedTask.MISSING_FIELD_MESSAGE_FORMAT, "Event dates"); + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedEvent::toModelType); + } + + @Test + public void toModelType_nullToDate_throwsIllegalValueException() { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(VALID_DESCRIPTION, IS_DONE, VALID_FROM, null); + String expectedMessage = String.format(JsonAdaptedTask.MISSING_FIELD_MESSAGE_FORMAT, "Event dates"); + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedEvent::toModelType); + } + + @Test + public void toModelType_validEventWithDone_returnsCorrectly() throws Exception { + JsonAdaptedEvent jsonAdaptedEvent = new JsonAdaptedEvent(VALID_DESCRIPTION, true, VALID_FROM, VALID_TO); + Event expectedEvent = new Event(VALID_DESCRIPTION, VALID_FROM, VALID_TO, true); + assertEquals(expectedEvent, jsonAdaptedEvent.toModelType()); + } } diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java index 396ab1b63c2..8adc475f112 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java @@ -1,2 +1,76 @@ -package seedu.address.storage;public class JsonAdaptedTaskTest { +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.storage.JsonAdaptedTask.MISSING_FIELD_MESSAGE_FORMAT; +import static seedu.address.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Date; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Description; +import seedu.address.model.task.Event; +import seedu.address.model.task.Todo; + +public class JsonAdaptedTaskTest { + + private static final String INVALID_DESCRIPTION = ""; + private static final String INVALID_DEADLINE_DATE = "32-12-2023"; // Invalid date + private static final String INVALID_EVENT_DATE = "invalid-date"; // Invalid date format + + private static final String VALID_TODO_DESCRIPTION = "Buy groceries"; + private static final String VALID_DEADLINE_DESCRIPTION = "Submit assignment"; + private static final String VALID_DEADLINE_DATE = "2023-12-31"; + private static final String VALID_EVENT_DESCRIPTION = "Team meeting"; + private static final String VALID_EVENT_START_DATE = "2023-10-01"; + private static final String VALID_EVENT_END_DATE = "2023-10-02"; + + @Test + public void toModelType_validTodoDetails_returnsTodo() throws Exception { + JsonAdaptedTodo todo = new JsonAdaptedTodo(VALID_TODO_DESCRIPTION, false); + Todo expectedTodo = new Todo(VALID_TODO_DESCRIPTION); + assertEquals(expectedTodo, todo.toModelType()); + } + + @Test + public void toModelType_invalidTodoDescription_throwsIllegalValueException() { + JsonAdaptedTodo todo = new JsonAdaptedTodo(INVALID_DESCRIPTION, false); + String expectedMessage = Description.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, todo::toModelType); + } + + @Test + public void toModelType_validDeadlineDetails_returnsDeadline() throws Exception { + JsonAdaptedDeadline deadline = new JsonAdaptedDeadline(VALID_DEADLINE_DESCRIPTION, false, VALID_DEADLINE_DATE); + Deadline expectedDeadline = new Deadline(VALID_DEADLINE_DESCRIPTION, VALID_DEADLINE_DATE); + assertEquals(expectedDeadline, deadline.toModelType()); + } + @Test + public void toModelType_invalidDeadlineDate_throwsIllegalValueException() { + JsonAdaptedDeadline deadline = new JsonAdaptedDeadline(VALID_DEADLINE_DESCRIPTION, false, INVALID_DEADLINE_DATE); + String expectedMessage = Date.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, deadline::toModelType); + } + + @Test + public void toModelType_validEventDetails_returnsEvent() throws Exception { + JsonAdaptedEvent event = new JsonAdaptedEvent(VALID_EVENT_DESCRIPTION, false, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + Event expectedEvent = new Event(VALID_EVENT_DESCRIPTION, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + assertEquals(expectedEvent, event.toModelType()); + } + + @Test + public void toModelType_invalidEventDates_throwsIllegalValueException() { + JsonAdaptedEvent event = new JsonAdaptedEvent(VALID_EVENT_DESCRIPTION, false, INVALID_EVENT_DATE, INVALID_EVENT_DATE); + String expectedMessage = Date.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, event::toModelType); + } + + @Test + public void toModelType_nullDescription_throwsIllegalValueException() { + JsonAdaptedTodo todo = new JsonAdaptedTodo(null, false); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, "Description"); + assertThrows(IllegalValueException.class, expectedMessage, todo::toModelType); + } } diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java index 1f7ca5522be..b8cac1a900c 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java @@ -1,2 +1,45 @@ -package seedu.address.storage;public class JsonAdaptedTodoTest { +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.task.Description; +import seedu.address.model.task.Todo; + +public class JsonAdaptedTodoTest { + + private static final String VALID_DESCRIPTION = "Buy groceries"; + private static final String INVALID_DESCRIPTION = ""; // Invalid due to being empty + private static final boolean IS_DONE = false; // Example completion status + + @Test + public void toModelType_validTodoDetails_returnsTodo() throws Exception { + JsonAdaptedTodo jsonAdaptedTodo = new JsonAdaptedTodo(VALID_DESCRIPTION, IS_DONE); + Todo expectedTodo = new Todo(VALID_DESCRIPTION); // Expected model Todo + assertEquals(expectedTodo, jsonAdaptedTodo.toModelType()); + } + + @Test + public void toModelType_invalidTodoDescription_throwsIllegalValueException() { + JsonAdaptedTodo jsonAdaptedTodo = new JsonAdaptedTodo(INVALID_DESCRIPTION, IS_DONE); + String expectedMessage = Description.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedTodo::toModelType); + } + + @Test + public void toModelType_nullDescription_throwsIllegalValueException() { + JsonAdaptedTodo jsonAdaptedTodo = new JsonAdaptedTodo(null, IS_DONE); + String expectedMessage = String.format(JsonAdaptedTask.MISSING_FIELD_MESSAGE_FORMAT, "Description"); + assertThrows(IllegalValueException.class, expectedMessage, jsonAdaptedTodo::toModelType); + } + + @Test + public void toModelType_validTodoWithDone_returnsCorrectly() throws Exception { + JsonAdaptedTodo jsonAdaptedTodo = new JsonAdaptedTodo(VALID_DESCRIPTION, true); + Todo expectedTodo = new Todo(VALID_DESCRIPTION, true); // Done Todo + assertEquals(expectedTodo, jsonAdaptedTodo.toModelType()); + } } From a6e68ed7d570b985aa70a07052b907304ed20794 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 17:45:04 +0800 Subject: [PATCH 17/25] Fix checkstyle issues --- src/main/java/seedu/address/model/task/Task.java | 6 ++++++ src/main/java/seedu/address/model/task/Todo.java | 6 ++++++ .../address/storage/JsonAdaptedDeadline.java | 1 + .../seedu/address/storage/JsonAdaptedEvent.java | 1 + .../seedu/address/storage/JsonAdaptedTask.java | 1 + .../seedu/address/storage/JsonAdaptedTodo.java | 1 + .../address/storage/JsonAdaptedTaskTest.java | 16 ++++++++++------ .../address/storage/JsonAdaptedTodoTest.java | 8 ++++---- 8 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java index c88c3d0e265..64476d6adda 100644 --- a/src/main/java/seedu/address/model/task/Task.java +++ b/src/main/java/seedu/address/model/task/Task.java @@ -21,6 +21,12 @@ public Task(String description) { this.isDone = false; } + /** + * Constructs a Task with the specified Description type description. + * The task is initially marked as not done. + * + * @param description The description of the task. + */ public Task(Description description) { this.description = description; this.isDone = false; diff --git a/src/main/java/seedu/address/model/task/Todo.java b/src/main/java/seedu/address/model/task/Todo.java index b6be90f1647..62068075431 100644 --- a/src/main/java/seedu/address/model/task/Todo.java +++ b/src/main/java/seedu/address/model/task/Todo.java @@ -31,6 +31,12 @@ public Todo(String description, boolean isDone) { this.isDone = isDone; } + /** + * Constructs a Todo task with the specified Description type description and isDone status. + * + * @param description The description of the todo task. + * @param isDone The completion status of the event. + */ public Todo(Description description, boolean isDone) { super(description); this.isDone = isDone; diff --git a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java index 9324c96ff07..1452677298d 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedDeadline.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.task.Date; import seedu.address.model.task.Deadline; diff --git a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java index 8fb480d876d..0e9423e533e 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedEvent.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedEvent.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.task.Date; import seedu.address.model.task.Deadline; diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java index 739b1481e70..a327f749378 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTask.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.task.Description; import seedu.address.model.task.Task; diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java index daddc2c1fb8..35200fd4d2a 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTodo.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTodo.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.task.Description; import seedu.address.model.task.Task; diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java index 8adc475f112..796d624b53f 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedTaskTest.java @@ -16,8 +16,8 @@ public class JsonAdaptedTaskTest { private static final String INVALID_DESCRIPTION = ""; - private static final String INVALID_DEADLINE_DATE = "32-12-2023"; // Invalid date - private static final String INVALID_EVENT_DATE = "invalid-date"; // Invalid date format + private static final String INVALID_DEADLINE_DATE = "32-12-2023"; + private static final String INVALID_EVENT_DATE = "invalid-date"; private static final String VALID_TODO_DESCRIPTION = "Buy groceries"; private static final String VALID_DEADLINE_DESCRIPTION = "Submit assignment"; @@ -42,27 +42,31 @@ public void toModelType_invalidTodoDescription_throwsIllegalValueException() { @Test public void toModelType_validDeadlineDetails_returnsDeadline() throws Exception { - JsonAdaptedDeadline deadline = new JsonAdaptedDeadline(VALID_DEADLINE_DESCRIPTION, false, VALID_DEADLINE_DATE); + JsonAdaptedDeadline deadline = new JsonAdaptedDeadline(VALID_DEADLINE_DESCRIPTION, + false, VALID_DEADLINE_DATE); Deadline expectedDeadline = new Deadline(VALID_DEADLINE_DESCRIPTION, VALID_DEADLINE_DATE); assertEquals(expectedDeadline, deadline.toModelType()); } @Test public void toModelType_invalidDeadlineDate_throwsIllegalValueException() { - JsonAdaptedDeadline deadline = new JsonAdaptedDeadline(VALID_DEADLINE_DESCRIPTION, false, INVALID_DEADLINE_DATE); + JsonAdaptedDeadline deadline = new JsonAdaptedDeadline(VALID_DEADLINE_DESCRIPTION, + false, INVALID_DEADLINE_DATE); String expectedMessage = Date.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, deadline::toModelType); } @Test public void toModelType_validEventDetails_returnsEvent() throws Exception { - JsonAdaptedEvent event = new JsonAdaptedEvent(VALID_EVENT_DESCRIPTION, false, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + JsonAdaptedEvent event = new JsonAdaptedEvent(VALID_EVENT_DESCRIPTION, + false, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); Event expectedEvent = new Event(VALID_EVENT_DESCRIPTION, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); assertEquals(expectedEvent, event.toModelType()); } @Test public void toModelType_invalidEventDates_throwsIllegalValueException() { - JsonAdaptedEvent event = new JsonAdaptedEvent(VALID_EVENT_DESCRIPTION, false, INVALID_EVENT_DATE, INVALID_EVENT_DATE); + JsonAdaptedEvent event = new JsonAdaptedEvent(VALID_EVENT_DESCRIPTION, + false, INVALID_EVENT_DATE, INVALID_EVENT_DATE); String expectedMessage = Date.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, event::toModelType); } diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java index b8cac1a900c..c2ddc2c9b8f 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedTodoTest.java @@ -12,13 +12,13 @@ public class JsonAdaptedTodoTest { private static final String VALID_DESCRIPTION = "Buy groceries"; - private static final String INVALID_DESCRIPTION = ""; // Invalid due to being empty - private static final boolean IS_DONE = false; // Example completion status + private static final String INVALID_DESCRIPTION = ""; // Invalid due to being empty + private static final boolean IS_DONE = false; @Test public void toModelType_validTodoDetails_returnsTodo() throws Exception { JsonAdaptedTodo jsonAdaptedTodo = new JsonAdaptedTodo(VALID_DESCRIPTION, IS_DONE); - Todo expectedTodo = new Todo(VALID_DESCRIPTION); // Expected model Todo + Todo expectedTodo = new Todo(VALID_DESCRIPTION); assertEquals(expectedTodo, jsonAdaptedTodo.toModelType()); } @@ -39,7 +39,7 @@ public void toModelType_nullDescription_throwsIllegalValueException() { @Test public void toModelType_validTodoWithDone_returnsCorrectly() throws Exception { JsonAdaptedTodo jsonAdaptedTodo = new JsonAdaptedTodo(VALID_DESCRIPTION, true); - Todo expectedTodo = new Todo(VALID_DESCRIPTION, true); // Done Todo + Todo expectedTodo = new Todo(VALID_DESCRIPTION, true); assertEquals(expectedTodo, jsonAdaptedTodo.toModelType()); } } From 9be2d68d65bf1966598751760194d80659396ec0 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 18:52:37 +0800 Subject: [PATCH 18/25] Add tests for task classes --- .../logic/commands/CreateTaskCommand.java | 7 + .../logic/commands/DeleteTaskCommand.java | 2 +- .../seedu/address/model/task/ParsedTask.java | 28 +++ .../logic/commands/CreateTaskCommandTest.java | 91 ++++++++++ .../logic/commands/DeleteTaskCommandTest.java | 77 ++++++++ .../parser/CreateTaskCommandParserTest.java | 55 ++++++ .../parser/DeleteTaskCommandParserTest.java | 49 ++++++ .../address/logic/parser/ParserUtilTest.java | 87 +++++++++ .../seedu/address/model/task/DateTest.java | 79 +++++++++ .../address/model/task/DeadlineTest.java | 92 ++++++++++ .../address/model/task/DescriptionTest.java | 83 +++++++++ .../seedu/address/model/task/EventTest.java | 95 ++++++++++ .../address/model/task/ParsedTaskTest.java | 62 +++++++ .../seedu/address/model/task/TaskTest.java | 107 +++++++++++ .../seedu/address/model/task/TodoTest.java | 88 ++++++++++ .../model/task/UniqueTaskListTest.java | 166 ++++++++++++++++++ .../address/testutil/TypicalIndexes.java | 4 + .../seedu/address/testutil/TypicalTasks.java | 11 ++ 18 files changed, 1182 insertions(+), 1 deletion(-) create mode 100644 src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java create mode 100644 src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java create mode 100644 src/test/java/seedu/address/logic/parser/CreateTaskCommandParserTest.java create mode 100644 src/test/java/seedu/address/logic/parser/DeleteTaskCommandParserTest.java create mode 100644 src/test/java/seedu/address/model/task/DateTest.java create mode 100644 src/test/java/seedu/address/model/task/DeadlineTest.java create mode 100644 src/test/java/seedu/address/model/task/DescriptionTest.java create mode 100644 src/test/java/seedu/address/model/task/EventTest.java create mode 100644 src/test/java/seedu/address/model/task/ParsedTaskTest.java create mode 100644 src/test/java/seedu/address/model/task/TaskTest.java create mode 100644 src/test/java/seedu/address/model/task/TodoTest.java create mode 100644 src/test/java/seedu/address/model/task/UniqueTaskListTest.java diff --git a/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java b/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java index 051c33f480e..f985dc6038a 100644 --- a/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java +++ b/src/main/java/seedu/address/logic/commands/CreateTaskCommand.java @@ -40,6 +40,13 @@ public CreateTaskCommand(HashSet task) { tasksToAdd = task; } + /** + * Returns the set of tasks to be added. + */ + public HashSet getTaskToAdd() { + return tasksToAdd; + } + @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); diff --git a/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java index de96f40f662..75f6b4a9ee1 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java @@ -42,7 +42,7 @@ public CommandResult execute(Model model) throws CommandException { Task taskToDelete = lastShownList.get(targetIndex.getZeroBased()); model.deleteTask(taskToDelete); - return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, Messages.format(taskToDelete))); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete.toString())); } @Override diff --git a/src/main/java/seedu/address/model/task/ParsedTask.java b/src/main/java/seedu/address/model/task/ParsedTask.java index b50cdfec03f..a1948abd023 100644 --- a/src/main/java/seedu/address/model/task/ParsedTask.java +++ b/src/main/java/seedu/address/model/task/ParsedTask.java @@ -1,5 +1,7 @@ package seedu.address.model.task; +import java.util.Objects; + /** * Represents a task that has been parsed into its type and details. */ @@ -25,4 +27,30 @@ public String getTaskType() { public String getTaskDetails() { return taskDetails; } + + /** + * Returns true if both parsed tasks have the same task type and details. + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof ParsedTask)) { + return false; + } + + ParsedTask otherParsedTask = (ParsedTask) other; + return Objects.equals(taskType, otherParsedTask.taskType) + && Objects.equals(taskDetails, otherParsedTask.taskDetails); + } + + /** + * Returns the hash code for the parsed task based on the task type and details. + */ + @Override + public int hashCode() { + return Objects.hash(taskType, taskDetails); + } } diff --git a/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java new file mode 100644 index 00000000000..8055e2a1986 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java @@ -0,0 +1,91 @@ +package seedu.address.logic.commands; + +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 seedu.address.testutil.TypicalTasks.DEADLINE_TASK; +import static seedu.address.testutil.TypicalTasks.EVENT_TASK; +import static seedu.address.testutil.TypicalTasks.TODO_TASK; + +import java.util.HashSet; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.task.Task; + +/** + * Contains integration tests (interaction with the Model) for {@code CreateTaskCommand}. + */ +public class CreateTaskCommandTest { + + private Model model; + + @BeforeEach + public void setUp() { + model = new ModelManager(); + } + + @Test + public void execute_addValidTask_success() throws Exception { + // Prepare a set of tasks to add + HashSet tasksToAdd = new HashSet<>(); + tasksToAdd.add(TODO_TASK); + tasksToAdd.add(DEADLINE_TASK); + + // Create a CreateTaskCommand with valid tasks + CreateTaskCommand command = new CreateTaskCommand(tasksToAdd); + + String expectedMessage = String.format(CreateTaskCommand.MESSAGE_SUCCESS, tasksToAdd); + + CommandResult result = command.execute(model); + + assertEquals(expectedMessage, result.getFeedbackToUser()); + } + + @Test + public void execute_duplicateTask_throwsCommandException() { + // Add a task to the model to simulate a duplicate + model.addTask(TODO_TASK); + + // Prepare a set of tasks with a duplicate task + HashSet tasksToAdd = new HashSet<>(); + tasksToAdd.add(TODO_TASK); + + CreateTaskCommand command = new CreateTaskCommand(tasksToAdd); + + assertThrows(CommandException.class, () -> command.execute(model), CreateTaskCommand.MESSAGE_DUPLICATE_TASK); + } + + @Test + public void equals() { + HashSet taskSet1 = new HashSet<>(); + taskSet1.add(TODO_TASK); + + HashSet taskSet2 = new HashSet<>(); + taskSet2.add(EVENT_TASK); + + CreateTaskCommand addFirstTaskCommand = new CreateTaskCommand(taskSet1); + CreateTaskCommand addSecondTaskCommand = new CreateTaskCommand(taskSet2); + + // same object -> returns true + assertEquals(addFirstTaskCommand, addFirstTaskCommand); + + // same values -> returns true + CreateTaskCommand addFirstTaskCommandCopy = new CreateTaskCommand(taskSet1); + assertEquals(addFirstTaskCommand, addFirstTaskCommandCopy); + + // different types -> returns false + assertFalse(addFirstTaskCommand.equals(1)); + + // null -> returns false + assertFalse(addFirstTaskCommand.equals(null)); + + // different task sets -> returns false + assertFalse(addFirstTaskCommand.equals(addSecondTaskCommand)); + } + +} diff --git a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java new file mode 100644 index 00000000000..608d0feb982 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java @@ -0,0 +1,77 @@ +package seedu.address.logic.commands; + +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.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_TASK; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_TASK; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +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.ModelManager; +import seedu.address.model.task.Task; +import seedu.address.testutil.TypicalTasks; + +public class DeleteTaskCommandTest { + + private Model model; + + @BeforeEach + public void setUp() { + model = new ModelManager(); + List taskList = TypicalTasks.getTypicalTasks(); + for (Task task : taskList) { + model.addTask(task); + } + } + + @Test + public void execute_validIndexUnfilteredList_success() throws Exception { + Task taskToDelete = model.getFilteredTaskList().get(INDEX_FIRST_TASK.getZeroBased()); + DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(INDEX_FIRST_TASK); + + CommandResult commandResult = deleteTaskCommand.execute(model); + + String expectedMessage = String.format(DeleteTaskCommand.MESSAGE_DELETE_TASK_SUCCESS, taskToDelete); + assertEquals(expectedMessage, commandResult.getFeedbackToUser()); + } + + @Test + public void execute_invalidIndexUnfilteredList_throwsCommandException() { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredTaskList().size() + 1); + DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(outOfBoundIndex); + + assertThrows(CommandException.class, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX, () + -> deleteTaskCommand.execute(model)); + } + + @Test + public void equals() { + DeleteTaskCommand deleteFirstCommand = new DeleteTaskCommand(INDEX_FIRST_TASK); + DeleteTaskCommand deleteSecondCommand = new DeleteTaskCommand(INDEX_SECOND_TASK); + + // same object -> returns true + assertTrue(deleteFirstCommand.equals(deleteFirstCommand)); + + // same values -> returns true + DeleteTaskCommand deleteFirstCommandCopy = new DeleteTaskCommand(INDEX_FIRST_TASK); + assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy)); + + // different types -> returns false + assertFalse(deleteFirstCommand.equals(1)); + + // null -> returns false + assertFalse(deleteFirstCommand.equals(null)); + + // different task -> returns false + assertFalse(deleteFirstCommand.equals(deleteSecondCommand)); + } +} diff --git a/src/test/java/seedu/address/logic/parser/CreateTaskCommandParserTest.java b/src/test/java/seedu/address/logic/parser/CreateTaskCommandParserTest.java new file mode 100644 index 00000000000..349e191e687 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/CreateTaskCommandParserTest.java @@ -0,0 +1,55 @@ +package seedu.address.logic.parser; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalTasks.INVALID_TASK_DESC; +import static seedu.address.testutil.TypicalTasks.TASK_DESC_DEADLINE; +import static seedu.address.testutil.TypicalTasks.TASK_DESC_EVENT; +import static seedu.address.testutil.TypicalTasks.TASK_DESC_TODO; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.Messages; +import seedu.address.logic.commands.CreateTaskCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.task.Task; +import seedu.address.testutil.TypicalTasks; + +public class CreateTaskCommandParserTest { + + private final CreateTaskCommandParser parser = new CreateTaskCommandParser(); + + @Test + public void parse_allFieldsPresent_success() throws Exception { + // CreateTaskCommand with all valid task descriptions + Set expectedTasks = Set.copyOf(TypicalTasks.getTypicalTasks()); + + CreateTaskCommand expectedCommand = new CreateTaskCommand(new HashSet<>(expectedTasks)); + + assertEquals(expectedCommand, parser.parse(TASK_DESC_TODO + TASK_DESC_DEADLINE + TASK_DESC_EVENT)); + } + + @Test + public void parse_incompleteDescription_failure() { + // Invalid task with incomplete description + assertThrows(ParseException.class, Messages.MESSAGE_INCOMPLETE_TASK_DESCRIPTION, () + -> parser.parse(INVALID_TASK_DESC)); + } + + @Test + public void parse_invalidValue_failure() { + // Invalid command format (empty argument) + assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, + CreateTaskCommand.MESSAGE_USAGE), () + -> parser.parse("")); + + // Missing task descriptions (no task prefix) + assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, + CreateTaskCommand.MESSAGE_USAGE), () + -> parser.parse("This is a random string")); + } +} diff --git a/src/test/java/seedu/address/logic/parser/DeleteTaskCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteTaskCommandParserTest.java new file mode 100644 index 00000000000..f963bf7f6a3 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/DeleteTaskCommandParserTest.java @@ -0,0 +1,49 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_TASK; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.Messages; +import seedu.address.logic.commands.DeleteTaskCommand; + +/** + * As we are only doing white-box testing, our test cases do not cover path variations + * outside of the DeleteTaskCommand code. For example, inputs "1" and "1 abc" take the + * same path through the DeleteTaskCommand, and therefore we test only one of them. + */ +public class DeleteTaskCommandParserTest { + + private DeleteTaskCommandParser parser = new DeleteTaskCommandParser(); + + @Test + public void parse_validArgs_returnsDeleteTaskCommand() { + assertParseSuccess(parser, "1", new DeleteTaskCommand(INDEX_FIRST_TASK)); + } + + @Test + public void parse_invalidArgs_throwsParseException() { + assertParseFailure(parser, "a", + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteTaskCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_extraArgs_throwsParseException() { + assertParseFailure(parser, "1 abc", + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteTaskCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_negativeIndex_throwsParseException() { + assertParseFailure(parser, "-1", + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteTaskCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_zeroIndex_throwsParseException() { + assertParseFailure(parser, "0", + String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, DeleteTaskCommand.MESSAGE_USAGE)); + } +} diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java index e0f47c67db7..70a466d5dcd 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java @@ -20,6 +20,10 @@ import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Deadline; +import seedu.address.model.task.Event; +import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; public class ParserUtilTest { private static final String INVALID_NAME = "R@chel"; @@ -37,6 +41,19 @@ public class ParserUtilTest { private static final String VALID_TAG_1_NAME = "florist"; private static final String VALID_TAG_2_NAME = "photographer"; + private static final String INVALID_TASK_TYPE = "unknownTask"; + private static final String INVALID_TODO_DESCRIPTION = "todo"; // No description + private static final String INVALID_DEADLINE_FORMAT = "deadline Submit assignment /by"; + private static final String INVALID_EVENT_FORMAT = "event Conference /from 2024-10-01"; + + private static final String VALID_TODO_DESCRIPTION = "todo Buy groceries"; + private static final String VALID_DEADLINE_DESCRIPTION = "deadline Submit assignment /by 2024-12-31"; + private static final String VALID_EVENT_DESCRIPTION = "event Conference /from 2024-10-01 /to 2024-10-05"; + + private static final String VALID_EVENT_START_DATE = "2024-10-01"; + private static final String VALID_EVENT_END_DATE = "2024-10-05"; + private static final String VALID_DEADLINE_DATE = "2024-12-31"; + private static final String WHITESPACE = " \t\r\n"; @Test @@ -198,4 +215,74 @@ public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception { assertEquals(expectedTagSet, actualTagSet); } + /* + *======================================================================================= + */ + @Test + public void parseTask_invalidTaskType_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_TASK_TYPE)); + } + + @Test + public void parseTask_invalidTodoDescription_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_TODO_DESCRIPTION)); + } + + @Test + public void parseTask_invalidDeadlineFormat_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_DEADLINE_FORMAT)); + } + + @Test + public void parseTask_invalidEventFormat_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_EVENT_FORMAT)); + } + + @Test + public void parseTask_validTodoDescription_returnsTodo() throws Exception { + Todo expectedTodo = new Todo("Buy groceries"); + Task actualTask = ParserUtil.parseTask(VALID_TODO_DESCRIPTION); + assertEquals(expectedTodo, actualTask); + } + + @Test + public void parseTask_validDeadlineDescription_returnsDeadline() throws Exception { + Deadline expectedDeadline = new Deadline("Submit assignment", VALID_DEADLINE_DATE); + Task actualTask = ParserUtil.parseTask(VALID_DEADLINE_DESCRIPTION); + assertEquals(expectedDeadline, actualTask); + } + + @Test + public void parseTask_validEventDescription_returnsEvent() throws Exception { + Event expectedEvent = new Event("Conference", VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + Task actualTask = ParserUtil.parseTask(VALID_EVENT_DESCRIPTION); + assertEquals(expectedEvent, actualTask); + } + + @Test + public void parseTasks_collectionWithValidTasks_returnsTaskSet() throws Exception { + Set actualTaskSet = ParserUtil.parseTasks( + Arrays.asList(VALID_TODO_DESCRIPTION, VALID_DEADLINE_DESCRIPTION, VALID_EVENT_DESCRIPTION)); + + Set expectedTaskSet = new HashSet<>( + Arrays.asList( + new Todo("Buy groceries"), + new Deadline("Submit assignment", VALID_DEADLINE_DATE), + new Event("Conference", VALID_EVENT_START_DATE, VALID_EVENT_END_DATE) + ) + ); + assertEquals(expectedTaskSet, actualTaskSet); + } + + @Test + public void parseTasks_emptyCollection_returnsEmptySet() throws Exception { + Set taskSet = ParserUtil.parseTasks(Arrays.asList()); + assertEquals(new HashSet<>(), taskSet); + } + + @Test + public void parseTasks_collectionWithInvalidTask_throwsParseException() { + assertThrows(ParseException.class, () -> + ParserUtil.parseTasks(Arrays.asList(VALID_TODO_DESCRIPTION, INVALID_DEADLINE_FORMAT))); + } } diff --git a/src/test/java/seedu/address/model/task/DateTest.java b/src/test/java/seedu/address/model/task/DateTest.java new file mode 100644 index 00000000000..b523e25df16 --- /dev/null +++ b/src/test/java/seedu/address/model/task/DateTest.java @@ -0,0 +1,79 @@ +package seedu.address.model.task; + +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.time.format.DateTimeFormatter; + +import org.junit.jupiter.api.Test; + +public class DateTest { + + private static final String VALID_DATE = "2023-10-20"; + private static final String INVALID_DATE = "2023-15-45"; + private static final String VALID_DATE_FORMATTED = "Oct 20 2023"; + + private static final DateTimeFormatter CUSTOM_FORMATTER = DateTimeFormatter.ofPattern("MMM dd yyyy"); + + @Test + public void constructor_validDate_success() { + Date date = new Date(VALID_DATE); + assertEquals(VALID_DATE, date.toString()); + } + + @Test + public void constructor_invalidDate_throwsDateTimeParseException() { + // Test if the constructor throws an exception when an invalid date is passed + try { + new Date(INVALID_DATE); + } catch (Exception e) { + assertTrue(e instanceof java.time.format.DateTimeParseException); + } + } + + @Test + public void isValidDate_validDate_returnsTrue() { + assertTrue(Date.isValidDate(VALID_DATE)); + } + + @Test + public void isValidDate_invalidDate_returnsFalse() { + assertFalse(Date.isValidDate(INVALID_DATE)); + } + + @Test + public void format_customFormatter_returnsFormattedDate() { + Date date = new Date(VALID_DATE); + String formattedDate = date.format(CUSTOM_FORMATTER); + assertEquals(VALID_DATE_FORMATTED, formattedDate); + } + + @Test + public void equals_sameDate_returnsTrue() { + Date date1 = new Date(VALID_DATE); + Date date2 = new Date(VALID_DATE); + assertTrue(date1.equals(date2)); + } + + @Test + public void equals_differentDate_returnsFalse() { + Date date1 = new Date(VALID_DATE); + Date date2 = new Date("2023-11-20"); // Different date + assertFalse(date1.equals(date2)); + } + + @Test + public void hashCode_sameDate_returnsSameHashCode() { + Date date1 = new Date(VALID_DATE); + Date date2 = new Date(VALID_DATE); + assertEquals(date1.hashCode(), date2.hashCode()); + } + + @Test + public void hashCode_differentDate_returnsDifferentHashCode() { + Date date1 = new Date(VALID_DATE); + Date date2 = new Date("2023-11-20"); + assertFalse(date1.hashCode() == date2.hashCode()); + } +} diff --git a/src/test/java/seedu/address/model/task/DeadlineTest.java b/src/test/java/seedu/address/model/task/DeadlineTest.java new file mode 100644 index 00000000000..dd6b4a1253e --- /dev/null +++ b/src/test/java/seedu/address/model/task/DeadlineTest.java @@ -0,0 +1,92 @@ +package seedu.address.model.task; + +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.time.format.DateTimeFormatter; + +import org.junit.jupiter.api.Test; + +public class DeadlineTest { + + private static final String VALID_DESCRIPTION = "Submit assignment"; + private static final String VALID_BY_DATE = "2023-12-31"; + private static final String VALID_BY_DATE_FORMATTED = "Dec 31 2023"; + private static final Description DESCRIPTION_OBJ = new Description(VALID_DESCRIPTION); + private static final DateTimeFormatter CUSTOM_FORMATTER = DateTimeFormatter.ofPattern("MMM dd yyyy"); + + @Test + public void constructor_validStringDescriptionAndByDate_success() { + Deadline deadline = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + assertEquals("[D][ ] Submit assignment (by: Dec 31 2023)", deadline.toString()); + } + + @Test + public void constructor_validDescriptionObject_success() { + Deadline deadline = new Deadline(DESCRIPTION_OBJ.toString(), VALID_BY_DATE); + assertEquals("[D][ ] Submit assignment (by: Dec 31 2023)", deadline.toString()); + } + + @Test + public void constructor_withDoneStatus_success() { + Deadline deadline = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE, true); + assertEquals("[D][X] Submit assignment (by: Dec 31 2023)", deadline.toString()); + } + + @Test + public void getBy_returnsCorrectDate() { + Deadline deadline = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + assertEquals(VALID_BY_DATE, deadline.getBy().toString()); + } + + @Test + public void markAsDone_marksTaskAsDone() { + Deadline deadline = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + deadline.markAsDone(); + assertTrue(deadline.getIsDone()); + assertEquals("[D][X] Submit assignment (by: Dec 31 2023)", deadline.toString()); + } + + @Test + public void markAsUndone_marksTaskAsUndone() { + Deadline deadline = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE, true); + deadline.markAsUndone(); + assertFalse(deadline.getIsDone()); + assertEquals("[D][ ] Submit assignment (by: Dec 31 2023)", deadline.toString()); + } + + @Test + public void equals_sameDeadline_returnsTrue() { + Deadline deadline1 = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + Deadline deadline2 = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + assertTrue(deadline1.equals(deadline2)); + } + + @Test + public void equals_differentDeadline_returnsFalse() { + Deadline deadline1 = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + Deadline deadline2 = new Deadline("Complete project", "2023-11-30"); + assertFalse(deadline1.equals(deadline2)); + } + + @Test + public void hashCode_sameDeadline_returnsSameHashCode() { + Deadline deadline1 = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + Deadline deadline2 = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + assertEquals(deadline1.hashCode(), deadline2.hashCode()); + } + + @Test + public void hashCode_differentDeadline_returnsDifferentHashCode() { + Deadline deadline1 = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + Deadline deadline2 = new Deadline("Complete project", "2023-11-30"); + assertFalse(deadline1.hashCode() == deadline2.hashCode()); + } + + @Test + public void toString_correctlyFormatsDeadline() { + Deadline deadline = new Deadline(VALID_DESCRIPTION, VALID_BY_DATE); + assertEquals("[D][ ] Submit assignment (by: Dec 31 2023)", deadline.toString()); + } +} diff --git a/src/test/java/seedu/address/model/task/DescriptionTest.java b/src/test/java/seedu/address/model/task/DescriptionTest.java new file mode 100644 index 00000000000..44fc2294632 --- /dev/null +++ b/src/test/java/seedu/address/model/task/DescriptionTest.java @@ -0,0 +1,83 @@ +package seedu.address.model.task; + +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 org.junit.jupiter.api.Test; + +public class DescriptionTest { + + private static final String VALID_DESCRIPTION = "Buy groceries"; + private static final String INVALID_DESCRIPTION_EMPTY = ""; + private static final String INVALID_DESCRIPTION_BLANK = " "; + private static final String VALID_DESCRIPTION_WITH_WHITESPACE = " Clean the house "; + + @Test + public void constructor_validDescription_success() { + Description description = new Description(VALID_DESCRIPTION); + assertEquals(VALID_DESCRIPTION, description.toString()); + } + + @Test + public void constructor_invalidDescription_throwsIllegalArgumentException() { + // Test with empty description + try { + new Description(INVALID_DESCRIPTION_EMPTY); + } catch (Exception e) { + assertTrue(e instanceof IllegalArgumentException); + } + + // Test with blank description (only spaces) + try { + new Description(INVALID_DESCRIPTION_BLANK); + } catch (Exception e) { + assertTrue(e instanceof IllegalArgumentException); + } + } + + @Test + public void isValidDescription_validDescription_returnsTrue() { + assertTrue(Description.isValidDescription(VALID_DESCRIPTION)); + } + + @Test + public void isValidDescription_invalidDescription_returnsFalse() { + assertFalse(Description.isValidDescription(INVALID_DESCRIPTION_EMPTY)); + assertFalse(Description.isValidDescription(INVALID_DESCRIPTION_BLANK)); + } + + @Test + public void equals_sameDescription_returnsTrue() { + Description description1 = new Description(VALID_DESCRIPTION); + Description description2 = new Description(VALID_DESCRIPTION); + assertTrue(description1.equals(description2)); + } + + @Test + public void equals_differentDescription_returnsFalse() { + Description description1 = new Description(VALID_DESCRIPTION); + Description description2 = new Description("Go for a run"); + assertFalse(description1.equals(description2)); + } + + @Test + public void hashCode_sameDescription_returnsSameHashCode() { + Description description1 = new Description(VALID_DESCRIPTION); + Description description2 = new Description(VALID_DESCRIPTION); + assertEquals(description1.hashCode(), description2.hashCode()); + } + + @Test + public void hashCode_differentDescription_returnsDifferentHashCode() { + Description description1 = new Description(VALID_DESCRIPTION); + Description description2 = new Description("Go for a run"); + assertFalse(description1.hashCode() == description2.hashCode()); + } + + @Test + public void toString_trimsWhitespace() { + Description description = new Description(VALID_DESCRIPTION_WITH_WHITESPACE.trim()); + assertEquals("Clean the house", description.toString()); + } +} diff --git a/src/test/java/seedu/address/model/task/EventTest.java b/src/test/java/seedu/address/model/task/EventTest.java new file mode 100644 index 00000000000..6e1319cf2a2 --- /dev/null +++ b/src/test/java/seedu/address/model/task/EventTest.java @@ -0,0 +1,95 @@ +package seedu.address.model.task; + +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 org.junit.jupiter.api.Test; + +public class EventTest { + + private static final String VALID_DESCRIPTION = "Team meeting"; + private static final String VALID_FROM_DATE = "2023-10-01"; + private static final String VALID_TO_DATE = "2023-10-02"; + private static final Description DESCRIPTION_OBJ = new Description(VALID_DESCRIPTION); + + @Test + public void constructor_validStringDescriptionAndDates_success() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + assertEquals("[E][ ] Team meeting (from: Oct 01 2023 to: Oct 02 2023)", event.toString()); + } + + @Test + public void constructor_validDescriptionObject_success() { + Event event = new Event(DESCRIPTION_OBJ.toString(), VALID_FROM_DATE, VALID_TO_DATE); + assertEquals("[E][ ] Team meeting (from: Oct 01 2023 to: Oct 02 2023)", event.toString()); + } + + @Test + public void constructor_withDoneStatus_success() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE, true); + assertEquals("[E][X] Team meeting (from: Oct 01 2023 to: Oct 02 2023)", event.toString()); + } + + @Test + public void getFrom_returnsCorrectDate() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + assertEquals(VALID_FROM_DATE, event.getFrom().toString()); + } + + @Test + public void getTo_returnsCorrectDate() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + assertEquals(VALID_TO_DATE, event.getTo().toString()); + } + + @Test + public void markAsDone_marksTaskAsDone() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + event.markAsDone(); + assertTrue(event.getIsDone()); + assertEquals("[E][X] Team meeting (from: Oct 01 2023 to: Oct 02 2023)", event.toString()); + } + + @Test + public void markAsUndone_marksTaskAsUndone() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE, true); + event.markAsUndone(); + assertFalse(event.getIsDone()); + assertEquals("[E][ ] Team meeting (from: Oct 01 2023 to: Oct 02 2023)", event.toString()); + } + + @Test + public void equals_sameEvent_returnsTrue() { + Event event1 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + Event event2 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + assertTrue(event1.equals(event2)); + } + + @Test + public void equals_differentEvent_returnsFalse() { + Event event1 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + Event event2 = new Event("Workshop", "2023-10-05", "2023-10-06"); + assertFalse(event1.equals(event2)); + } + + @Test + public void hashCode_sameEvent_returnsSameHashCode() { + Event event1 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + Event event2 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + assertEquals(event1.hashCode(), event2.hashCode()); + } + + @Test + public void hashCode_differentEvent_returnsDifferentHashCode() { + Event event1 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + Event event2 = new Event("Workshop", "2023-10-05", "2023-10-06"); + assertFalse(event1.hashCode() == event2.hashCode()); + } + + @Test + public void toString_correctlyFormatsEvent() { + Event event = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + assertEquals("[E][ ] Team meeting (from: Oct 01 2023 to: Oct 02 2023)", event.toString()); + } +} diff --git a/src/test/java/seedu/address/model/task/ParsedTaskTest.java b/src/test/java/seedu/address/model/task/ParsedTaskTest.java new file mode 100644 index 00000000000..da5cce36dd2 --- /dev/null +++ b/src/test/java/seedu/address/model/task/ParsedTaskTest.java @@ -0,0 +1,62 @@ +package seedu.address.model.task; + +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 org.junit.jupiter.api.Test; + +public class ParsedTaskTest { + + private static final String VALID_TASK_TYPE = "todo"; + private static final String VALID_TASK_DETAILS = "Buy groceries"; + private static final String DIFFERENT_TASK_TYPE = "event"; + private static final String DIFFERENT_TASK_DETAILS = "Team meeting"; + + @Test + public void constructor_validTaskTypeAndDetails_success() { + ParsedTask parsedTask = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertEquals(VALID_TASK_TYPE, parsedTask.getTaskType()); + assertEquals(VALID_TASK_DETAILS, parsedTask.getTaskDetails()); + } + + @Test + public void getTaskType_returnsCorrectTaskType() { + ParsedTask parsedTask = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertEquals(VALID_TASK_TYPE, parsedTask.getTaskType()); + } + + @Test + public void getTaskDetails_returnsCorrectTaskDetails() { + ParsedTask parsedTask = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertEquals(VALID_TASK_DETAILS, parsedTask.getTaskDetails()); + } + + @Test + public void equals_sameParsedTask_returnsTrue() { + ParsedTask parsedTask1 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + ParsedTask parsedTask2 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertTrue(parsedTask1.equals(parsedTask2)); + } + + @Test + public void equals_differentParsedTask_returnsFalse() { + ParsedTask parsedTask1 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + ParsedTask parsedTask2 = new ParsedTask(DIFFERENT_TASK_TYPE, DIFFERENT_TASK_DETAILS); + assertFalse(parsedTask1.equals(parsedTask2)); + } + + @Test + public void hashCode_sameParsedTask_returnsSameHashCode() { + ParsedTask parsedTask1 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + ParsedTask parsedTask2 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertEquals(parsedTask1.hashCode(), parsedTask2.hashCode()); + } + + @Test + public void hashCode_differentParsedTask_returnsDifferentHashCode() { + ParsedTask parsedTask1 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + ParsedTask parsedTask2 = new ParsedTask(DIFFERENT_TASK_TYPE, DIFFERENT_TASK_DETAILS); + assertFalse(parsedTask1.hashCode() == parsedTask2.hashCode()); + } +} diff --git a/src/test/java/seedu/address/model/task/TaskTest.java b/src/test/java/seedu/address/model/task/TaskTest.java new file mode 100644 index 00000000000..cc757c66975 --- /dev/null +++ b/src/test/java/seedu/address/model/task/TaskTest.java @@ -0,0 +1,107 @@ +package seedu.address.model.task; + +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 org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TaskTest { + + private Task task1; + private Task task2; + + @BeforeEach + public void setUp() { + task1 = new Task("Complete project"); + task2 = new Task(new Description("Submit report")); + } + + @Test + public void constructor_validStringDescription_success() { + Task task = new Task("Buy groceries"); + assertEquals("[ ] Buy groceries", task.toString()); + } + + @Test + public void constructor_validDescriptionObject_success() { + Task task = new Task(new Description("Clean the house")); + assertEquals("[ ] Clean the house", task.toString()); + } + + @Test + public void markAsDone_marksTaskAsDone() { + task1.markAsDone(); + assertTrue(task1.getIsDone()); + assertEquals("[X] Complete project", task1.toString()); + } + + @Test + public void markAsUndone_marksTaskAsNotDone() { + task1.markAsDone(); + task1.markAsUndone(); + assertFalse(task1.getIsDone()); + assertEquals("[ ] Complete project", task1.toString()); + } + + @Test + public void hasKeywordInPartialDescription_keywordFound_returnsTrue() { + assertTrue(task1.hasKeywordInPartialDescription("project")); + assertTrue(task2.hasKeywordInPartialDescription("Submit")); + assertTrue(task2.hasKeywordInPartialDescription("report")); + } + + @Test + public void hasKeywordInPartialDescription_keywordNotFound_returnsFalse() { + assertFalse(task1.hasKeywordInPartialDescription("report")); + assertFalse(task2.hasKeywordInPartialDescription("project")); + } + + @Test + public void isSameTask_sameDescription_returnsTrue() { + Task task3 = new Task("Complete project"); + assertTrue(task1.isSameTask(task3)); + } + + @Test + public void isSameTask_differentDescription_returnsFalse() { + assertFalse(task1.isSameTask(task2)); + } + + @Test + public void equals_sameObject_returnsTrue() { + assertTrue(task1.equals(task1)); + } + + @Test + public void equals_sameValues_returnsTrue() { + Task task3 = new Task("Complete project"); + assertTrue(task1.equals(task3)); + } + + @Test + public void equals_differentDescription_returnsFalse() { + assertFalse(task1.equals(task2)); + } + + @Test + public void equals_differentStatus_returnsFalse() { + task1.markAsDone(); + Task task3 = new Task("Complete project"); // Task with same description but not done + assertFalse(task1.equals(task3)); + } + + @Test + public void hashCode_sameValues_returnsSameHashCode() { + Task task3 = new Task("Complete project"); + assertEquals(task1.hashCode(), task3.hashCode()); // Same description and status + } + + @Test + public void toString_correctFormatting() { + assertEquals("[ ] Complete project", task1.toString()); + task1.markAsDone(); + assertEquals("[X] Complete project", task1.toString()); + } +} diff --git a/src/test/java/seedu/address/model/task/TodoTest.java b/src/test/java/seedu/address/model/task/TodoTest.java new file mode 100644 index 00000000000..06f524c86b6 --- /dev/null +++ b/src/test/java/seedu/address/model/task/TodoTest.java @@ -0,0 +1,88 @@ +package seedu.address.model.task; + +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 org.junit.jupiter.api.Test; + +public class TodoTest { + + private static final String VALID_DESCRIPTION = "Buy groceries"; + private static final String VALID_DESCRIPTION_TRIMMED = "Clean the house"; + private static final Description DESCRIPTION_OBJ = new Description("Complete homework"); + + @Test + public void constructor_validStringDescription_success() { + Todo todo = new Todo(VALID_DESCRIPTION); + assertEquals("[T][ ] Buy groceries", todo.toString()); + } + + @Test + public void constructor_validDescriptionObject_success() { + Todo todo = new Todo(DESCRIPTION_OBJ); + assertEquals("[T][ ] Complete homework", todo.toString()); + } + + @Test + public void constructor_withDoneStatus_success() { + Todo todo = new Todo(VALID_DESCRIPTION, true); + assertEquals("[T][X] Buy groceries", todo.toString()); + } + + @Test + public void constructor_withDescriptionObjectAndDoneStatus_success() { + Todo todo = new Todo(DESCRIPTION_OBJ, true); + assertEquals("[T][X] Complete homework", todo.toString()); + } + + @Test + public void markAsDone_marksTaskAsDone() { + Todo todo = new Todo(VALID_DESCRIPTION); + todo.markAsDone(); + assertTrue(todo.getIsDone()); + assertEquals("[T][X] Buy groceries", todo.toString()); + } + + @Test + public void markAsUndone_marksTaskAsUndone() { + Todo todo = new Todo(VALID_DESCRIPTION, true); + todo.markAsUndone(); + assertFalse(todo.getIsDone()); + assertEquals("[T][ ] Buy groceries", todo.toString()); + } + + @Test + public void equals_sameTodo_returnsTrue() { + Todo todo1 = new Todo(VALID_DESCRIPTION); + Todo todo2 = new Todo(VALID_DESCRIPTION); + assertTrue(todo1.equals(todo2)); + } + + @Test + public void equals_differentTodo_returnsFalse() { + Todo todo1 = new Todo(VALID_DESCRIPTION); + Todo todo2 = new Todo("Complete homework"); + assertFalse(todo1.equals(todo2)); + } + + @Test + public void hashCode_sameTodo_returnsSameHashCode() { + Todo todo1 = new Todo(VALID_DESCRIPTION); + Todo todo2 = new Todo(VALID_DESCRIPTION); + assertEquals(todo1.hashCode(), todo2.hashCode()); + } + + @Test + public void hashCode_differentTodo_returnsDifferentHashCode() { + Todo todo1 = new Todo(VALID_DESCRIPTION); + Todo todo2 = new Todo("Complete homework"); + assertFalse(todo1.hashCode() == todo2.hashCode()); + } + + @Test + public void toString_trimsWhitespaceCorrectly() { + Todo todo = new Todo(VALID_DESCRIPTION_TRIMMED.trim()); + assertEquals("[T][ ] Clean the house", todo.toString()); + } +} diff --git a/src/test/java/seedu/address/model/task/UniqueTaskListTest.java b/src/test/java/seedu/address/model/task/UniqueTaskListTest.java new file mode 100644 index 00000000000..927cdaeac06 --- /dev/null +++ b/src/test/java/seedu/address/model/task/UniqueTaskListTest.java @@ -0,0 +1,166 @@ +package seedu.address.model.task; + +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 java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.task.exceptions.DuplicateTaskException; +import seedu.address.model.task.exceptions.TaskNotFoundException; + +public class UniqueTaskListTest { + private static final Task TODO_TASK = new Todo("Buy groceries"); + private static final Task EVENT_TASK = new Event("Team meeting", "2023-10-01", "2023-10-02"); + private final UniqueTaskList uniqueTaskList = new UniqueTaskList(); + + + @Test + public void contains_nullTask_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.contains(null)); + } + + @Test + public void contains_taskNotInList_returnsFalse() { + assertFalse(uniqueTaskList.contains(TODO_TASK)); + } + + @Test + public void contains_taskInList_returnsTrue() { + uniqueTaskList.add(TODO_TASK); + assertTrue(uniqueTaskList.contains(TODO_TASK)); + } + + @Test + public void contains_taskWithSameIdentityFieldsInList_returnsTrue() { + uniqueTaskList.add(TODO_TASK); + Task todoTaskCopy = new Todo("Buy groceries"); // Same description as TODO_TASK + assertTrue(uniqueTaskList.contains(todoTaskCopy)); + } + + @Test + public void add_nullTask_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.add(null)); + } + + @Test + public void add_duplicateTask_throwsDuplicateTaskException() { + uniqueTaskList.add(TODO_TASK); + assertThrows(DuplicateTaskException.class, () -> uniqueTaskList.add(TODO_TASK)); + } + + @Test + public void setTask_nullTargetTask_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.setTask(null, TODO_TASK)); + } + + @Test + public void setTask_nullEditedTask_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.setTask(TODO_TASK, null)); + } + + @Test + public void setTask_targetTaskNotInList_throwsTaskNotFoundException() { + assertThrows(TaskNotFoundException.class, () -> uniqueTaskList.setTask(TODO_TASK, TODO_TASK)); + } + + @Test + public void setTask_editedTaskIsSameTask_success() { + uniqueTaskList.add(TODO_TASK); + uniqueTaskList.setTask(TODO_TASK, TODO_TASK); + UniqueTaskList expectedTaskList = new UniqueTaskList(); + expectedTaskList.add(TODO_TASK); + assertEquals(expectedTaskList, uniqueTaskList); + } + + @Test + public void setTask_editedTaskHasSameIdentity_success() { + uniqueTaskList.add(TODO_TASK); + Task editedTodoTask = new Todo("Buy groceries"); + uniqueTaskList.setTask(TODO_TASK, editedTodoTask); + UniqueTaskList expectedTaskList = new UniqueTaskList(); + expectedTaskList.add(editedTodoTask); + assertEquals(expectedTaskList, uniqueTaskList); + } + + @Test + public void setTask_editedTaskHasDifferentIdentity_success() { + uniqueTaskList.add(TODO_TASK); + uniqueTaskList.setTask(TODO_TASK, EVENT_TASK); + UniqueTaskList expectedTaskList = new UniqueTaskList(); + expectedTaskList.add(EVENT_TASK); + assertEquals(expectedTaskList, uniqueTaskList); + } + + @Test + public void setTask_editedTaskHasNonUniqueIdentity_throwsDuplicateTaskException() { + uniqueTaskList.add(TODO_TASK); + uniqueTaskList.add(EVENT_TASK); + assertThrows(DuplicateTaskException.class, () -> uniqueTaskList.setTask(TODO_TASK, EVENT_TASK)); + } + + @Test + public void remove_nullTask_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.remove(null)); + } + + @Test + public void remove_taskDoesNotExist_throwsTaskNotFoundException() { + assertThrows(TaskNotFoundException.class, () -> uniqueTaskList.remove(TODO_TASK)); + } + + @Test + public void remove_existingTask_removesTask() { + uniqueTaskList.add(TODO_TASK); + uniqueTaskList.remove(TODO_TASK); + UniqueTaskList expectedTaskList = new UniqueTaskList(); + assertEquals(expectedTaskList, uniqueTaskList); + } + + @Test + public void setTasks_nullUniqueTaskList_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.setTasks((UniqueTaskList) null)); + } + + @Test + public void setTasks_uniqueTaskList_replacesOwnListWithProvidedUniqueTaskList() { + uniqueTaskList.add(TODO_TASK); + UniqueTaskList expectedTaskList = new UniqueTaskList(); + expectedTaskList.add(EVENT_TASK); + uniqueTaskList.setTasks(expectedTaskList); + assertEquals(expectedTaskList, uniqueTaskList); + } + + @Test + public void setTasks_nullList_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTaskList.setTasks((List) null)); + } + + @Test + public void setTasks_list_replacesOwnListWithProvidedList() { + uniqueTaskList.add(TODO_TASK); + List taskList = Collections.singletonList(EVENT_TASK); + uniqueTaskList.setTasks(taskList); + UniqueTaskList expectedTaskList = new UniqueTaskList(); + expectedTaskList.add(EVENT_TASK); + assertEquals(expectedTaskList, uniqueTaskList); + } + + @Test + public void setTasks_listWithDuplicateTasks_throwsDuplicateTaskException() { + List listWithDuplicateTasks = Arrays.asList(TODO_TASK, TODO_TASK); + assertThrows(DuplicateTaskException.class, () -> uniqueTaskList.setTasks(listWithDuplicateTasks)); + } + + @Test + public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() { + uniqueTaskList.add(TODO_TASK); + assertThrows(UnsupportedOperationException.class, () -> + uniqueTaskList.asUnmodifiableObservableList().remove(0)); + } +} diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/seedu/address/testutil/TypicalIndexes.java index 1e613937657..35e1e7b3ea4 100644 --- a/src/test/java/seedu/address/testutil/TypicalIndexes.java +++ b/src/test/java/seedu/address/testutil/TypicalIndexes.java @@ -9,4 +9,8 @@ public class TypicalIndexes { public static final Index INDEX_FIRST_PERSON = Index.fromOneBased(1); public static final Index INDEX_SECOND_PERSON = Index.fromOneBased(2); public static final Index INDEX_THIRD_PERSON = Index.fromOneBased(3); + + public static final Index INDEX_FIRST_TASK = Index.fromOneBased(1); + public static final Index INDEX_SECOND_TASK = Index.fromOneBased(2); + public static final Index INDEX_THIRD_TASK = Index.fromOneBased(3); } diff --git a/src/test/java/seedu/address/testutil/TypicalTasks.java b/src/test/java/seedu/address/testutil/TypicalTasks.java index 2dcf86fccbd..bfb845c0076 100644 --- a/src/test/java/seedu/address/testutil/TypicalTasks.java +++ b/src/test/java/seedu/address/testutil/TypicalTasks.java @@ -24,6 +24,17 @@ public class TypicalTasks { public static final String VALID_EVENT_START_DATE = "2024-10-10"; public static final String VALID_EVENT_END_DATE = "2024-10-11"; + public static final String TASK_DESC_TODO = " tk/todo Buy groceries"; + public static final String TASK_DESC_DEADLINE = " tk/deadline Submit report /by 2024-12-31"; + public static final String TASK_DESC_EVENT = " tk/event Project meeting /from 2024-10-10 /to 2024-10-11"; + + public static final String TASK_DESC_BUY_GROCERIES = " tk/todo Buy groceries"; + public static final String TASK_DESC_SUBMIT_ASSIGNMENT = " tk/deadline Submit assignment /by 2023-12-31"; + public static final String TASK_DESC_TEAM_MEETING = " tk/event Team meeting /from 2024-10-01 /to 2024-10-02"; + + // Invalid Task Descriptions + public static final String INVALID_TASK_DESC = " tk/event "; // incomplete event details + // Sample Tasks public static final Todo TODO_TASK = new Todo(VALID_TODO_DESCRIPTION); public static final Deadline DEADLINE_TASK = new Deadline(VALID_DEADLINE_DESCRIPTION, VALID_DEADLINE_DATE); From 17a4f378f3637532c19e1ff1844474cbd58ba4d0 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 19:58:20 +0800 Subject: [PATCH 19/25] Add more tests --- .../DescriptionContainsKeywordsPredicate.java | 37 +++++++++++++++++ src/main/java/seedu/address/ui/TaskCard.java | 16 ++++++++ .../logic/commands/CommandTestUtil.java | 16 ++++++++ .../logic/commands/ListTaskCommandTest.java | 41 +++++++++++++++++++ .../logic/parser/AddressBookParserTest.java | 34 +++++++++++++++ .../address/logic/parser/ParserUtilTest.java | 36 ++++++++++++++++ .../address/testutil/TypicalPersons.java | 2 +- .../seedu/address/testutil/TypicalTasks.java | 14 +++++++ 8 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicate.java create mode 100644 src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java diff --git a/src/main/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicate.java new file mode 100644 index 00000000000..76ee8b235eb --- /dev/null +++ b/src/main/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicate.java @@ -0,0 +1,37 @@ +package seedu.address.model.task.keywordspredicate; + +import java.util.List; + +import seedu.address.commons.util.StringUtil; +import seedu.address.model.person.keywordspredicate.TraitContainsKeywordsPredicate; +import seedu.address.model.task.Task; + +/** + * Tests that a {@code Task}'s {@code Description} matches any of the keywords given. + */ +public class DescriptionContainsKeywordsPredicate extends TraitContainsKeywordsPredicate { + + public DescriptionContainsKeywordsPredicate(List keywords) { + super(keywords); + } + + @Override + public boolean test(Task task) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsPartialWordIgnoreCase(task.getDescription(), keyword)); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof DescriptionContainsKeywordsPredicate otherDescriptionContainsKeywordsPredicate)) { + return false; + } + + return keywords.equals(otherDescriptionContainsKeywordsPredicate.keywords); + } +} diff --git a/src/main/java/seedu/address/ui/TaskCard.java b/src/main/java/seedu/address/ui/TaskCard.java index 349fb2fedce..bdffb08e12f 100644 --- a/src/main/java/seedu/address/ui/TaskCard.java +++ b/src/main/java/seedu/address/ui/TaskCard.java @@ -44,5 +44,21 @@ public TaskCard(Task task, int displayedIndex) { isDone.setText(task.getIsDone() ? "Completed" : "Incomplete"); } + + public Label getDescriptionLabel() { + return description; + } + + public Label getIdLabel() { + return id; + } + + public Label getDateLabel() { + return date; + } + + public Label getIsDoneLabel() { + return isDone; + } } diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 75c5bd01380..344099c0288 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -22,6 +22,8 @@ import seedu.address.model.person.keywordspredicate.NameContainsKeywordsPredicate; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Task; +import seedu.address.model.task.keywordspredicate.DescriptionContainsKeywordsPredicate; import seedu.address.testutil.EditPersonDescriptorBuilder; /** @@ -162,4 +164,18 @@ public static void showPersonAtIndex(Model model, Index targetIndex) { assertEquals(1, model.getFilteredPersonList().size()); } + + /** + * Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the + * {@code model}'s address book. + */ + public static void showTaskAtIndex(Model model, Index targetIndex) { + assertTrue(targetIndex.getZeroBased() < model.getFilteredTaskList().size()); + + Task task = model.getFilteredTaskList().get(targetIndex.getZeroBased()); + final String[] splitDescription = task.getDescription().split("\\s+"); + model.updateFilteredTaskList(new DescriptionContainsKeywordsPredicate(Arrays.asList(splitDescription[0]))); + + assertEquals(1, model.getFilteredTaskList().size()); + } } diff --git a/src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java new file mode 100644 index 00000000000..9ae2dfeb9e5 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java @@ -0,0 +1,41 @@ +package seedu.address.logic.commands; + +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.CommandTestUtil.showTaskAtIndex; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_TASK; +import static seedu.address.testutil.TypicalTasks.getTypicalAddressBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; + +/** + * Contains integration tests (interaction with the Model) and unit tests for ListTaskCommand. + */ +public class ListTaskCommandTest { + + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + } + + @Test + public void execute_listIsNotFiltered_showsSameList() { + CommandResult actualCommandResult = new ListTaskCommand().execute(model); + assertCommandSuccess(new ListTaskCommand(), model, actualCommandResult, expectedModel); + } + + @Test + public void execute_listIsFiltered_showsEverything() { + showTaskAtIndex(model, INDEX_FIRST_TASK); // Filters the task list to show only the first task + CommandResult actualCommandResult = new ListTaskCommand().execute(model); + assertCommandSuccess(new ListTaskCommand(), model, actualCommandResult, expectedModel); + } +} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index d2897bebf6d..acffc5ab8d4 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -18,15 +18,18 @@ import seedu.address.logic.commands.AssignWeddingCommand; import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.CreateTagCommand; +import seedu.address.logic.commands.CreateTaskCommand; import seedu.address.logic.commands.CreateWeddingCommand; import seedu.address.logic.commands.DeleteCommand; import seedu.address.logic.commands.DeleteTagCommand; +import seedu.address.logic.commands.DeleteTaskCommand; import seedu.address.logic.commands.DeleteWeddingCommand; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.ListTaskCommand; import seedu.address.logic.commands.ListWeddingsCommand; import seedu.address.logic.commands.TagCommand; import seedu.address.logic.commands.UnassignWeddingCommand; @@ -38,11 +41,13 @@ import seedu.address.model.person.keywordspredicate.NameContainsKeywordsPredicate; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Task; import seedu.address.model.wedding.Wedding; import seedu.address.model.wedding.WeddingName; import seedu.address.testutil.EditPersonDescriptorBuilder; import seedu.address.testutil.PersonBuilder; import seedu.address.testutil.PersonUtil; +import seedu.address.testutil.TypicalTasks; public class AddressBookParserTest { @@ -195,6 +200,35 @@ public void parseCommand_listWeddings() throws Exception { assertTrue(parser.parseCommand(ListWeddingsCommand.COMMAND_WORD + " 3") instanceof ListWeddingsCommand); } + @Test + public void parseCommand_listTask() throws Exception { + assertTrue(parser.parseCommand(ListTaskCommand.COMMAND_WORD) instanceof ListTaskCommand); + assertTrue(parser.parseCommand(ListTaskCommand.COMMAND_WORD + " 3") instanceof ListTaskCommand); + } + + @Test + public void parseCommand_createTask() throws Exception { + String userInput = CreateTaskCommand.COMMAND_WORD + + " tk/todo Buy groceries tk/deadline Submit report /by 2024-12-31" + + " tk/event Project meeting /from 2024-10-10 /to 2024-10-11"; + HashSet tasksToAdd = new HashSet<>(TypicalTasks.getTypicalTasks()); + + CreateTaskCommand expectedCommand = new CreateTaskCommand(tasksToAdd); + CreateTaskCommand command = (CreateTaskCommand) parser.parseCommand(userInput); + + assertEquals(expectedCommand, command); + } + + @Test + public void parseCommand_deleteTask() throws Exception { + DeleteTaskCommand command = (DeleteTaskCommand) parser.parseCommand( + DeleteTaskCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased()); + assertEquals(new DeleteTaskCommand(INDEX_FIRST_PERSON), command); + } + + + + @Test public void parseCommand_unrecognisedInput_throwsParseException() { assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), () diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java index 70a466d5dcd..1208d6d9a90 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java @@ -54,6 +54,15 @@ public class ParserUtilTest { private static final String VALID_EVENT_END_DATE = "2024-10-05"; private static final String VALID_DEADLINE_DATE = "2024-12-31"; + private static final String INVALID_DEADLINE_DATE_MONTH = "deadline Submit assignment /by 2024-13-31"; + private static final String INVALID_DEADLINE_DATE_DAY = "deadline Submit assignment /by 2024-12-32"; + private static final String INVALID_DEADLINE_DATE_STRING = "deadline Submit assignment /by not-a-date"; + + private static final String INVALID_EVENT_DATE_MONTH = "event Conference /from 2024-13-01 /to 2024-12-31"; + private static final String INVALID_EVENT_DATE_DAY = "event Conference /from 2024-12-01 /to 2024-12-32"; + private static final String INVALID_EVENT_DATE_STRING = "event Conference /from 2024-12-01 /to not-a-date"; + private static final String INVALID_EVENT_DATE_ORDER = "event Conference /from 2024-12-31 /to 2024-12-01"; + private static final String WHITESPACE = " \t\r\n"; @Test @@ -285,4 +294,31 @@ public void parseTasks_collectionWithInvalidTask_throwsParseException() { assertThrows(ParseException.class, () -> ParserUtil.parseTasks(Arrays.asList(VALID_TODO_DESCRIPTION, INVALID_DEADLINE_FORMAT))); } + + @Test + public void parseTask_invalidDeadlineDate_throwsParseException() { + // Invalid month + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_DEADLINE_DATE_MONTH)); + + // Invalid day + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_DEADLINE_DATE_DAY)); + + // Invalid date string + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_DEADLINE_DATE_STRING)); + } + + @Test + public void parseTask_invalidEventDates_throwsParseException() { + // Invalid month + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_EVENT_DATE_MONTH)); + + // Invalid day + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_EVENT_DATE_DAY)); + + // Invalid date string + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_EVENT_DATE_STRING)); + + // "from" date is after "to" date + assertThrows(ParseException.class, () -> ParserUtil.parseTask(INVALID_EVENT_DATE_ORDER)); + } } diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java index 8a13de862bb..dae9530747a 100644 --- a/src/test/java/seedu/address/testutil/TypicalPersons.java +++ b/src/test/java/seedu/address/testutil/TypicalPersons.java @@ -85,7 +85,7 @@ public class TypicalPersons { private TypicalPersons() {} // prevents instantiation /** - * Returns an {@code AddressBook} with all the typical persons. + * Returns an {@code AddressBook} with all the typical tasks. */ public static AddressBook getTypicalAddressBook() { AddressBook ab = new AddressBook(); diff --git a/src/test/java/seedu/address/testutil/TypicalTasks.java b/src/test/java/seedu/address/testutil/TypicalTasks.java index bfb845c0076..ca3b72632b5 100644 --- a/src/test/java/seedu/address/testutil/TypicalTasks.java +++ b/src/test/java/seedu/address/testutil/TypicalTasks.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.List; +import seedu.address.model.AddressBook; import seedu.address.model.task.Deadline; import seedu.address.model.task.Event; import seedu.address.model.task.Task; @@ -41,6 +42,19 @@ public class TypicalTasks { public static final Event EVENT_TASK = new Event(VALID_EVENT_DESCRIPTION, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + + /** + * Returns an {@code AddressBook} with all the typical persons. + */ + public static AddressBook getTypicalAddressBook() { + AddressBook ab = new AddressBook(); + + for (Task task : getTypicalTasks()) { + ab.addTask(task); + } + return ab; + } + // Returns a list of all typical tasks public static List getTypicalTasks() { return new ArrayList<>(Arrays.asList(TODO_TASK, DEADLINE_TASK, EVENT_TASK)); From 914a320a09fa2f0dba2831d640581489147f0a7b Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 20:15:11 +0800 Subject: [PATCH 20/25] Add more tests --- .../logic/commands/CreateTaskCommandTest.java | 21 +++++++++++++++++++ .../logic/commands/DeleteTaskCommandTest.java | 9 ++++++++ .../seedu/address/model/task/DateTest.java | 16 +++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java index 8055e2a1986..3b42bc230f4 100644 --- a/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/CreateTaskCommandTest.java @@ -59,6 +59,27 @@ public void execute_duplicateTask_throwsCommandException() { assertThrows(CommandException.class, () -> command.execute(model), CreateTaskCommand.MESSAGE_DUPLICATE_TASK); } + @Test + public void getTaskToAdd_validTaskSet_returnsCorrectSet() { + // Prepare a set of tasks to add + HashSet tasksToAdd = new HashSet<>(); + tasksToAdd.add(TODO_TASK); + + CreateTaskCommand command = new CreateTaskCommand(tasksToAdd); + + assertEquals(tasksToAdd, command.getTaskToAdd()); + } + @Test + public void toString_validTaskSet_returnsCorrectString() { + // Prepare a set of tasks to add + HashSet tasksToAdd = new HashSet<>(); + tasksToAdd.add(TODO_TASK); + + CreateTaskCommand command = new CreateTaskCommand(tasksToAdd); + + String expectedString = "seedu.address.logic.commands.CreateTaskCommand{taskToAdd=[[T][ ] Buy groceries]}"; + assertEquals(expectedString, command.toString()); + } @Test public void equals() { diff --git a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java index 608d0feb982..7c3af5fb249 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java @@ -53,6 +53,15 @@ public void execute_invalidIndexUnfilteredList_throwsCommandException() { -> deleteTaskCommand.execute(model)); } + @Test + public void toString_validIndex_returnsCorrectString() { + DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(INDEX_FIRST_TASK); + System.out.println(deleteTaskCommand.toString()); + String expectedString = "seedu.address.logic.commands." + + "DeleteTaskCommand{targetIndex=seedu.address.commons.core.index.Index{zeroBasedIndex=0}}"; + assertEquals(expectedString, deleteTaskCommand.toString()); + } + @Test public void equals() { DeleteTaskCommand deleteFirstCommand = new DeleteTaskCommand(INDEX_FIRST_TASK); diff --git a/src/test/java/seedu/address/model/task/DateTest.java b/src/test/java/seedu/address/model/task/DateTest.java index b523e25df16..f5d1c6a6941 100644 --- a/src/test/java/seedu/address/model/task/DateTest.java +++ b/src/test/java/seedu/address/model/task/DateTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.LocalDate; import java.time.format.DateTimeFormatter; import org.junit.jupiter.api.Test; @@ -13,7 +14,7 @@ public class DateTest { private static final String VALID_DATE = "2023-10-20"; private static final String INVALID_DATE = "2023-15-45"; private static final String VALID_DATE_FORMATTED = "Oct 20 2023"; - + private static final String DIFFERENT_DATE = "2023-11-20"; private static final DateTimeFormatter CUSTOM_FORMATTER = DateTimeFormatter.ofPattern("MMM dd yyyy"); @Test @@ -49,6 +50,19 @@ public void format_customFormatter_returnsFormattedDate() { assertEquals(VALID_DATE_FORMATTED, formattedDate); } + @Test + public void getDate_validDate_returnsLocalDate() { + Date date = new Date(VALID_DATE); + LocalDate expectedLocalDate = LocalDate.parse(VALID_DATE); + assertEquals(expectedLocalDate, date.getDate()); + } + + @Test + public void equals_nonDateObject_returnsFalse() { + Date date = new Date(VALID_DATE); + assertFalse(date.equals("Some String")); + } + @Test public void equals_sameDate_returnsTrue() { Date date1 = new Date(VALID_DATE); From efbe1a91723cabe4cd03bfd8ea6c622057df7828 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 20:17:06 +0800 Subject: [PATCH 21/25] Fix checkstyle --- .../seedu/address/logic/commands/DeleteTaskCommandTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java index 7c3af5fb249..ea97ac09c2a 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java @@ -57,8 +57,8 @@ public void execute_invalidIndexUnfilteredList_throwsCommandException() { public void toString_validIndex_returnsCorrectString() { DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(INDEX_FIRST_TASK); System.out.println(deleteTaskCommand.toString()); - String expectedString = "seedu.address.logic.commands." + - "DeleteTaskCommand{targetIndex=seedu.address.commons.core.index.Index{zeroBasedIndex=0}}"; + String expectedString = "seedu.address.logic.commands." + + "DeleteTaskCommand{targetIndex=seedu.address.commons.core.index.Index{zeroBasedIndex=0}}"; assertEquals(expectedString, deleteTaskCommand.toString()); } From 839ff998b40d697dee5dde31a34868982e4e96f5 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 20:33:54 +0800 Subject: [PATCH 22/25] Add more tests --- .../seedu/address/logic/MessagesTest.java | 11 +++ .../model/task/UniqueTaskListTest.java | 36 ++++++++ ...criptionContainsKeywordsPredicateTest.java | 83 +++++++++++++++++++ .../seedu/address/testutil/TypicalTasks.java | 2 + 4 files changed, 132 insertions(+) create mode 100644 src/test/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicateTest.java diff --git a/src/test/java/seedu/address/logic/MessagesTest.java b/src/test/java/seedu/address/logic/MessagesTest.java index 6124dda957e..feb6360b1f9 100644 --- a/src/test/java/seedu/address/logic/MessagesTest.java +++ b/src/test/java/seedu/address/logic/MessagesTest.java @@ -11,7 +11,9 @@ import seedu.address.model.person.Person; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Task; import seedu.address.testutil.PersonBuilder; +import seedu.address.testutil.TypicalTasks; public class MessagesTest { @@ -62,4 +64,13 @@ public void format_tag_success() { String actualOutput = Messages.format(tag); assertEquals(expectedOutput, actualOutput); } + + @Test + public void format_task_success() { + Task task = TypicalTasks.TODO_TASK; + String expectedOutput = task.getDescription(); + + String actualOutput = Messages.format(task); + assertEquals(expectedOutput, actualOutput); + } } diff --git a/src/test/java/seedu/address/model/task/UniqueTaskListTest.java b/src/test/java/seedu/address/model/task/UniqueTaskListTest.java index 927cdaeac06..da11f9d5be1 100644 --- a/src/test/java/seedu/address/model/task/UniqueTaskListTest.java +++ b/src/test/java/seedu/address/model/task/UniqueTaskListTest.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; import org.junit.jupiter.api.Test; @@ -163,4 +164,39 @@ public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationEx assertThrows(UnsupportedOperationException.class, () -> uniqueTaskList.asUnmodifiableObservableList().remove(0)); } + + @Test + public void hashCode_sameInternalList_returnsSameHashCode() { + uniqueTaskList.add(TODO_TASK); + UniqueTaskList anotherUniqueTaskList = new UniqueTaskList(); + anotherUniqueTaskList.add(TODO_TASK); + assertEquals(uniqueTaskList.hashCode(), anotherUniqueTaskList.hashCode()); + } + + @Test + public void hashCode_differentInternalList_returnsDifferentHashCode() { + uniqueTaskList.add(TODO_TASK); + UniqueTaskList anotherUniqueTaskList = new UniqueTaskList(); + anotherUniqueTaskList.add(EVENT_TASK); + assertFalse(uniqueTaskList.hashCode() == anotherUniqueTaskList.hashCode()); + } + + @Test + public void toString_returnsCorrectStringRepresentation() { + uniqueTaskList.add(TODO_TASK); + assertEquals(Collections.singletonList(TODO_TASK).toString(), uniqueTaskList.toString()); + } + + @Test + public void iterator_iterateOverList_returnsCorrectOrder() { + uniqueTaskList.add(TODO_TASK); + uniqueTaskList.add(EVENT_TASK); + List taskList = Arrays.asList(TODO_TASK, EVENT_TASK); + Iterator iterator = uniqueTaskList.iterator(); + for (Task task : taskList) { + assertTrue(iterator.hasNext()); + assertEquals(task, iterator.next()); + } + } } + diff --git a/src/test/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicateTest.java new file mode 100644 index 00000000000..c25e2735069 --- /dev/null +++ b/src/test/java/seedu/address/model/task/keywordspredicate/DescriptionContainsKeywordsPredicateTest.java @@ -0,0 +1,83 @@ +package seedu.address.model.task.keywordspredicate; + +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.model.task.Task; +import seedu.address.testutil.TypicalTasks; + +public class DescriptionContainsKeywordsPredicateTest { + + private static final Task TASK_BUY_GROCERIES = TypicalTasks.TODO_TASK; + private static final Task TASK_SUBMIT_ASSIGNMENT = TypicalTasks.SUBMIT_ASSIGNMENT_TASK; + + @Test + public void equals() { + List firstPredicateKeywordList = Collections.singletonList("groceries"); + List secondPredicateKeywordList = Arrays.asList("groceries", "assignment"); + + DescriptionContainsKeywordsPredicate firstPredicate = + new DescriptionContainsKeywordsPredicate(firstPredicateKeywordList); + DescriptionContainsKeywordsPredicate secondPredicate = + new DescriptionContainsKeywordsPredicate(secondPredicateKeywordList); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + DescriptionContainsKeywordsPredicate firstPredicateCopy = + new DescriptionContainsKeywordsPredicate(firstPredicateKeywordList); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different predicate -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_descriptionContainsKeywords_returnsTrue() { + // One keyword + DescriptionContainsKeywordsPredicate predicate = + new DescriptionContainsKeywordsPredicate(Collections.singletonList("groceries")); + assertTrue(predicate.test(TASK_BUY_GROCERIES)); + + // Multiple keywords + predicate = new DescriptionContainsKeywordsPredicate(Arrays.asList("groceries", "assignment")); + assertTrue(predicate.test(TASK_BUY_GROCERIES)); + + // Only one matching keyword + predicate = new DescriptionContainsKeywordsPredicate(Arrays.asList("assignment", "groceries")); + assertTrue(predicate.test(TASK_SUBMIT_ASSIGNMENT)); + + // Mixed-case keywords + predicate = new DescriptionContainsKeywordsPredicate(Arrays.asList("GrOCeRiEs", "ASSIGNMENT")); + assertTrue(predicate.test(TASK_BUY_GROCERIES)); + } + + @Test + public void test_descriptionDoesNotContainKeywords_returnsFalse() { + // Zero keywords + DescriptionContainsKeywordsPredicate predicate = + new DescriptionContainsKeywordsPredicate(Collections.emptyList()); + assertFalse(predicate.test(TASK_BUY_GROCERIES)); + + // Non-matching keyword + predicate = new DescriptionContainsKeywordsPredicate(Arrays.asList("assignment")); + assertFalse(predicate.test(TASK_BUY_GROCERIES)); + + // Keywords match part of the description but not fully + predicate = new DescriptionContainsKeywordsPredicate(Arrays.asList("buy", "grocer")); + assertFalse(predicate.test(TASK_SUBMIT_ASSIGNMENT)); + } +} diff --git a/src/test/java/seedu/address/testutil/TypicalTasks.java b/src/test/java/seedu/address/testutil/TypicalTasks.java index ca3b72632b5..789a3ccf1f6 100644 --- a/src/test/java/seedu/address/testutil/TypicalTasks.java +++ b/src/test/java/seedu/address/testutil/TypicalTasks.java @@ -19,6 +19,7 @@ public class TypicalTasks { public static final String VALID_TODO_DESCRIPTION = "Buy groceries"; public static final String VALID_DEADLINE_DESCRIPTION = "Submit report"; public static final String VALID_EVENT_DESCRIPTION = "Project meeting"; + public static final String VALID_SUBMIT_ASSIGNMENT_DESCRIPTION = "Submit assignment"; // Dates for Deadline and Event tasks public static final String VALID_DEADLINE_DATE = "2024-12-31"; @@ -41,6 +42,7 @@ public class TypicalTasks { public static final Deadline DEADLINE_TASK = new Deadline(VALID_DEADLINE_DESCRIPTION, VALID_DEADLINE_DATE); public static final Event EVENT_TASK = new Event(VALID_EVENT_DESCRIPTION, VALID_EVENT_START_DATE, VALID_EVENT_END_DATE); + public static final Todo SUBMIT_ASSIGNMENT_TASK = new Todo(VALID_SUBMIT_ASSIGNMENT_DESCRIPTION); // New Task /** From 944a321f6f34771f41aaae43a1c9d702b17ba6e9 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Wed, 23 Oct 2024 20:54:11 +0800 Subject: [PATCH 23/25] Add more tests --- .../logic/commands/CommandTestUtil.java | 2 ++ .../seedu/address/model/ModelManagerTest.java | 34 +++++++++++++++++++ .../address/model/person/PersonTest.java | 31 +++++++++++++++++ .../address/model/task/DescriptionTest.java | 12 +++++++ .../address/model/task/ParsedTaskTest.java | 11 ++++++ 5 files changed, 90 insertions(+) diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 344099c0288..a029e655435 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -57,6 +57,8 @@ public class CommandTestUtil { public static final String VALID_TAG_NEIGHBOR = "neighbor"; public static final String VALID_TAG_PHOTOGRAPHER = "photographer"; public static final String VALID_WEDDING_AMY = "Amy's Wedding"; + public static final String VALID_TASK_TODO = "todo: Different Task"; + public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY; public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB; diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index 4ed9c40a04d..d436abefed8 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -8,6 +8,7 @@ import static seedu.address.testutil.TypicalPersons.ALICE; import static seedu.address.testutil.TypicalPersons.BENSON; import static seedu.address.testutil.TypicalTags.FLORIST; +import static seedu.address.testutil.TypicalTasks.TODO_TASK; import java.nio.file.Path; import java.nio.file.Paths; @@ -19,6 +20,10 @@ import seedu.address.model.person.keywordspredicate.NameContainsKeywordsPredicate; import seedu.address.model.tag.Tag; import seedu.address.model.tag.TagName; +import seedu.address.model.task.Task; +import seedu.address.model.task.Todo; +import seedu.address.model.wedding.Wedding; +import seedu.address.model.wedding.WeddingName; import seedu.address.testutil.AddressBookBuilder; public class ModelManagerTest { @@ -135,6 +140,35 @@ public void updateFilteredTagList_nullPredicate_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> modelManager.updateFilteredTagList(null)); } + @Test + public void setTag_validTag_replacesTagSuccessfully() { + modelManager.addTag(FLORIST); + Tag editedTag = new Tag(new TagName("newFlorist")); + modelManager.setTag(FLORIST, editedTag); + assertTrue(modelManager.hasTag(editedTag)); + assertFalse(modelManager.hasTag(FLORIST)); + } + + @Test + public void setTask_validTask_replacesTaskSuccessfully() { + modelManager.addTask(TODO_TASK); + Task editedTask = new Todo("New task description"); + modelManager.setTask(TODO_TASK, editedTask); + assertTrue(modelManager.hasTask(editedTask)); + assertFalse(modelManager.hasTask(TODO_TASK)); + } + + @Test + public void setWedding_validWedding_replacesWeddingSuccessfully() { + Wedding wedding = new Wedding(new WeddingName("Old Wedding")); + Wedding editedWedding = new Wedding(new WeddingName("New Wedding")); + modelManager.addWedding(wedding); + modelManager.setWedding(wedding, editedWedding); + assertTrue(modelManager.hasWedding(editedWedding)); + assertFalse(modelManager.hasWedding(wedding)); + } + + @Test public void equals() { AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build(); diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java index 9c8fd9f688f..9b8cf9bf26e 100644 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ b/src/test/java/seedu/address/model/person/PersonTest.java @@ -8,6 +8,8 @@ import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB; import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB; import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TASK_TODO; +import static seedu.address.logic.commands.CommandTestUtil.VALID_WEDDING_AMY; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalPersons.ALICE; import static seedu.address.testutil.TypicalPersons.BOB; @@ -88,6 +90,35 @@ public void equals() { // different tags -> returns false editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build(); assertFalse(ALICE.equals(editedAlice)); + + // different weddings -> returns false + editedAlice = new PersonBuilder(ALICE).withWeddings(VALID_WEDDING_AMY).build(); + assertFalse(ALICE.equals(editedAlice)); + + // different tasks -> returns false + editedAlice = new PersonBuilder(ALICE).withTasks(VALID_TASK_TODO).build(); + assertFalse(ALICE.equals(editedAlice)); + } + + @Test + public void hashCodeTest() { + Person person1 = new PersonBuilder(ALICE).build(); + Person person2 = new PersonBuilder(ALICE).build(); + + // same person -> returns same hashCode + assertEquals(person1.hashCode(), person2.hashCode()); + + // different name -> returns different hashCode + Person personWithDifferentName = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build(); + assertFalse(person1.hashCode() == personWithDifferentName.hashCode()); + + // different weddings -> returns different hashCode + Person personWithDifferentWeddings = new PersonBuilder(ALICE).withWeddings(VALID_WEDDING_AMY).build(); + assertFalse(person1.hashCode() == personWithDifferentWeddings.hashCode()); + + // different tasks -> returns different hashCode + Person personWithDifferentTasks = new PersonBuilder(ALICE).withTasks(VALID_TASK_TODO).build(); + assertFalse(person1.hashCode() == personWithDifferentTasks.hashCode()); } @Test diff --git a/src/test/java/seedu/address/model/task/DescriptionTest.java b/src/test/java/seedu/address/model/task/DescriptionTest.java index 44fc2294632..e9293fcf67b 100644 --- a/src/test/java/seedu/address/model/task/DescriptionTest.java +++ b/src/test/java/seedu/address/model/task/DescriptionTest.java @@ -61,6 +61,18 @@ public void equals_differentDescription_returnsFalse() { assertFalse(description1.equals(description2)); } + @Test + public void equals_nullDescription_returnsFalse() { + Description description = new Description(VALID_DESCRIPTION); + assertFalse(description.equals(null)); + } + + @Test + public void equals_differentObjectType_returnsFalse() { + Description description = new Description(VALID_DESCRIPTION); + assertFalse(description.equals("some string")); + } + @Test public void hashCode_sameDescription_returnsSameHashCode() { Description description1 = new Description(VALID_DESCRIPTION); diff --git a/src/test/java/seedu/address/model/task/ParsedTaskTest.java b/src/test/java/seedu/address/model/task/ParsedTaskTest.java index da5cce36dd2..0ec63aaf102 100644 --- a/src/test/java/seedu/address/model/task/ParsedTaskTest.java +++ b/src/test/java/seedu/address/model/task/ParsedTaskTest.java @@ -46,6 +46,17 @@ public void equals_differentParsedTask_returnsFalse() { assertFalse(parsedTask1.equals(parsedTask2)); } + @Test + public void equals_nullParsedTask_returnsFalse() { + ParsedTask parsedTask = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertFalse(parsedTask.equals(null)); + } + + @Test + public void equals_differentObjectType_returnsFalse() { + ParsedTask parsedTask = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); + assertFalse(parsedTask.equals("some string")); + } @Test public void hashCode_sameParsedTask_returnsSameHashCode() { ParsedTask parsedTask1 = new ParsedTask(VALID_TASK_TYPE, VALID_TASK_DETAILS); From 73cef602c2866f751a64b5c2ad75441da9563bee Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Thu, 24 Oct 2024 13:06:35 +0800 Subject: [PATCH 24/25] Resolve all comments in PR --- .../{ListTaskCommand.java => ListTasksCommand.java} | 4 ++-- .../seedu/address/logic/parser/AddressBookParser.java | 4 ++-- ...tTaskCommandTest.java => ListTasksCommandTest.java} | 10 +++++----- .../address/logic/parser/AddressBookParserTest.java | 6 +++--- src/test/java/seedu/address/model/task/DateTest.java | 6 ++++++ 5 files changed, 18 insertions(+), 12 deletions(-) rename src/main/java/seedu/address/logic/commands/{ListTaskCommand.java => ListTasksCommand.java} (85%) rename src/test/java/seedu/address/logic/commands/{ListTaskCommandTest.java => ListTasksCommandTest.java} (74%) diff --git a/src/main/java/seedu/address/logic/commands/ListTaskCommand.java b/src/main/java/seedu/address/logic/commands/ListTasksCommand.java similarity index 85% rename from src/main/java/seedu/address/logic/commands/ListTaskCommand.java rename to src/main/java/seedu/address/logic/commands/ListTasksCommand.java index 765b11e3b8a..f684ebe820f 100644 --- a/src/main/java/seedu/address/logic/commands/ListTaskCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListTasksCommand.java @@ -10,9 +10,9 @@ /** * Lists all tasks in the address book to the user. */ -public class ListTaskCommand extends Command { +public class ListTasksCommand extends Command { - public static final String COMMAND_WORD = "list-task"; + public static final String COMMAND_WORD = "list-tasks"; public static final String MESSAGE_SUCCESS = "Listed all tasks"; diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 5f29af0842f..f3084842d71 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -20,7 +20,7 @@ import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; -import seedu.address.logic.commands.ListTaskCommand; +import seedu.address.logic.commands.ListTasksCommand; import seedu.address.logic.commands.TagCommand; import seedu.address.logic.commands.UntagCommand; import seedu.address.logic.commands.findcommand.FindCommand; @@ -89,7 +89,7 @@ public Command parseCommand(String userInput) throws ParseException { case AssignWeddingCommand.COMMAND_WORD -> new AssignWeddingCommandParser().parse(arguments); case UnassignWeddingCommand.COMMAND_WORD -> new UnassignWeddingCommandParser().parse(arguments); case CreateTaskCommand.COMMAND_WORD -> new CreateTaskCommandParser().parse(arguments); - case ListTaskCommand.COMMAND_WORD -> new ListTaskCommand(); + case ListTasksCommand.COMMAND_WORD -> new ListTasksCommand(); case DeleteTaskCommand.COMMAND_WORD -> new DeleteTaskCommandParser().parse(arguments); default -> { logger.finer("This user input caused a ParseException: " + userInput); diff --git a/src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/ListTasksCommandTest.java similarity index 74% rename from src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java rename to src/test/java/seedu/address/logic/commands/ListTasksCommandTest.java index 2cf49c52730..59bc783c51e 100644 --- a/src/test/java/seedu/address/logic/commands/ListTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ListTasksCommandTest.java @@ -15,7 +15,7 @@ /** * Contains integration tests (interaction with the Model) and unit tests for ListTaskCommand. */ -public class ListTaskCommandTest { +public class ListTasksCommandTest { private Model model; private Model expectedModel; @@ -28,14 +28,14 @@ public void setUp() { @Test public void execute_listIsNotFiltered_showsSameList() { - CommandResult actualCommandResult = new ListTaskCommand().execute(model); - assertCommandSuccess(new ListTaskCommand(), model, actualCommandResult, expectedModel); + CommandResult actualCommandResult = new ListTasksCommand().execute(model); + assertCommandSuccess(new ListTasksCommand(), model, actualCommandResult, expectedModel); } @Test public void execute_listIsFiltered_showsEverything() { showTaskAtIndex(model, INDEX_FIRST); // Filters the task list to show only the first task - CommandResult actualCommandResult = new ListTaskCommand().execute(model); - assertCommandSuccess(new ListTaskCommand(), model, actualCommandResult, expectedModel); + CommandResult actualCommandResult = new ListTasksCommand().execute(model); + assertCommandSuccess(new ListTasksCommand(), model, actualCommandResult, expectedModel); } } diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 2b3b87939b0..a02800d46f4 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -26,7 +26,7 @@ import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; -import seedu.address.logic.commands.ListTaskCommand; +import seedu.address.logic.commands.ListTasksCommand; import seedu.address.logic.commands.TagCommand; import seedu.address.logic.commands.UntagCommand; import seedu.address.logic.commands.findcommand.FindCommand; @@ -202,8 +202,8 @@ public void parseCommand_listWeddings() throws Exception { @Test public void parseCommand_listTask() throws Exception { - assertTrue(parser.parseCommand(ListTaskCommand.COMMAND_WORD) instanceof ListTaskCommand); - assertTrue(parser.parseCommand(ListTaskCommand.COMMAND_WORD + " 3") instanceof ListTaskCommand); + assertTrue(parser.parseCommand(ListTasksCommand.COMMAND_WORD) instanceof ListTasksCommand); + assertTrue(parser.parseCommand(ListTasksCommand.COMMAND_WORD + " 3") instanceof ListTasksCommand); } @Test diff --git a/src/test/java/seedu/address/model/task/DateTest.java b/src/test/java/seedu/address/model/task/DateTest.java index f5d1c6a6941..98c42fd96f9 100644 --- a/src/test/java/seedu/address/model/task/DateTest.java +++ b/src/test/java/seedu/address/model/task/DateTest.java @@ -70,6 +70,12 @@ public void equals_sameDate_returnsTrue() { assertTrue(date1.equals(date2)); } + @Test + public void equals_self_returnsTrue() { + Date date1 = new Date(VALID_DATE); + assertTrue(date1.equals(date1)); + } + @Test public void equals_differentDate_returnsFalse() { Date date1 = new Date(VALID_DATE); From ca8d9a6e770546d17cdde72210369abede3328b1 Mon Sep 17 00:00:00 2001 From: DanzaSeah Date: Thu, 24 Oct 2024 13:10:52 +0800 Subject: [PATCH 25/25] Add test for Event --- src/test/java/seedu/address/model/task/EventTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/seedu/address/model/task/EventTest.java b/src/test/java/seedu/address/model/task/EventTest.java index 6e1319cf2a2..48c09d5a1d1 100644 --- a/src/test/java/seedu/address/model/task/EventTest.java +++ b/src/test/java/seedu/address/model/task/EventTest.java @@ -66,6 +66,13 @@ public void equals_sameEvent_returnsTrue() { assertTrue(event1.equals(event2)); } + @Test + public void equals_nonEvent_returnsFalse() { + Event event1 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE); + Todo event2 = new Todo(VALID_DESCRIPTION); + assertFalse(event1.equals(event2)); + } + @Test public void equals_differentEvent_returnsFalse() { Event event1 = new Event(VALID_DESCRIPTION, VALID_FROM_DATE, VALID_TO_DATE);