diff --git a/src/main/java/seedu/address/logic/parser/AddTagCommandParser.java b/src/main/java/seedu/address/logic/parser/AddTagCommandParser.java index d138e402cb7..f4d0e52dc95 100644 --- a/src/main/java/seedu/address/logic/parser/AddTagCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddTagCommandParser.java @@ -9,7 +9,7 @@ import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.tag.Tag; -public class AddTagCommandParser { +public class AddTagCommandParser implements Parser { /** * Parses the given {@code String} of arguments in the context of the AddCommand diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 18fe5d02bd7..31572dd71ea 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -175,7 +175,8 @@ public boolean equals(Object obj) { ModelManager other = (ModelManager) obj; return addressBook.equals(other.addressBook) && userPrefs.equals(other.userPrefs) - && filteredPersons.equals(other.filteredPersons); + && filteredPersons.equals(other.filteredPersons) + && tags.equals(other.tags); } } diff --git a/src/test/java/seedu/address/logic/commands/AddTagCommandTest.java b/src/test/java/seedu/address/logic/commands/AddTagCommandTest.java new file mode 100644 index 00000000000..83f8d581e5c --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/AddTagCommandTest.java @@ -0,0 +1,221 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +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 java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; + +import javafx.collections.ObservableList; +import seedu.address.commons.core.GuiSettings; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.AddressBook; +import seedu.address.model.Model; +import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.ReadOnlyUserPrefs; +import seedu.address.model.person.Person; +import seedu.address.model.tag.Tag; +import seedu.address.testutil.TagBuilder; + + + +public class AddTagCommandTest { + @Test + public void constructor_nullTag_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new AddTagCommand(null)); + } + + @Test + public void execute_tagAcceptedByModel_addSuccessful() throws Exception { + AddTagCommandTest.ModelStubAcceptingTagAdded modelStub = new AddTagCommandTest.ModelStubAcceptingTagAdded(); + Tag validTag = new TagBuilder().build(); + + CommandResult commandResult = new AddTagCommand(validTag).execute(modelStub); + + assertEquals(String.format(AddTagCommand.MESSAGE_SUCCESS, validTag), commandResult.getFeedbackToUser()); + assertEquals(Arrays.asList(validTag), modelStub.tagsAdded); + } + + @Test + public void execute_duplicateTag_throwsCommandException() { + Tag validTag = new TagBuilder().build(); + AddTagCommand addTagCommand = new AddTagCommand(validTag); + AddTagCommandTest.ModelStub modelStub = new AddTagCommandTest.ModelStubWithTag(validTag); + + assertThrows(CommandException.class, AddTagCommand.MESSAGE_DUPLICATE_TAG, () -> + addTagCommand.execute(modelStub)); + } + + @Test + public void equals() { + Tag aTag = new TagBuilder().withTagName("ATag").build(); + Tag bTag = new TagBuilder().withTagName("BTag").build(); + AddTagCommand addATagCommand = new AddTagCommand(aTag); + AddTagCommand addBTagCommand = new AddTagCommand(bTag); + + // same object -> returns true + assertTrue(addATagCommand.equals(addATagCommand)); + + // same values -> returns true + AddTagCommand addATagCommandCopy = new AddTagCommand(aTag); + assertTrue(addATagCommand.equals(addATagCommandCopy)); + + // different types -> returns false + assertFalse(addATagCommand.equals(1)); + + // null -> returns false + assertFalse(addATagCommand.equals(null)); + + // different tag -> returns false + assertFalse(addATagCommand.equals(addBTagCommand)); + } + + /** + * A default model stub that have all of the methods failing. + */ + private class ModelStub implements Model { + @Override + public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ReadOnlyUserPrefs getUserPrefs() { + throw new AssertionError("This method should not be called."); + } + + @Override + public GuiSettings getGuiSettings() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setGuiSettings(GuiSettings guiSettings) { + throw new AssertionError("This method should not be called."); + } + + @Override + public Path getAddressBookFilePath() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setAddressBookFilePath(Path addressBookFilePath) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addPerson(Person person) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addTag(Tag tag) { + + } + + @Override + public void setAddressBook(ReadOnlyAddressBook newData) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ReadOnlyAddressBook getAddressBook() { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean hasPerson(Person person) { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean hasTag(Tag tag) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deletePerson(Person target) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteTag(Tag target) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setPerson(Person target, Person editedTag) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setTag(Tag target, Tag editedTag) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getFilteredPersonList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getTagList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredPersonList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + } + + /** + * A Model stub that contains a single tag. + */ + private class ModelStubWithTag extends AddTagCommandTest.ModelStub { + private final Tag tag; + + ModelStubWithTag(Tag tag) { + requireNonNull(tag); + this.tag = tag; + } + + @Override + public boolean hasTag(Tag tag) { + requireNonNull(tag); + return this.tag.isSameTag(tag); + } + } + + /** + * A Model stub that always accept the tag being added. + */ + private class ModelStubAcceptingTagAdded extends AddTagCommandTest.ModelStub { + final ArrayList tagsAdded = new ArrayList<>(); + + @Override + public boolean hasTag(Tag tag) { + requireNonNull(tag); + return tagsAdded.stream().anyMatch(tag::isSameTag); + } + + @Override + public void addTag(Tag tag) { + requireNonNull(tag); + tagsAdded.add(tag); + } + + @Override + public ReadOnlyAddressBook getAddressBook() { + return new AddressBook(); + } + } +} diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 643a1d08069..6de9143c6ac 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -53,6 +53,7 @@ public class CommandTestUtil { public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags + public static final String INVALID_TAG_DESC_FRIEND = " " + PREFIX_TAG + "friend*"; // '*' not allowed in tags public static final String PREAMBLE_WHITESPACE = "\t \r \n"; public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble"; diff --git a/src/test/java/seedu/address/logic/commands/DeleteTagCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTagCommandTest.java new file mode 100644 index 00000000000..c6fb10a7727 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/DeleteTagCommandTest.java @@ -0,0 +1,91 @@ +package seedu.address.logic.commands; + +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.testutil.TypicalIndexes.INDEX_FIRST_TAG; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_TAG; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.Person; +import seedu.address.model.tag.Tag; + + +/** + * Contains integration tests (interaction with the Model) and unit tests for + * {@code DeleteCommand}. + */ +public class DeleteTagCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void execute_validIndexUnfilteredList_success() { + Tag tagToDelete = model.getTagList().get(INDEX_FIRST_TAG.getZeroBased()); + DeleteTagCommand deleteTagCommand = new DeleteTagCommand(INDEX_FIRST_TAG); + + String expectedMessage = String.format(DeleteTagCommand.MESSAGE_DELETE_TAG_SUCCESS, tagToDelete); + + ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + // delete tag + expectedModel.deleteTag(tagToDelete); + // delete tag from each person + for (Person currPerson : expectedModel.getAddressBook().getPersonList()) { + Set tempTags = currPerson.getTags(); + Set tagCopy = new HashSet<>(tempTags); + tagCopy.removeIf(t -> t.isSameTag(tagToDelete)); + Person newPerson = new Person(currPerson.getName(), currPerson.getPhone(), + currPerson.getEmail(), currPerson.getAddress(), tagCopy); + expectedModel.setPerson(currPerson, newPerson); + } + assertCommandSuccess(deleteTagCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidIndexUnfilteredList_throwsCommandException() { + Index outOfBoundIndex = Index.fromOneBased(model.getTagList().size() + 1); + DeleteTagCommand deleteTagCommand = new DeleteTagCommand(outOfBoundIndex); + + assertCommandFailure(deleteTagCommand, model, Messages.MESSAGE_INVALID_TAG_DISPLAYED_INDEX); + } + + @Test + public void equals() { + DeleteTagCommand deleteFirstTagCommand = new DeleteTagCommand(INDEX_FIRST_TAG); + DeleteTagCommand deleteSecondTagCommand = new DeleteTagCommand(INDEX_SECOND_TAG); + + // same object -> returns true + assertTrue(deleteFirstTagCommand.equals(deleteFirstTagCommand)); + + // same values -> returns true + DeleteTagCommand deleteFirstTagCommandCopy = new DeleteTagCommand(INDEX_FIRST_TAG); + assertTrue(deleteFirstTagCommand.equals(deleteFirstTagCommandCopy)); + + // different types -> returns false + assertFalse(deleteFirstTagCommand.equals(1)); + + // null -> returns false + assertFalse(deleteFirstTagCommand.equals(null)); + + // different tag -> returns false + assertFalse(deleteFirstTagCommand.equals(deleteSecondTagCommand)); + } + + /** + * Updates {@code model}'s filtered list to show no one. + */ + private void showNoTag(Model model) { + assertTrue(model.getTagList().isEmpty()); + } +} diff --git a/src/test/java/seedu/address/logic/commands/ListTagCommandTest.java b/src/test/java/seedu/address/logic/commands/ListTagCommandTest.java new file mode 100644 index 00000000000..3d0409fa054 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/ListTagCommandTest.java @@ -0,0 +1,41 @@ +package seedu.address.logic.commands; + +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.List; + +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; +import seedu.address.model.tag.Tag; + +/** + * Contains integration tests (interaction with the Model) and unit tests for ListTagCommand. + */ +public class ListTagCommandTest { + + 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() { + // get success message in String + List tags = expectedModel.getTagList(); + StringBuilder result = new StringBuilder(ListTagCommand.MESSAGE_SUCCESS); + for (Tag tag : tags) { + result.append(" ").append(tag.getTagName()); + } + result.append(" ]"); + assertCommandSuccess(new ListTagCommand(), model, result.toString(), expectedModel); + } +} diff --git a/src/test/java/seedu/address/logic/parser/AddTagCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddTagCommandParserTest.java new file mode 100644 index 00000000000..64f553877e1 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/AddTagCommandParserTest.java @@ -0,0 +1,60 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC; +import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY; +import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE; +import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND; +import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.AddTagCommand; +import seedu.address.model.tag.Tag; +import seedu.address.testutil.TagBuilder; + +public class AddTagCommandParserTest { + private AddTagCommandParser parser = new AddTagCommandParser(); + + @Test + public void parse_allFieldsPresent_success() { + Tag expectedTag = new TagBuilder().withTagName(VALID_TAG_FRIEND).build(); + + // whitespace only preamble + assertParseSuccess(parser, PREAMBLE_WHITESPACE + TAG_DESC_FRIEND, + new AddTagCommand(expectedTag)); + + // multiple tags - last tag accepted + assertParseSuccess(parser, TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + new AddTagCommand(expectedTag)); + + // multiple tags with one of them invalid - last tag accepted + assertParseSuccess(parser, INVALID_TAG_DESC + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, + new AddTagCommand(expectedTag)); + } + + @Test + public void parse_compulsoryFieldMissing_failure() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTagCommand.MESSAGE_USAGE); + + // missing tag prefix + assertParseFailure(parser, VALID_TAG_FRIEND, expectedMessage); + } + + @Test + public void parse_invalidValue_failure() { + // invalid tag + assertParseFailure(parser, INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); + + // multiple invalids - first invalid will be reported + assertParseFailure(parser, INVALID_TAG_DESC + TAG_DESC_FRIEND + INVALID_TAG_DESC, + Tag.MESSAGE_CONSTRAINTS); + + // non-empty preamble + assertParseFailure(parser, PREAMBLE_NON_EMPTY + TAG_DESC_FRIEND, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTagCommand.MESSAGE_USAGE)); + } +} diff --git a/src/test/java/seedu/address/logic/parser/DeleteTagCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteTagCommandParserTest.java new file mode 100644 index 00000000000..ea1dd9bee12 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/DeleteTagCommandParserTest.java @@ -0,0 +1,33 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.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_TAG; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.DeleteTagCommand; + +/** + * As we are only doing white-box testing, our test cases do not cover path variations + * outside of the DeleteTagCommand code. For example, inputs "1" and "1 abc" take the + * same path through the DeleteTagCommand, 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 DeleteTagCommandParserTest { + + private DeleteTagCommandParser parser = new DeleteTagCommandParser(); + + @Test + public void parse_validArgs_returnsDeleteCommand() { + assertParseSuccess(parser, "1", new DeleteTagCommand(INDEX_FIRST_TAG)); + } + + @Test + public void parse_invalidArgs_throwsParseException() { + assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, + DeleteTagCommand.MESSAGE_USAGE)); + } +} diff --git a/src/test/java/seedu/address/model/tag/UniqueTagListTest.java b/src/test/java/seedu/address/model/tag/UniqueTagListTest.java new file mode 100644 index 00000000000..1189015b45a --- /dev/null +++ b/src/test/java/seedu/address/model/tag/UniqueTagListTest.java @@ -0,0 +1,167 @@ +package seedu.address.model.tag; + +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.TypicalTags.FRIEND; +import static seedu.address.testutil.TypicalTags.OWEMONEY; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.tag.exceptions.DuplicateTagException; +import seedu.address.model.tag.exceptions.TagNotFoundException; +import seedu.address.testutil.TagBuilder; + +public class UniqueTagListTest { + + private final UniqueTagList uniqueTagList = new UniqueTagList(); + + @Test + public void contains_nullTag_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.contains(null)); + } + + @Test + public void contains_tagNotInList_returnsFalse() { + assertFalse(uniqueTagList.contains(FRIEND)); + } + + @Test + public void contains_tagInList_returnsTrue() { + uniqueTagList.add(FRIEND); + assertTrue(uniqueTagList.contains(FRIEND)); + } + + @Test + public void contains_tagWithSameIdentityFieldsInList_returnsTrue() { + uniqueTagList.add(FRIEND); + Tag editedFriend = new TagBuilder().withTagName(FRIEND.getTagName()).build(); + assertTrue(uniqueTagList.contains(editedFriend)); + } + + @Test + public void add_nullTag_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.add(null)); + } + + @Test + public void add_duplicateTag_throwsDuplicateTagException() { + uniqueTagList.add(FRIEND); + assertThrows(DuplicateTagException.class, () -> uniqueTagList.add(FRIEND)); + } + + @Test + public void setTag_nullTargetTag_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.setTag(null, FRIEND)); + } + + @Test + public void setTag_nullEditedTag_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.setTag(FRIEND, null)); + } + + @Test + public void setTag_targetTagNotInList_throwsTagNotFoundException() { + assertThrows(TagNotFoundException.class, () -> uniqueTagList.setTag(FRIEND, FRIEND)); + } + + @Test + public void setTag_editedTagIsSameTag_success() { + uniqueTagList.add(FRIEND); + uniqueTagList.setTag(FRIEND, FRIEND); + UniqueTagList expectedUniqueTagList = new UniqueTagList(); + expectedUniqueTagList.add(FRIEND); + assertEquals(expectedUniqueTagList, uniqueTagList); + } + + @Test + public void setTag_editedTagHasSameIdentity_success() { + uniqueTagList.add(FRIEND); + Tag editedAlice = new TagBuilder(FRIEND).withTagName(FRIEND.getTagName()) + .build(); + uniqueTagList.setTag(FRIEND, editedAlice); + UniqueTagList expectedUniqueTagList = new UniqueTagList(); + expectedUniqueTagList.add(editedAlice); + assertEquals(expectedUniqueTagList, uniqueTagList); + } + + @Test + public void setTag_editedTagHasDifferentIdentity_success() { + uniqueTagList.add(FRIEND); + uniqueTagList.setTag(FRIEND, OWEMONEY); + UniqueTagList expectedUniqueTagList = new UniqueTagList(); + expectedUniqueTagList.add(OWEMONEY); + assertEquals(expectedUniqueTagList, uniqueTagList); + } + + @Test + public void setTag_editedTagHasNonUniqueIdentity_throwsDuplicateTagException() { + uniqueTagList.add(FRIEND); + uniqueTagList.add(OWEMONEY); + assertThrows(DuplicateTagException.class, () -> uniqueTagList.setTag(FRIEND, OWEMONEY)); + } + + @Test + public void remove_nullTag_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.remove(null)); + } + + @Test + public void remove_tagDoesNotExist_throwsTagNotFoundException() { + assertThrows(TagNotFoundException.class, () -> uniqueTagList.remove(FRIEND)); + } + + @Test + public void remove_existingTag_removesTag() { + uniqueTagList.add(FRIEND); + uniqueTagList.remove(FRIEND); + UniqueTagList expectedUniqueTagList = new UniqueTagList(); + assertEquals(expectedUniqueTagList, uniqueTagList); + } + + @Test + public void setTags_nullUniqueTagList_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.setTags((UniqueTagList) null)); + } + + @Test + public void setTags_uniqueTagList_replacesOwnListWithProvidedUniqueTagList() { + uniqueTagList.add(FRIEND); + UniqueTagList expectedUniqueTagList = new UniqueTagList(); + expectedUniqueTagList.add(OWEMONEY); + uniqueTagList.setTags(expectedUniqueTagList); + assertEquals(expectedUniqueTagList, uniqueTagList); + } + + @Test + public void setTags_nullList_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> uniqueTagList.setTags((List) null)); + } + + @Test + public void setTags_list_replacesOwnListWithProvidedList() { + uniqueTagList.add(FRIEND); + List tagList = Collections.singletonList(OWEMONEY); + uniqueTagList.setTags(tagList); + UniqueTagList expectedUniqueTagList = new UniqueTagList(); + expectedUniqueTagList.add(OWEMONEY); + assertEquals(expectedUniqueTagList, uniqueTagList); + } + + @Test + public void setTags_listWithDuplicateTags_throwsDuplicateTagException() { + List listWithDuplicateTags = Arrays.asList(FRIEND, FRIEND); + assertThrows(DuplicateTagException.class, () -> uniqueTagList.setTags(listWithDuplicateTags)); + } + + @Test + public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() { + assertThrows(UnsupportedOperationException.class, () -> + uniqueTagList.asUnmodifiableObservableList().remove(0)); + } +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTagTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTagTest.java new file mode 100644 index 00000000000..a84aeece84e --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdaptedTagTest.java @@ -0,0 +1,27 @@ +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalTags.FRIEND; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; + +public class JsonAdaptedTagTest { + + private static final String INVALID_TAG = "#friend"; + + @Test + public void toModelType_validTagDetails_returnsTag() throws Exception { + JsonAdaptedTag tag = new JsonAdaptedTag(FRIEND); + assertEquals(FRIEND, tag.toModelType()); + } + + @Test + public void toModelType_invalidTags_throwsIllegalValueException() { + JsonAdaptedTag tag = new JsonAdaptedTag(INVALID_TAG); + assertThrows(IllegalValueException.class, tag::toModelType); + } + +} diff --git a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java index 188c9058d20..b041f26d636 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java @@ -11,6 +11,8 @@ import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.commons.util.JsonUtil; import seedu.address.model.AddressBook; +import seedu.address.model.person.Person; +import seedu.address.model.tag.Tag; import seedu.address.testutil.TypicalPersons; public class JsonSerializableAddressBookTest { @@ -25,6 +27,13 @@ public void toModelType_typicalPersonsFile_success() throws Exception { JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE, JsonSerializableAddressBook.class).get(); AddressBook addressBookFromFile = dataFromFile.toModelType(); + for (Person eachPerson :addressBookFromFile.getPersonList()) { + for (Tag eachTag: eachPerson.getTags()) { + if (!addressBookFromFile.hasTag(eachTag)) { + addressBookFromFile.addTag(eachTag); + } + } + } AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook(); assertEquals(addressBookFromFile, typicalPersonsAddressBook); } diff --git a/src/test/java/seedu/address/testutil/TagBuilder.java b/src/test/java/seedu/address/testutil/TagBuilder.java new file mode 100644 index 00000000000..2c6fa55bb6a --- /dev/null +++ b/src/test/java/seedu/address/testutil/TagBuilder.java @@ -0,0 +1,35 @@ +package seedu.address.testutil; + +import seedu.address.model.tag.Tag; + +public class TagBuilder { + + public static final String DEFAULT_TAG_NAME = "friend"; + private Tag tag; + + /** + * Creates a {@code TagBuilder} with the default details. + */ + public TagBuilder() { + tag = new Tag(DEFAULT_TAG_NAME); + } + + /** + * Initializes the TagBuilder with the data of {@code tagToCopy}. + */ + public TagBuilder(Tag tagToCopy) { + tag = tagToCopy; + } + + /** + * Sets the {@code TagName} of the {@code Tag} that we are building. + */ + public TagBuilder withTagName(String tagName) { + this.tag = new Tag(tagName); + return this; + } + + public Tag build() { + return tag; + } +} diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/seedu/address/testutil/TypicalIndexes.java index 1e613937657..fb7ea3c0024 100644 --- a/src/test/java/seedu/address/testutil/TypicalIndexes.java +++ b/src/test/java/seedu/address/testutil/TypicalIndexes.java @@ -9,4 +9,7 @@ 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_TAG = Index.fromOneBased(1); + public static final Index INDEX_SECOND_TAG = Index.fromOneBased(2); + public static final Index INDEX_THIRD_TAG = Index.fromOneBased(3); } diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java index fec76fb7129..74507371cd5 100644 --- a/src/test/java/seedu/address/testutil/TypicalPersons.java +++ b/src/test/java/seedu/address/testutil/TypicalPersons.java @@ -17,6 +17,7 @@ import seedu.address.model.AddressBook; import seedu.address.model.person.Person; +import seedu.address.model.tag.Tag; /** * A utility class containing a list of {@code Person} objects to be used in tests. @@ -60,12 +61,17 @@ public class TypicalPersons { private TypicalPersons() {} // prevents instantiation /** - * Returns an {@code AddressBook} with all the typical persons. + * Returns an {@code AddressBook} with all the typical persons and tags. */ public static AddressBook getTypicalAddressBook() { AddressBook ab = new AddressBook(); for (Person person : getTypicalPersons()) { ab.addPerson(person); + for (Tag tag : person.getTags()) { + if (!ab.hasTag(tag)) { + ab.addTag(tag); + } + } } return ab; } diff --git a/src/test/java/seedu/address/testutil/TypicalTags.java b/src/test/java/seedu/address/testutil/TypicalTags.java new file mode 100644 index 00000000000..8b389dcbab6 --- /dev/null +++ b/src/test/java/seedu/address/testutil/TypicalTags.java @@ -0,0 +1,8 @@ +package seedu.address.testutil; + +import seedu.address.model.tag.Tag; + +public class TypicalTags { + public static final Tag FRIEND = new TagBuilder().withTagName("friends").build(); + public static final Tag OWEMONEY = new TagBuilder().withTagName("owesMoney").build(); +}