From cdee9199c8ab6a1646ef9fce6930ce41f1b1b25b Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Fri, 22 Feb 2019 21:07:16 +0100 Subject: [PATCH] Replace Sone change detector with simple comparison helper --- .../java/net/pterodactylus/sone/core/Core.java | 67 +++++------- .../sone/core/SoneChangeDetector.java | 112 --------------------- .../pterodactylus/sone/core/SoneChangeCollector.kt | 49 --------- .../net/pterodactylus/sone/core/SoneComparison.kt | 12 +++ .../sone/core/UpdatedSoneProcessor.kt | 49 ++++----- .../sone/core/SoneChangeDetectorTest.java | 106 ------------------- .../sone/core/SoneChangeCollectorTest.kt | 78 -------------- .../pterodactylus/sone/core/SoneComparisonTest.kt | 50 +++++++++ 8 files changed, 112 insertions(+), 411 deletions(-) delete mode 100644 src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java delete mode 100644 src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt create mode 100644 src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt delete mode 100644 src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java delete mode 100644 src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt create mode 100644 src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 4319d8b..8e20176 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -48,8 +48,6 @@ import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound; import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound; import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound; import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound; -import net.pterodactylus.sone.core.SoneChangeDetector.PostProcessor; -import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor; import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent; import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; import net.pterodactylus.sone.core.event.MarkPostKnownEvent; @@ -851,48 +849,33 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } } - private List collectEventsForChangesInSone(Sone oldSone, - final Sone newSone) { - final List events = new ArrayList(); - SoneChangeDetector soneChangeDetector = new SoneChangeDetector( - oldSone); - soneChangeDetector.onNewPosts(new PostProcessor() { - @Override - public void processPost(Post post) { - if (post.getSone().equals(newSone)) { - post.setKnown(true); - } else if (post.getTime() < database.getFollowingTime(newSone.getId())) { - post.setKnown(true); - } else if (!post.isKnown()) { - events.add(new NewPostFoundEvent(post)); - } - } - }); - soneChangeDetector.onRemovedPosts(new PostProcessor() { - @Override - public void processPost(Post post) { - events.add(new PostRemovedEvent(post)); - } - }); - soneChangeDetector.onNewPostReplies(new PostReplyProcessor() { - @Override - public void processPostReply(PostReply postReply) { - if (postReply.getSone().equals(newSone)) { - postReply.setKnown(true); - } else if (postReply.getTime() < database.getFollowingTime(newSone.getId())) { - postReply.setKnown(true); - } else if (!postReply.isKnown()) { - events.add(new NewPostReplyFoundEvent(postReply)); - } + private List collectEventsForChangesInSone(Sone oldSone, Sone newSone) { + List events = new ArrayList<>(); + SoneComparison soneComparison = new SoneComparison(oldSone, newSone); + for (Post newPost : soneComparison.getNewPosts()) { + if (newPost.getSone().equals(newSone)) { + newPost.setKnown(true); + } else if (newPost.getTime() < database.getFollowingTime(newSone.getId())) { + newPost.setKnown(true); + } else if (!newPost.isKnown()) { + events.add(new NewPostFoundEvent(newPost)); } - }); - soneChangeDetector.onRemovedPostReplies(new PostReplyProcessor() { - @Override - public void processPostReply(PostReply postReply) { - events.add(new PostReplyRemovedEvent(postReply)); + } + for (Post post : soneComparison.getRemovedPosts()) { + events.add(new PostRemovedEvent(post)); + } + for (PostReply postReply : soneComparison.getNewPostReplies()) { + if (postReply.getSone().equals(newSone)) { + postReply.setKnown(true); + } else if (postReply.getTime() < database.getFollowingTime(newSone.getId())) { + postReply.setKnown(true); + } else if (!postReply.isKnown()) { + events.add(new NewPostReplyFoundEvent(postReply)); } - }); - soneChangeDetector.detectChanges(newSone); + } + for (PostReply postReply : soneComparison.getRemovedPostReplies()) { + events.add(new PostReplyRemovedEvent(postReply)); + } return events; } diff --git a/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java b/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java deleted file mode 100644 index 7dd882d..0000000 --- a/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java +++ /dev/null @@ -1,112 +0,0 @@ -package net.pterodactylus.sone.core; - -import static com.google.common.base.Optional.absent; -import static com.google.common.base.Optional.fromNullable; -import static com.google.common.collect.FluentIterable.from; - -import java.util.Collection; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; - -/** - * Compares the contents of two {@link Sone}s and fires events for new and - * removed elements. - */ -public class SoneChangeDetector { - - private final Sone oldSone; - private Optional newPostProcessor = absent(); - private Optional removedPostProcessor = absent(); - private Optional newPostReplyProcessor = absent(); - private Optional removedPostReplyProcessor = absent(); - - public SoneChangeDetector(Sone oldSone) { - this.oldSone = oldSone; - } - - public void onNewPosts(PostProcessor newPostProcessor) { - this.newPostProcessor = fromNullable(newPostProcessor); - } - - public void onRemovedPosts(PostProcessor removedPostProcessor) { - this.removedPostProcessor = fromNullable(removedPostProcessor); - } - - public void onNewPostReplies(PostReplyProcessor newPostReplyProcessor) { - this.newPostReplyProcessor = fromNullable(newPostReplyProcessor); - } - - public void onRemovedPostReplies( - PostReplyProcessor removedPostReplyProcessor) { - this.removedPostReplyProcessor = fromNullable(removedPostReplyProcessor); - } - - public void detectChanges(Sone newSone) { - processPosts(from(newSone.getPosts()).filter( - notContainedIn(oldSone.getPosts())), newPostProcessor); - processPosts(from(oldSone.getPosts()).filter( - notContainedIn(newSone.getPosts())), removedPostProcessor); - processPostReplies(from(newSone.getReplies()).filter( - notContainedIn(oldSone.getReplies())), newPostReplyProcessor); - processPostReplies(from(oldSone.getReplies()).filter( - notContainedIn(newSone.getReplies())), removedPostReplyProcessor); - } - - private void processPostReplies(FluentIterable postReplies, - Optional postReplyProcessor) { - for (PostReply postReply : postReplies) { - notifyPostReplyProcessor(postReplyProcessor, postReply); - } - } - - private void notifyPostReplyProcessor( - Optional postReplyProcessor, - PostReply postReply) { - if (postReplyProcessor.isPresent()) { - postReplyProcessor.get() - .processPostReply(postReply); - } - } - - private void processPosts(FluentIterable posts, - Optional newPostProcessor) { - for (Post post : posts) { - notifyPostProcessor(newPostProcessor, post); - } - } - - private void notifyPostProcessor(Optional postProcessor, - Post newPost) { - if (postProcessor.isPresent()) { - postProcessor.get().processPost(newPost); - } - } - - private Predicate notContainedIn(final Collection posts) { - return new Predicate() { - @Override - public boolean apply(T element) { - return !posts.contains(element); - } - }; - } - - public interface PostProcessor { - - void processPost(Post post); - - } - - public interface PostReplyProcessor { - - void processPostReply(PostReply postReply); - - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt b/src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt deleted file mode 100644 index 609a55f..0000000 --- a/src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt +++ /dev/null @@ -1,49 +0,0 @@ -package net.pterodactylus.sone.core - -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone - -/** - * Wrapper around a [SoneChangeDetector] that can turn changed elements into - * different elements which are then being returned. This can be used to turn - * changed elements into events for further processing. - */ -class SoneChangeCollector(private val oldSone: Sone) { - - private val newPostEventCreators = mutableListOf<(Post) -> Any?>() - private val removedPostEventCreators = mutableListOf<(Post) -> Any?>() - private val newPostReplyEventCreators = mutableListOf<(PostReply) -> Any?>() - private val removedPostReplyEventCreators = mutableListOf<(PostReply) -> Any?>() - - fun onNewPost(postProcessor: (Post) -> Unit) = - newPostEventCreators.add { postProcessor(it).let { null } }.let { this } - - fun newPostEvent(postEventCreator: (Post) -> Any?) = - newPostEventCreators.add(postEventCreator).let { this } - - fun onNewPostReply(postReplyProcessor: (PostReply) -> Unit) = - newPostReplyEventCreators.add { postReplyProcessor(it).let { null } }.let { this } - - fun newPostReplyEvent(postReplyEventCreator: (PostReply) -> Any?) = - newPostReplyEventCreators.add(postReplyEventCreator).let { this } - - fun removedPostEvent(postEventCreator: (Post) -> Any?) = - removedPostEventCreators.add(postEventCreator).let { this } - - fun onRemovedPostReply(postReplyEventCreator: (PostReply) -> Any?) = - removedPostReplyEventCreators.add(postReplyEventCreator).let { this } - - fun detectChanges(newSone: Sone): List { - val events = mutableListOf() - SoneChangeDetector(oldSone).apply { - onNewPosts { post -> newPostEventCreators.mapNotNull { it(post) }.forEach { events.add(it) } } - onRemovedPosts { post -> removedPostEventCreators.mapNotNull { it(post) }.forEach { events.add(it) } } - onNewPostReplies { reply -> newPostReplyEventCreators.mapNotNull { it(reply) }.forEach { events.add(it) } } - onRemovedPostReplies { reply -> removedPostReplyEventCreators.mapNotNull { it(reply) }.forEach { events.add(it) } } - detectChanges(newSone) - } - return events - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt b/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt new file mode 100644 index 0000000..9a67f80 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt @@ -0,0 +1,12 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.data.* + +class SoneComparison(private val oldSone: Sone, private val newSone: Sone) { + + val newPosts: Collection get() = newSone.posts - oldSone.posts + val removedPosts: Collection get() = oldSone.posts - newSone.posts + val newPostReplies: Collection get() = newSone.replies - oldSone.replies + val removedPostReplies: Collection get() = oldSone.replies - newSone.replies + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt b/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt index 580f227..ebaa3c8 100644 --- a/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt +++ b/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt @@ -1,16 +1,13 @@ package net.pterodactylus.sone.core -import com.google.common.eventbus.EventBus -import com.google.inject.ImplementedBy -import net.pterodactylus.sone.core.event.NewPostFoundEvent -import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent -import net.pterodactylus.sone.core.event.PostRemovedEvent -import net.pterodactylus.sone.core.event.PostReplyRemovedEvent -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.data.Sone.SoneStatus -import net.pterodactylus.sone.database.Database -import net.pterodactylus.sone.utils.ifFalse -import net.pterodactylus.util.logging.Logging +import com.google.common.eventbus.* +import com.google.inject.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Sone.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.util.logging.* import javax.inject.Inject /** @@ -35,9 +32,23 @@ abstract class BasicUpdateSoneProcessor(private val database: Database, private logger.fine("Downloaded Sone $sone can not update stored Sone $storedSone.") return } - collectEventsForChanges(storedSone, sone) - .also { database.storeSone(sone) } - .forEach(eventBus::post) + + SoneComparison(storedSone, sone).apply { + newPosts + .onEach { post -> if (post.time <= sone.followingTime) post.isKnown = true } + .mapNotNull { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } } + .forEach(eventBus::post) + removedPosts + .map { PostRemovedEvent(it) } + .forEach(eventBus::post) + newPostReplies + .onEach { postReply -> if (postReply.time <= sone.followingTime) postReply.isKnown = true } + .mapNotNull { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } } + .forEach(eventBus::post) + removedPostReplies + .map { PostReplyRemovedEvent(it) } + .forEach(eventBus::post) + } sone.options = storedSone.options sone.isKnown = storedSone.isKnown sone.status = if (sone.time != 0L) SoneStatus.idle else SoneStatus.unknown @@ -47,16 +58,6 @@ abstract class BasicUpdateSoneProcessor(private val database: Database, private private val Sone.followingTime get() = database.getFollowingTime(id) ?: 0 - private fun collectEventsForChanges(oldSone: Sone, newSone: Sone): List = - SoneChangeCollector(oldSone) - .onNewPost { post -> if (post.time <= newSone.followingTime) post.isKnown = true } - .newPostEvent { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } } - .removedPostEvent { PostRemovedEvent(it) } - .onNewPostReply { postReply -> if (postReply.time <= newSone.followingTime) postReply.isKnown = true } - .newPostReplyEvent { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } } - .onRemovedPostReply { PostReplyRemovedEvent(it) } - .detectChanges(newSone) - } class DefaultUpdateSoneProcessor @Inject constructor(database: Database, eventBus: EventBus) : diff --git a/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java b/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java deleted file mode 100644 index eaa9637..0000000 --- a/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package net.pterodactylus.sone.core; - -import static java.util.Arrays.asList; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashSet; - -import net.pterodactylus.sone.core.SoneChangeDetector.PostProcessor; -import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor; -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link SoneChangeDetector}. - */ -public class SoneChangeDetectorTest { - - private final Sone oldSone = mock(Sone.class); - private final Sone newSone = mock(Sone.class); - private final SoneChangeDetector soneChangeDetector = - new SoneChangeDetector(oldSone); - private final Post oldPost = mock(Post.class); - private final Post removedPost = mock(Post.class); - private final Post newPost = mock(Post.class); - private final PostProcessor newPostProcessor = mock(PostProcessor.class); - private final PostProcessor removedPostProcessor = - mock(PostProcessor.class); - private final PostReply oldPostReply = mock(PostReply.class); - private final PostReply removedPostReply = mock(PostReply.class); - private final PostReply newPostReply = mock(PostReply.class); - private final PostReplyProcessor newPostReplyProcessor = - mock(PostReplyProcessor.class); - private final PostReplyProcessor removedPostReplyProcessor = - mock(PostReplyProcessor.class); - - @Before - public void setupPosts() { - when(oldSone.getPosts()).thenReturn(asList(oldPost, removedPost)); - when(newSone.getPosts()).thenReturn(asList(oldPost, newPost)); - } - - @Before - public void setupPostProcessors() { - soneChangeDetector.onNewPosts(newPostProcessor); - soneChangeDetector.onRemovedPosts(removedPostProcessor); - } - - @Before - public void setupPostReplies() { - when(oldSone.getReplies()).thenReturn( - new HashSet( - asList(oldPostReply, removedPostReply))); - when(newSone.getReplies()).thenReturn( - new HashSet(asList(oldPostReply, newPostReply))); - } - - @Before - public void setupPostReplyProcessors() { - soneChangeDetector.onNewPostReplies(newPostReplyProcessor); - soneChangeDetector.onRemovedPostReplies(removedPostReplyProcessor); - } - - @Test - public void changeDetectorDetectsChanges() { - soneChangeDetector.detectChanges(newSone); - - verify(newPostProcessor).processPost(newPost); - verify(newPostProcessor, never()).processPost(oldPost); - verify(newPostProcessor, never()).processPost(removedPost); - verify(removedPostProcessor).processPost(removedPost); - verify(removedPostProcessor, never()).processPost(oldPost); - verify(removedPostProcessor, never()).processPost(newPost); - - verify(newPostReplyProcessor).processPostReply(newPostReply); - verify(newPostReplyProcessor, never()).processPostReply(oldPostReply); - verify(newPostReplyProcessor, never()).processPostReply( - removedPostReply); - verify(removedPostReplyProcessor).processPostReply(removedPostReply); - verify(removedPostReplyProcessor, never()).processPostReply( - oldPostReply); - verify(removedPostReplyProcessor, never()).processPostReply( - newPostReply); - } - - @Test - public void changeDetectorDoesNotNotifyAnyProcessorIfProcessorsUnset() { - soneChangeDetector.onNewPosts(null); - soneChangeDetector.onRemovedPosts(null); - soneChangeDetector.onNewPostReplies(null); - soneChangeDetector.onRemovedPostReplies(null); - soneChangeDetector.detectChanges(newSone); - verify(newPostProcessor, never()).processPost(any(Post.class)); - verify(removedPostProcessor, never()).processPost(any(Post.class)); - verify(newPostReplyProcessor, never()).processPostReply(any(PostReply.class)); - verify(removedPostReplyProcessor, never()).processPostReply(any(PostReply.class)); - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt deleted file mode 100644 index 3b82b49..0000000 --- a/src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -package net.pterodactylus.sone.core - -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.containsInAnyOrder -import org.hamcrest.Matchers.emptyIterable -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import java.util.concurrent.atomic.AtomicInteger - -/** - * Unit test for [SoneChangeCollectorTest]. - */ -class SoneChangeCollectorTest { - - private val oldSone = mock() - private val newSone = mock() - private val changeCollector = SoneChangeCollector(oldSone) - - @Test - fun `new posts are correctly turned into events`() { - val posts = listOf(mock(), mock(), mock()) - whenever(newSone.posts).thenReturn(posts) - changeCollector.newPostEvent { it.takeIf { it != posts[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(posts[0], posts[2])) - } - - @Test - fun `actions can be performed on new post without being returned`() { - val posts = listOf(mock(), mock(), mock()) - val counter = AtomicInteger(0) - whenever(newSone.posts).thenReturn(posts.slice(0..2)) - whenever(oldSone.posts).thenReturn(posts.slice(2..2)) - changeCollector.onNewPost { counter.incrementAndGet() } - assertThat(changeCollector.detectChanges(newSone), emptyIterable()) - assertThat(counter.get(), equalTo(2)) - } - - @Test - fun `removed posts are correctly turned into events`() { - val posts = listOf(mock(), mock(), mock()) - whenever(oldSone.posts).thenReturn(posts) - changeCollector.removedPostEvent { it.takeIf { it != posts[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(posts[0], posts[2])) - } - - @Test - fun `new post replies are correctly turned into events`() { - val postReplies = listOf(mock(), mock(), mock()) - whenever(newSone.replies).thenReturn(postReplies.toSet()) - changeCollector.newPostReplyEvent { it.takeIf { it != postReplies[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(postReplies[0], postReplies[2])) - } - - @Test - fun `actions can be performed on new replies without being returned`() { - val replies = listOf(mock(), mock(), mock()) - val counter = AtomicInteger(0) - whenever(newSone.replies).thenReturn(replies.slice(0..2).toSet()) - whenever(oldSone.replies).thenReturn(replies.slice(2..2).toSet()) - changeCollector.onNewPostReply { counter.incrementAndGet() } - assertThat(changeCollector.detectChanges(newSone), emptyIterable()) - assertThat(counter.get(), equalTo(2)) - } - - @Test - fun `removed post replies are correctly turned into events`() { - val postReplies = listOf(mock(), mock(), mock()) - whenever(oldSone.replies).thenReturn(postReplies.toSet()) - changeCollector.onRemovedPostReply { it.takeIf { it != postReplies[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(postReplies[0], postReplies[2])) - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt new file mode 100644 index 0000000..f79d736 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt @@ -0,0 +1,50 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +class SoneComparsisonTest { + + private val oldSone = mock() + private val newSone = mock() + + private val oldPost = mock() + private val removedPost = mock() + private val newPost = mock() + private val oldPostReply = mock() + private val removedPostReply = mock() + private val newPostReply = mock() + + init { + whenever(oldSone.posts).thenReturn(listOf(oldPost, removedPost)) + whenever(newSone.posts).thenReturn(listOf(oldPost, newPost)) + whenever(oldSone.replies).thenReturn(setOf(oldPostReply, removedPostReply)) + whenever(newSone.replies).thenReturn(setOf(oldPostReply, newPostReply)) + } + + private val soneComparison = SoneComparison(oldSone, newSone) + + @Test + fun `new posts are identified correctly`() { + assertThat(soneComparison.newPosts, contains(newPost)) + } + + @Test + fun `removed posts are identified correctly`() { + assertThat(soneComparison.removedPosts, contains(removedPost)) + } + + @Test + fun `new post replies are identified correctly`() { + assertThat(soneComparison.newPostReplies, contains(newPostReply)) + } + + @Test + fun `removed post replies are identified correctly`() { + assertThat(soneComparison.removedPostReplies, contains(removedPostReply)) + } + +} -- 2.7.4