-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Conversation
v1@yamgent submitted v1 for review.
Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/1/head:BRANCHNAME where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[1/4] I've modified the 1st 2 paragraphs of your commit message to fit our standard structure more.
AddressBook#updatePerson() does not update the list of tags in the
address book correctly, as tags that are no longer used by anyone after
the update remains in the list.
This is a buggy behavior as the list of tags is expected to only
contain tags that are used persons in the address book.
Let's modify AddressBook#updatePerson() to refresh the tags list after
updating the person, so that any unused tags are purged.
} | ||
|
||
/** | ||
* Returns whether any {@code Person} in this {@code AddressBook} is still using {@code tag}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private void removeUnusedTags() { | ||
Set<Tag> tagsInUse = new HashSet<Tag>(); | ||
|
||
tags.forEach(tag -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use enhanced for-loop here, since you are doing so as well for the method isTagUsed
, so we should standardise it (since there's no additional benefit compared to using forEach
over enhanced for-loop.
Alternatively, you can update the UniquePersonList
& UniqueTagList
to return a Stream<Person>
and Stream<Tag>
respectively. That will shorten these methods here quite substantially.
@@ -112,6 +112,35 @@ public void updatePerson(ReadOnlyPerson target, ReadOnlyPerson editedReadOnlyPer | |||
// This can cause the tags master list to have additional tags that are not tagged to any person | |||
// in the person list. | |||
persons.setPerson(target, editedPerson); | |||
removeUnusedTags(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you spotted a bug here, this should actually be fixed in master right? Wanna raise an issue for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already raised in #753 actually.
This commit is a temporary fix, it is not ideal because the complexity will become O(n^2). An overhaul of the tag list is probably required.
@@ -69,6 +72,16 @@ public void getTagList_modifyList_throwsUnsupportedOperationException() { | |||
addressBook.getTagList().remove(0); | |||
} | |||
|
|||
@Test | |||
public void updatePerson_detailsChanged_personsAndTagsListUpdated() throws Exception { | |||
addressBook.addPerson(BOB); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we should use AddressBookBuilder()
to create an AddressBook
with BOB
. Then we call addressBook.updatePerson(BOB, AMY);
afterwards.
This is so that we don't need to rely on AddressBook#addPerson(Person)
to be working correctly, since this method only tests for updatePerson(Person, Person)
* Removes all {@code Tag}s that are not used by any {@code Person} in this {@code AddressBook}. | ||
*/ | ||
private void removeUnusedTags() { | ||
Set<Tag> tagsInUse = new HashSet<Tag>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, the word Tag
in new HashSet<Tag>
is unnecessary, as reported by my trustworthy IntelliJ :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[2/4] Should the tests be more vigorous by including the throwing of PersonNotFoundException
?
@Test | ||
public void removeTagFromPerson_tagUsedByMultiplePersons_personUpdated() throws Exception { | ||
addressBook.addPerson(AMY); | ||
addressBook.addPerson(BOB); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as mentioned above.
@@ -191,6 +191,22 @@ public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { | |||
tags.add(t); | |||
} | |||
|
|||
/** | |||
* Removes {@code tag} from {@code person} in this {@code AddressBook}. | |||
* @throws DuplicatePersonException if removing the tag causes the {@code person} to be equivalent to another |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of equals
doesn't allow for this exception to happen actually, since it doesn't consider equality of tags. As such, perhaps we shouldn't throw this exception, but do a try-catch
followed with throw new AssertionError()
?
I'm not too picky about this though, @damithc what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[3/4]
/** | ||
* Removes {@code tag} in this {@code AddressBook}. | ||
*/ | ||
public void removeTag(Tag tag) throws DuplicatePersonException, PersonNotFoundException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this method shouldn't be throwing both Exceptions, we should do a try-catch
followed by throw new AssertionError()
.
|
||
AddressBook expectedAddressBook = new AddressBookBuilder().withPerson(AMY).withPerson(BOB).build(); | ||
|
||
assertEquals(addressBook, expectedAddressBook); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong order of assertEquals
:P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[4/4]
public void deleteTag(Tag tag) throws PersonNotFoundException, DuplicatePersonException { | ||
for (ReadOnlyPerson person : addressBook.getPersonList()) { | ||
addressBook.removeTagFromPerson(tag, person); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just call addressBook.removeTag(tag);
right? :P That way, you can make removeTagFromPerson
private instead.
ModelManager modelManager = new ModelManager(addressBook, userPrefs); | ||
modelManager.deleteTag(new Tag(VALID_TAG_UNUSED)); | ||
|
||
assertEquals(modelManager, new ModelManager(addressBook, userPrefs)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong ordering of assertEquals
:P
AddressBook expectedAddressBook = new AddressBookBuilder().withPerson(amyWithoutFriendTag) | ||
.withPerson(bobWithoutFriendTag).build(); | ||
|
||
assertEquals(modelManager, new ModelManager(expectedAddressBook, userPrefs)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong ordering of assertEquals
:P
@@ -26,6 +35,34 @@ public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException | |||
modelManager.getFilteredPersonList().remove(0); | |||
} | |||
|
|||
@Test | |||
public void deleteTag_nonExistentTag_sameAddressBook() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should the last segment of this test be named as modelUnchanged
instead?
b313b09
to
b2ad284
Compare
v2@yamgent submitted v2 for review.
(📚 Archive) (📈 Interdiff between v1 and v2) Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/2/head:BRANCHNAME where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[1/4] commit message for 2nd paragraph, sorry I typed wrongly:
This is a buggy behavior as the list of tags is expected to only
contain tags that are used by persons in the address book.
@Test | ||
public void updatePerson_detailsChanged_personsAndTagsListUpdated() throws Exception { | ||
AddressBook addressBookWithBob = new AddressBookBuilder().withPerson(BOB).build(); | ||
addressBookWithBob.updatePerson(BOB, AMY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after the update, this address book is no longer addressBookWithBob
cos it actually stores AMY
. Not sure if this may end up being confusing. I can't think of a better naming though. Maybe addressBookUpdatedToAmy
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[2/4]
try { | ||
updatePerson(person, newPerson); | ||
} catch (DuplicatePersonException dpe) { | ||
throw new AssertionError("Modifying a person's tags only should not result in a duplicate."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add something like "See Person#equals(Object)" for clarity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[3/4] as mentioned #790 (comment), we can make removeTagFromPerson(Tag, ReadOnlyPerson)
private. As such, perhaps a better way is to squash commits 2 and 3 together. I think we don't test private methods in our code base right? So I think we can remove the tests in commit 2.
@@ -116,6 +116,28 @@ public void removeTagFromPerson_tagUsedByMultiplePersons_personUpdated() throws | |||
assertEquals(expectedAddressBook, addressBookWithBobAndAmy); | |||
} | |||
|
|||
@Test | |||
public void removeTag_nonExistentTag_sameAddressBook() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we change sameAddressBook
-> addressBookUnchanged
? Sounds a bit more natural.
bf83718
to
299e83a
Compare
v3@yamgent submitted v3 for review.
(📚 Archive) (📈 Interdiff between v2 and v3) Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/3/head:BRANCHNAME where |
299e83a
to
c398d58
Compare
v4@yamgent submitted v4 for review.
(📚 Archive) (📈 Interdiff between v3 and v4) Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/4/head:BRANCHNAME where |
1b03d80
to
20502f5
Compare
v7@yamgent submitted v7 for review.
(📚 Archive) (📈 Interdiff between v6 and v7) (📈 Range-Diff between v6 and v7) Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/7/head:BRANCHNAME where |
Changelog:
|
|
||
try { | ||
updatePerson(person, newPerson); | ||
} catch (DuplicatePersonException dpe) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DuplicatePersonException
will be made RuntimeException
in #896 tho :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh, I'll say that is a good thing, given the
throw new AssertionError("Modifying a person's tags only should not result in a duplicate. "
+ "See Person#equals(Object).");
below.
for (Person person : persons) { | ||
removeTagFromPerson(tag, person); | ||
} | ||
} catch (PersonNotFoundException pnfe) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we catch PNFE
and DPE
at the same location (in removeTagFromPerson
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it makes sense to handle PNFE
here, because callers of removeTagFromPerson(Tag, Person)
might actually pass in a person
that does not exist in the address book, so it is a valid exception in that sense. However, handling DPE
here would be quite strange since callers are not expected to manipulate Person
s themselves, so removeTagFromPerson(Tag, Person)
should deal with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nvm I read your comments wrongly, will update it :P.
2b094b4
to
04fa653
Compare
v8@yamgent submitted v8 for review.
(📚 Archive) (📈 Interdiff between v7 and v8) (📈 Range-Diff between v7 and v8) Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/8/head:BRANCHNAME where |
Conflicts Resolution (Round 2):
Update:
|
|
||
try { | ||
updatePerson(person, newPerson); | ||
} catch (DuplicatePersonException dpe) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this can be removed?
throw new AssertionError("Modifying a person's tags only should not result in a duplicate. " | ||
+ "See Person#equals(Object)."); | ||
} catch (PersonNotFoundException pnfe) { | ||
throw new AssertionError("Original person must be obtained from the address book."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this can be removed?
*/ | ||
public void removeTag(Tag tag) { | ||
for (Person person : persons) { | ||
removeTagFromPerson(tag, person); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do foreach
here instead?
We want to be able to delete a particular Tag from our AddressBook entirely. Let's add AddressBook#removeTag(Tag). An alternative would be to move the logic to a new method ModelManager#deleteTag(Tag). However, it violates SRP as the ModelManager should not be concerned with the details of how the tags are removed from the AddressBook.
The Model API does not expose a way to delete a particular Tag entirely from the AddressBook (i.e. removing the Tag from all Persons and purging the Tag in the AddressBook's tag list). Let's add Model#deleteTag(Tag).
04fa653
to
f798470
Compare
v9@yamgent submitted v9 for review.
(📚 Archive) (📈 Interdiff between v8 and v9) (📈 Range-Diff between v8 and v9) Checkout this PR version locallygit fetch https://github.com/se-edu/addressbook-level4.git refs/pr/790/9/head:BRANCHNAME where |
Part of #784. Fixed the
deleteTag(Tag)
exception by overhauling the design. Also added test.Proposed commit message:
Note: For demo purpose, don't merge this to master!