Skip to content

Commit

Permalink
Merge pull request #89 from pra-navi/branch-deleteTask
Browse files Browse the repository at this point in the history
feat: Implement deleteTask
  • Loading branch information
HugeNoob authored Oct 19, 2023
2 parents ef04b62 + 29ef7d3 commit 958558e
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 1 deletion.
69 changes: 69 additions & 0 deletions src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java
Original file line number Diff line number Diff line change
@@ -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 = "deleteTask";

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<Task> lastShownList = model.getFilteredTaskList();

if (targetIndex.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
}

Task toDelete = lastShownList.get(targetIndex.getZeroBased());
model.deleteTask(toDelete);
return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, Messages.format(toDelete)));
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof DeleteTaskCommand)) {
return false;
}

DeleteTaskCommand otherDeleteCommand = (DeleteTaskCommand) other;
return targetIndex.equals(otherDeleteCommand.targetIndex);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("targetIndex", targetIndex)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import seedu.address.logic.commands.DeleteAllPersonCommand;
import seedu.address.logic.commands.DeleteAllTaskCommand;
import seedu.address.logic.commands.DeletePersonCommand;
import seedu.address.logic.commands.DeleteTaskCommand;
import seedu.address.logic.commands.EditPersonCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindPersonCommand;
Expand Down Expand Up @@ -80,6 +81,9 @@ public Command parseCommand(String userInput) throws ParseException {
case ListTaskCommand.COMMAND_WORD:
return new ListTaskCommand();

case DeleteTaskCommand.COMMAND_WORD:
return new DeleteTaskCommandParser().parse(arguments);

case MarkTaskCommand.COMMAND_WORD:
return new MarkTaskCommandParser().parse(arguments);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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<DeleteTaskCommand> {
/**
* 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);
}
}
}
6 changes: 6 additions & 0 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ public interface Model {
*/
void addTask(Task task);

/**
* Deletes the given task.
* The task must exist in the address book.
*/
void deleteTask(Task target);

/**
* Replaces the given task {@code target} with {@code editedTask}.
* {@code target} must exist in the task list.
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ public void addTask(Task task) {
updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
}

@Override
public void deleteTask(Task task) {
addressBook.deleteTask(task);
}

@Override
public void setTask(Task target, Task editedTask) {
requireAllNonNull(target, editedTask);
Expand Down
120 changes: 120 additions & 0 deletions src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
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.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.commands.CommandTestUtil.showTaskAtIndex;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST;
import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND;
import static seedu.address.testutil.TypicalTasks.getTypicalAddressBook;

import org.junit.jupiter.api.Test;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.task.Task;

/**
* Contains integration tests (interaction with the Model) and unit tests for
* {@code DeleteTaskCommand}.
*/
public class DeleteTaskCommandTest {

private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());

@Test
public void execute_validIndexUnfilteredList_success() {
Task taskToDelete = model.getFilteredTaskList().get(INDEX_FIRST.getZeroBased());
DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(INDEX_FIRST);

String expectedMessage = String.format(DeleteTaskCommand.MESSAGE_DELETE_TASK_SUCCESS,
Messages.format(taskToDelete));

ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.deleteTask(taskToDelete);

assertCommandSuccess(deleteTaskCommand, model, expectedMessage, expectedModel);
}

@Test
public void execute_invalidIndexUnfilteredList_throwsCommandException() {
Index outOfBoundIndex = Index.fromOneBased(model.getFilteredTaskList().size() + 1);
DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(outOfBoundIndex);

assertCommandFailure(deleteTaskCommand, model, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
}

@Test
public void execute_validIndexFilteredList_success() {
showTaskAtIndex(model, INDEX_FIRST);

Task taskToDelete = model.getFilteredTaskList().get(INDEX_FIRST.getZeroBased());
DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(INDEX_FIRST);

String expectedMessage = String.format(DeleteTaskCommand.MESSAGE_DELETE_TASK_SUCCESS,
Messages.format(taskToDelete));

Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.deleteTask(taskToDelete);
showNoTask(expectedModel);

assertCommandSuccess(deleteTaskCommand, model, expectedMessage, expectedModel);
}

@Test
public void execute_invalidIndexFilteredList_throwsCommandException() {
showTaskAtIndex(model, INDEX_FIRST);

Index outOfBoundIndex = INDEX_SECOND;
// ensures that outOfBoundIndex is still in bounds of address book list
assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getTaskList().size());

DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(outOfBoundIndex);

assertCommandFailure(deleteTaskCommand, model, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
}

@Test
public void equals() {
DeleteTaskCommand deleteTaskFirstCommand = new DeleteTaskCommand(INDEX_FIRST);
DeleteTaskCommand deleteTaskSecondCommand = new DeleteTaskCommand(INDEX_SECOND);

// same object -> returns true
assertTrue(deleteTaskFirstCommand.equals(deleteTaskFirstCommand));

// same values -> returns true
DeleteTaskCommand deleteTaskFirstCommandCopy = new DeleteTaskCommand(INDEX_FIRST);
assertTrue(deleteTaskFirstCommand.equals(deleteTaskFirstCommandCopy));

// different types -> returns false
assertFalse(deleteTaskFirstCommand.equals(1));

// null -> returns false
assertFalse(deleteTaskFirstCommand.equals(null));

// different task -> returns false
assertFalse(deleteTaskFirstCommand.equals(deleteTaskSecondCommand));
}

@Test
public void toStringMethod() {
Index targetIndex = Index.fromOneBased(1);
DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(targetIndex);
String expected = DeleteTaskCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
assertEquals(expected, deleteTaskCommand.toString());
}

/**
* Updates {@code model}'s filtered list to show no task.
*/
private void showNoTask(Model model) {
model.updateFilteredTaskList(p -> false);

assertTrue(model.getFilteredTaskList().isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import seedu.address.logic.commands.DeleteAllPersonCommand;
import seedu.address.logic.commands.DeleteAllTaskCommand;
import seedu.address.logic.commands.DeletePersonCommand;
import seedu.address.logic.commands.DeleteTaskCommand;
import seedu.address.logic.commands.EditPersonCommand;
import seedu.address.logic.commands.EditPersonCommand.EditPersonDescriptor;
import seedu.address.logic.commands.ExitCommand;
Expand Down Expand Up @@ -132,6 +133,13 @@ public void parseCommand_unmarkTask() throws Exception {
assertEquals(new UnmarkTaskCommand(INDEX_FIRST), command);
}

@Test
public void parseCommand_deleteTask() throws Exception {
DeleteTaskCommand command = (DeleteTaskCommand) parser.parseCommand(
DeleteTaskCommand.COMMAND_WORD + " " + INDEX_FIRST.getOneBased());
assertEquals(new DeleteTaskCommand(INDEX_FIRST), command);
}

@Test
public void parseCommand_deleteAllTask() throws Exception {
assertTrue(parser.parseCommand(DeleteAllTaskCommand.COMMAND_WORD) instanceof DeleteAllTaskCommand);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST;

import org.junit.jupiter.api.Test;

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.
* The path variation for those two cases occur inside the ParserUtil, and
* therefore should be covered by the ParserUtilTest.
*/
public class DeleteTaskCommandParserTest {

private DeleteTaskCommandParser parser = new DeleteTaskCommandParser();

@Test
public void parse_validArgs_returnsDeleteTaskCommand() {
assertParseSuccess(parser, "1", new DeleteTaskCommand(INDEX_FIRST));
}

@Test
public void parse_invalidArgs_throwsParseException() {
assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
DeleteTaskCommand.MESSAGE_USAGE));
}
}
4 changes: 3 additions & 1 deletion src/test/java/seedu/address/model/AddressBookTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ public void deleteAllTask_clearsTaskList() {
private static class AddressBookStub implements ReadOnlyAddressBook {
private final ObservableList<Person> persons = FXCollections.observableArrayList();

private final ObservableList<Task> tasks = FXCollections.observableArrayList();

AddressBookStub(Collection<Person> persons) {
this.persons.setAll(persons);
}
Expand All @@ -121,7 +123,7 @@ public ObservableList<Person> getPersonList() {

@Override
public ObservableList<Task> getTaskList() {
return null;
return tasks;
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/test/java/seedu/address/model/ModelStub.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public void setTask(Task target, Task editedTask) {
throw new AssertionError("This method should not be called.");
}

@Override
public void deleteTask(Task task) {
throw new AssertionError("This method should not be called.");
}

@Override
public ObservableList<Person> getFilteredPersonList() {
throw new AssertionError("This method should not be called.");
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/seedu/address/model/task/UniqueTaskListTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.junit.jupiter.api.Test;

import seedu.address.model.task.exceptions.TaskNotFoundException;
import seedu.address.testutil.TaskBuilder;

public class UniqueTaskListTest {
Expand Down Expand Up @@ -45,6 +46,24 @@ public void contains_taskWithSameFieldsInList_returnsTrue() {
assertTrue(uniqueTaskList.contains(agendaCopy));
}

@Test
public void remove_nullTask_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> uniqueTaskList.delete(null));
}

@Test
public void remove_staffDoesNotExist_throwsTaskNotFoundException() {
assertThrows(TaskNotFoundException.class, () -> uniqueTaskList.delete(AGENDA));
}

@Test
public void remove_existingTask_removesTask() {
uniqueTaskList.add(AGENDA);
uniqueTaskList.delete(AGENDA);
UniqueTaskList expectedUniqueTaskList = new UniqueTaskList();
assertEquals(expectedUniqueTaskList, uniqueTaskList);
}

@Test
public void deleteAll_clearsList() {
uniqueTaskList.add(AGENDA);
Expand Down

0 comments on commit 958558e

Please sign in to comment.