diff --git a/.classpath b/.classpath
index b646e855e65f..ce003ecf2ca6 100644
--- a/.classpath
+++ b/.classpath
@@ -17,5 +17,6 @@
+
diff --git a/libs/A0146130WreusedToTest.md b/libs/A0146130WreusedToTest.md
new file mode 100644
index 000000000000..b3041d81ba9b
--- /dev/null
+++ b/libs/A0146130WreusedToTest.md
@@ -0,0 +1,17 @@
+# A0146130WreusedToTest
+###### /src/test/java/seedu/gtd/logic/LogicManagerTest.java
+``` java
+ @Test
+ public void execute_help() throws Exception {
+ assertCommandBehavior("help", HelpCommand.MESSAGE_USAGE+"/n"+HelpCommand.SHOWING_HELP_MESSAGE);
+ assertTrue(helpShown);
+ assertCommandBehavior("help add", AddCommand.MESSAGE_USAGE);
+ assertCommandBehavior("help select", SelectCommand.MESSAGE_USAGE);
+ assertCommandBehavior("help delete", DeleteCommand.MESSAGE_USAGE);
+ assertCommandBehavior("help clear", ClearCommand.MESSAGE_USAGE);
+ assertCommandBehavior("help find", FindCommand.MESSAGE_USAGE);
+ assertCommandBehavior("help list", ListCommand.MESSAGE_USAGE);
+ assertCommandBehavior("help exit", ExitCommand.MESSAGE_USAGE);
+ }
+
+```
diff --git a/libs/Collate-GUI.jar b/libs/Collate-GUI.jar
new file mode 100644
index 000000000000..3f9e6de8069c
Binary files /dev/null and b/libs/Collate-GUI.jar differ
diff --git a/libs/addressbooklevel4.md b/libs/addressbooklevel4.md
new file mode 100644
index 000000000000..238c99e9cec5
--- /dev/null
+++ b/libs/addressbooklevel4.md
@@ -0,0 +1,481 @@
+# addressbooklevel4
+###### /src/test/java/seedu/gtd/logic/LogicManagerTest.java
+``` java
+
+ /**
+ * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule
+ */
+ @Rule
+ public TemporaryFolder saveFolder = new TemporaryFolder();
+
+ private Model model;
+ private Logic logic;
+
+ //These are for checking the correctness of the events raised
+ private ReadOnlyAddressBook latestSavedAddressBook;
+ private boolean helpShown;
+ private int targetedJumpIndex;
+
+ @Subscribe
+ private void handleLocalModelChangedEvent(AddressBookChangedEvent abce) {
+ latestSavedAddressBook = new AddressBook(abce.data);
+ }
+
+ @Subscribe
+ private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) {
+ helpShown = true;
+ }
+
+ @Subscribe
+ private void handleJumpToListRequestEvent(JumpToListRequestEvent je) {
+ targetedJumpIndex = je.targetIndex;
+ }
+
+ @Before
+ public void setup() {
+ model = new ModelManager();
+ String tempAddressBookFile = saveFolder.getRoot().getPath() + "TempAddressBook.xml";
+ String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json";
+ logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile));
+ EventsCenter.getInstance().registerHandler(this);
+
+ latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before.
+ helpShown = false;
+ targetedJumpIndex = -1; // non yet
+ }
+
+ @After
+ public void teardown() {
+ EventsCenter.clearSubscribers();
+ }
+
+ @Test
+ public void execute_invalid() throws Exception {
+ String invalidCommand = " ";
+ assertCommandBehavior(invalidCommand,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
+
+ /**
+ * Executes the command and confirms that the result message is correct.
+ * Both the 'address book' and the 'last shown list' are expected to be empty.
+ * @see #assertCommandBehavior(String, String, ReadOnlyAddressBook, List)
+ */
+ private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception {
+ assertCommandBehavior(inputCommand, expectedMessage, new AddressBook(), Collections.emptyList());
+ }
+
+ /**
+ * Executes the command and confirms that the result message is correct and
+ * also confirms that the following three parts of the LogicManager object's state are as expected:
+ * - the internal address book data are same as those in the {@code expectedAddressBook}
+ * - the backing list shown by UI matches the {@code shownList}
+ * - {@code expectedAddressBook} was saved to the storage file.
+ */
+ private void assertCommandBehavior(String inputCommand, String expectedMessage,
+ ReadOnlyAddressBook expectedAddressBook,
+ List extends ReadOnlyTask> expectedShownList) throws Exception {
+
+ //Execute the command
+ CommandResult result = logic.execute(inputCommand);
+
+ //Confirm the ui display elements should contain the right data
+ assertEquals(expectedMessage, result.feedbackToUser);
+ assertEquals(expectedShownList, model.getFilteredTaskList());
+
+ //Confirm the state of data (saved and in-memory) is as expected
+ assertEquals(expectedAddressBook, model.getAddressBook());
+ assertEquals(expectedAddressBook, latestSavedAddressBook);
+ }
+
+
+ @Test
+ public void execute_unknownCommandWord() throws Exception {
+ String unknownCommand = "uicfhmowqewca";
+ assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND);
+ }
+
+```
+###### /src/test/java/seedu/gtd/logic/LogicManagerTest.java
+``` java
+ @Test
+ public void execute_exit() throws Exception {
+ assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT);
+ }
+
+ @Test
+ public void execute_clear() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ model.addTask(helper.generateTask(1));
+ model.addTask(helper.generateTask(2));
+ model.addTask(helper.generateTask(3));
+
+ assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new AddressBook(), Collections.emptyList());
+ }
+
+
+ @Test
+ public void execute_add_invalidArgsFormat() throws Exception {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE);
+ assertCommandBehavior(
+ "add wrong args wrong args", expectedMessage);
+ assertCommandBehavior(
+ "add Valid Name 12345 d/valid@dueDate.butNoDueDatePrefix a/valid, address", expectedMessage);
+ assertCommandBehavior(
+ "add Valid Name d/12345 valid@address.butNoPrefix p/valid, priority", expectedMessage);
+ assertCommandBehavior(
+ "add Valid Name d/12345 a/valid@email.butNoAddressPrefix valid, priority", expectedMessage);
+ }
+
+ @Test
+ public void execute_add_invalidTaskData() throws Exception {
+ assertCommandBehavior(
+ "add []\\[;] d/12345 a/valid, address p/1", Name.MESSAGE_NAME_CONSTRAINTS);
+ assertCommandBehavior(
+ "add Valid Name d/not_numbers a/valid, address p/2", DueDate.MESSAGE_DUEDATE_CONSTRAINTS);
+ assertCommandBehavior(
+ "add Valid Name d/12345 a/valid, address p/not_priority_numbers", Priority.MESSAGE_PRIORITY_CONSTRAINTS);
+ assertCommandBehavior(
+ "add Valid Name d/12345 a/valid, address p/5 t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS);
+
+ }
+
+ @Test
+ public void execute_add_successful() throws Exception {
+ // setup expectations
+ TestDataHelper helper = new TestDataHelper();
+ Task toBeAdded = helper.adam();
+ AddressBook expectedAB = new AddressBook();
+ expectedAB.addTask(toBeAdded);
+
+ // execute command and verify result
+ assertCommandBehavior(helper.generateAddCommand(toBeAdded),
+ String.format(AddCommand.MESSAGE_SUCCESS, toBeAdded),
+ expectedAB,
+ expectedAB.getTaskList());
+
+ }
+
+ @Test
+ public void execute_addDuplicate_notAllowed() throws Exception {
+ // setup expectations
+ TestDataHelper helper = new TestDataHelper();
+ Task toBeAdded = helper.adam();
+ AddressBook expectedAB = new AddressBook();
+ expectedAB.addTask(toBeAdded);
+
+ // setup starting state
+ model.addTask(toBeAdded); // task already in internal address book
+
+ // execute command and verify result
+ assertCommandBehavior(
+ helper.generateAddCommand(toBeAdded),
+ AddCommand.MESSAGE_DUPLICATE_TASK,
+ expectedAB,
+ expectedAB.getTaskList());
+
+ }
+
+
+ @Test
+ public void execute_list_showsAllTasks() throws Exception {
+ // prepare expectations
+ TestDataHelper helper = new TestDataHelper();
+ AddressBook expectedAB = helper.generateAddressBook(2);
+ List extends ReadOnlyTask> expectedList = expectedAB.getTaskList();
+
+ // prepare address book state
+ helper.addToModel(model, 2);
+
+ assertCommandBehavior("list",
+ ListCommand.MESSAGE_SUCCESS,
+ expectedAB,
+ expectedList);
+ }
+
+
+ /**
+ * Confirms the 'invalid argument index number behaviour' for the given command
+ * targeting a single task in the shown list, using visible index.
+ * @param commandWord to test assuming it targets a single task in the last shown list based on visible index.
+ */
+ private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception {
+ assertCommandBehavior(commandWord , expectedMessage); //index missing
+ assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned
+ assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned
+ assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0
+ assertCommandBehavior(commandWord + " not_a_number", expectedMessage);
+ }
+
+ /**
+ * Confirms the 'invalid argument index number behaviour' for the given command
+ * targeting a single task in the shown list, using visible index.
+ * @param commandWord to test assuming it targets a single task in the last shown list based on visible index.
+ */
+ private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception {
+ String expectedMessage = MESSAGE_INVALID_TASK_DISPLAYED_INDEX;
+ TestDataHelper helper = new TestDataHelper();
+ List taskList = helper.generateTaskList(2);
+
+ // set AB state to 2 tasks
+ model.resetData(new AddressBook());
+ for (Task p : taskList) {
+ model.addTask(p);
+ }
+
+ assertCommandBehavior(commandWord + " 3", expectedMessage, model.getAddressBook(), taskList);
+ }
+
+ @Test
+ public void execute_selectInvalidArgsFormat_errorMessageShown() throws Exception {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE);
+ assertIncorrectIndexFormatBehaviorForCommand("select", expectedMessage);
+ }
+
+ @Test
+ public void execute_selectIndexNotFound_errorMessageShown() throws Exception {
+ assertIndexNotFoundBehaviorForCommand("select");
+ }
+
+ @Test
+ public void execute_select_jumpsToCorrectTask() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ List threeTasks = helper.generateTaskList(3);
+
+ AddressBook expectedAB = helper.generateAddressBook(threeTasks);
+ helper.addToModel(model, threeTasks);
+
+ assertCommandBehavior("select 2",
+ String.format(SelectCommand.MESSAGE_SELECT_TASK_SUCCESS, 2),
+ expectedAB,
+ expectedAB.getTaskList());
+ assertEquals(1, targetedJumpIndex);
+ assertEquals(model.getFilteredTaskList().get(1), threeTasks.get(1));
+ }
+
+
+ @Test
+ public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE);
+ assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage);
+ }
+
+ @Test
+ public void execute_deleteIndexNotFound_errorMessageShown() throws Exception {
+ assertIndexNotFoundBehaviorForCommand("delete");
+ }
+
+ @Test
+ public void execute_delete_removesCorrectTask() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ List threeTasks = helper.generateTaskList(3);
+
+ AddressBook expectedAB = helper.generateAddressBook(threeTasks);
+ expectedAB.removeTask(threeTasks.get(1));
+ helper.addToModel(model, threeTasks);
+
+ assertCommandBehavior("delete 2",
+ String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, threeTasks.get(1)),
+ expectedAB,
+ expectedAB.getTaskList());
+ }
+
+
+ @Test
+ public void execute_find_invalidArgsFormat() throws Exception {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE);
+ assertCommandBehavior("find ", expectedMessage);
+ }
+
+ @Test
+ public void execute_find_onlyMatchesFullWordsInNames() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla");
+ Task pTarget2 = helper.generateTaskWithName("bla KEY bla bceofeia");
+ Task p1 = helper.generateTaskWithName("KE Y");
+ Task p2 = helper.generateTaskWithName("KEYKEYKEY sduauo");
+
+ List fourTasks = helper.generateTaskList(p1, pTarget1, p2, pTarget2);
+ AddressBook expectedAB = helper.generateAddressBook(fourTasks);
+ List expectedList = helper.generateTaskList(pTarget1, pTarget2);
+ helper.addToModel(model, fourTasks);
+
+ assertCommandBehavior("find KEY",
+ Command.getMessageForTaskListShownSummary(expectedList.size()),
+ expectedAB,
+ expectedList);
+ }
+
+ @Test
+ public void execute_find_isNotCaseSensitive() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ Task p1 = helper.generateTaskWithName("bla bla KEY bla");
+ Task p2 = helper.generateTaskWithName("bla KEY bla bceofeia");
+ Task p3 = helper.generateTaskWithName("key key");
+ Task p4 = helper.generateTaskWithName("KEy sduauo");
+
+ List fourTasks = helper.generateTaskList(p3, p1, p4, p2);
+ AddressBook expectedAB = helper.generateAddressBook(fourTasks);
+ List expectedList = fourTasks;
+ helper.addToModel(model, fourTasks);
+
+ assertCommandBehavior("find KEY",
+ Command.getMessageForTaskListShownSummary(expectedList.size()),
+ expectedAB,
+ expectedList);
+ }
+
+ @Test
+ public void execute_find_matchesIfAnyKeywordPresent() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla");
+ Task pTarget2 = helper.generateTaskWithName("bla rAnDoM bla bceofeia");
+ Task pTarget3 = helper.generateTaskWithName("key key");
+ Task p1 = helper.generateTaskWithName("sduauo");
+
+ List fourTasks = helper.generateTaskList(pTarget1, p1, pTarget2, pTarget3);
+ AddressBook expectedAB = helper.generateAddressBook(fourTasks);
+ List expectedList = helper.generateTaskList(pTarget1, pTarget2, pTarget3);
+ helper.addToModel(model, fourTasks);
+
+ assertCommandBehavior("find key rAnDoM",
+ Command.getMessageForTaskListShownSummary(expectedList.size()),
+ expectedAB,
+ expectedList);
+ }
+
+
+ /**
+ * A utility class to generate test data.
+ */
+ class TestDataHelper{
+
+ Task adam() throws Exception {
+ Name name = new Name("Adam Brown");
+ DueDate privateDueDate = new DueDate("111111");
+ Address address = new Address("111, alpha street");
+ Priority privatePriority = new Priority("1");
+ Tag tag1 = new Tag("tag1");
+ Tag tag2 = new Tag("tag2");
+ UniqueTagList tags = new UniqueTagList(tag1, tag2);
+ return new Task(name, privateDueDate, address, privatePriority, tags);
+ }
+
+ /**
+ * Generates a valid task using the given seed.
+ * Running this function with the same parameter values guarantees the returned task will have the same state.
+ * Each unique seed will generate a unique Task object.
+ *
+ * @param seed used to generate the task data field values
+ */
+ Task generateTask(int seed) throws Exception {
+ return new Task(
+ new Name("Task " + seed),
+ new DueDate("" + Math.abs(seed)),
+ new Address(seed + ", -address"),
+ new Priority("1 " + seed),
+ new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1)))
+ );
+ }
+
+ /** Generates the correct add command based on the task given */
+ String generateAddCommand(Task p) {
+ StringBuffer cmd = new StringBuffer();
+
+ cmd.append("add ");
+
+ cmd.append(p.getName().toString());
+ cmd.append(" d/").append(p.getDueDate());
+ cmd.append(" a/").append(p.getAddress());
+ cmd.append(" p/").append(p.getPriority());
+
+ UniqueTagList tags = p.getTags();
+ for(Tag t: tags){
+ cmd.append(" t/").append(t.tagName);
+ }
+
+ return cmd.toString();
+ }
+
+ /**
+ * Generates an AddressBook with auto-generated tasks.
+ */
+ AddressBook generateAddressBook(int numGenerated) throws Exception{
+ AddressBook addressBook = new AddressBook();
+ addToAddressBook(addressBook, numGenerated);
+ return addressBook;
+ }
+
+ /**
+ * Generates an AddressBook based on the list of Tasks given.
+ */
+ AddressBook generateAddressBook(List tasks) throws Exception{
+ AddressBook addressBook = new AddressBook();
+ addToAddressBook(addressBook, tasks);
+ return addressBook;
+ }
+
+ /**
+ * Adds auto-generated Task objects to the given AddressBook
+ * @param addressBook The AddressBook to which the Tasks will be added
+ */
+ void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{
+ addToAddressBook(addressBook, generateTaskList(numGenerated));
+ }
+
+ /**
+ * Adds the given list of Tasks to the given AddressBook
+ */
+ void addToAddressBook(AddressBook addressBook, List tasksToAdd) throws Exception{
+ for(Task p: tasksToAdd){
+ addressBook.addTask(p);
+ }
+ }
+
+ /**
+ * Adds auto-generated Task objects to the given model
+ * @param model The model to which the Tasks will be added
+ */
+ void addToModel(Model model, int numGenerated) throws Exception{
+ addToModel(model, generateTaskList(numGenerated));
+ }
+
+ /**
+ * Adds the given list of Tasks to the given model
+ */
+ void addToModel(Model model, List tasksToAdd) throws Exception{
+ for(Task p: tasksToAdd){
+ model.addTask(p);
+ }
+ }
+
+ /**
+ * Generates a list of Tasks based on the flags.
+ */
+ List generateTaskList(int numGenerated) throws Exception{
+ List tasks = new ArrayList<>();
+ for(int i = 1; i <= numGenerated; i++){
+ tasks.add(generateTask(i));
+ }
+ return tasks;
+ }
+
+ List generateTaskList(Task... tasks) {
+ return Arrays.asList(tasks);
+ }
+
+ /**
+ * Generates a Task object with given name. Other fields will have some dummy values.
+ */
+ Task generateTaskWithName(String name) throws Exception {
+ return new Task(
+ new Name(name),
+ new DueDate("1"),
+ new Address("House of 1"),
+ new Priority("1"),
+ new UniqueTagList(new Tag("tag"))
+ );
+ }
+ }
+}
+```
diff --git a/src/main/java/seedu/gtd/MainApp.java b/src/main/java/seedu/gtd/MainApp.java
index 8055afe864fe..98d3e7f4c732 100644
--- a/src/main/java/seedu/gtd/MainApp.java
+++ b/src/main/java/seedu/gtd/MainApp.java
@@ -28,6 +28,8 @@
/**
* The main entry point to the application.
*/
+
+//@@author addressbook-level4
public class MainApp extends Application {
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
diff --git a/src/test/java/seedu/gtd/logic/LogicManagerTest.java b/src/test/java/seedu/gtd/logic/LogicManagerTest.java
index c850a81946da..e6192b344c41 100644
--- a/src/test/java/seedu/gtd/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/gtd/logic/LogicManagerTest.java
@@ -34,6 +34,8 @@
import static seedu.gtd.commons.core.Messages.*;
public class LogicManagerTest {
+
+ //@@author addressbook-level4
/**
* See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule
@@ -127,48 +129,22 @@ public void execute_unknownCommandWord() throws Exception {
String unknownCommand = "uicfhmowqewca";
assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND);
}
-
+
+ //@@author A0146130W-reusedToTest
@Test
public void execute_help() throws Exception {
assertCommandBehavior("help", HelpCommand.MESSAGE_USAGE+"/n"+HelpCommand.SHOWING_HELP_MESSAGE);
assertTrue(helpShown);
- }
-
- @Test
- public void execute_addhelp() throws Exception {
assertCommandBehavior("help add", AddCommand.MESSAGE_USAGE);
- }
-
- @Test
- public void execute_selecthelp() throws Exception {
assertCommandBehavior("help select", SelectCommand.MESSAGE_USAGE);
- }
-
- @Test
- public void execute_deletehelp() throws Exception {
assertCommandBehavior("help delete", DeleteCommand.MESSAGE_USAGE);
- }
-
- @Test
- public void execute_clearhelp() throws Exception {
assertCommandBehavior("help clear", ClearCommand.MESSAGE_USAGE);
- }
-
- @Test
- public void execute_findhelp() throws Exception {
assertCommandBehavior("help find", FindCommand.MESSAGE_USAGE);
- }
-
- @Test
- public void execute_listhelp() throws Exception {
assertCommandBehavior("help list", ListCommand.MESSAGE_USAGE);
- }
-
- @Test
- public void execute_exithelp() throws Exception {
assertCommandBehavior("help exit", ExitCommand.MESSAGE_USAGE);
}
+ //@@author addressbook-level4
@Test
public void execute_exit() throws Exception {
assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT);