1 package net.pterodactylus.sone.core
3 import com.google.common.eventbus.EventBus
4 import net.pterodactylus.sone.core.event.NewPostFoundEvent
5 import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent
6 import net.pterodactylus.sone.core.event.PostRemovedEvent
7 import net.pterodactylus.sone.core.event.PostReplyRemovedEvent
8 import net.pterodactylus.sone.data.Post
9 import net.pterodactylus.sone.data.PostReply
10 import net.pterodactylus.sone.data.Sone
11 import net.pterodactylus.sone.database.Database
12 import net.pterodactylus.sone.test.argumentCaptor
13 import net.pterodactylus.sone.test.getInstance
14 import net.pterodactylus.sone.test.isProvidedByMock
15 import net.pterodactylus.sone.test.mock
16 import net.pterodactylus.sone.test.whenever
17 import net.pterodactylus.sone.web.baseInjector
18 import org.hamcrest.MatcherAssert.assertThat
19 import org.hamcrest.Matchers.contains
20 import org.hamcrest.Matchers.containsInAnyOrder
21 import org.hamcrest.Matchers.not
22 import org.hamcrest.Matchers.notNullValue
23 import org.junit.Before
25 import org.mockito.Mockito.any
26 import org.mockito.Mockito.atLeastOnce
27 import org.mockito.Mockito.never
28 import org.mockito.Mockito.times
29 import org.mockito.Mockito.verify
32 * Unit test for all [UpdatedSoneProcessor] implementations.
34 class UpdatedSoneProcessorTest {
36 private val database = mock<Database>()
37 private val eventBus = mock<EventBus>()
38 private val updatedSoneProcessor = DefaultUpdateSoneProcessor(database, eventBus)
39 private val storedSone = mock<Sone>()
40 private val newSone = mock<Sone>()
41 private val posts = listOf(mock<Post>(), mock(), mock())
42 private val postReplies = listOf(mock<PostReply>(), mock(), mock())
44 private val events = argumentCaptor<Any>()
47 fun setupPostsAndReplies() {
48 posts.forEachIndexed { index, post -> whenever(post.time).thenReturn((index + 1) * 1000L + 100) }
49 postReplies.forEachIndexed { index, postReply -> whenever(postReply.time).thenReturn((index + 1) * 1000L + 200) }
54 whenever(storedSone.time).thenReturn(1000L)
55 whenever(storedSone.posts).thenReturn(posts.slice(0..1))
56 whenever(storedSone.replies).thenReturn(postReplies.slice(0..1).toSet())
57 whenever(newSone.id).thenReturn("sone")
58 whenever(newSone.time).thenReturn(2000L)
59 whenever(newSone.posts).thenReturn(posts.slice(1..2))
60 whenever(newSone.replies).thenReturn(postReplies.slice(1..2).toSet())
65 whenever(database.getSone("sone")).thenReturn(storedSone)
66 whenever(database.getFollowingTime("sone")).thenReturn(500L)
70 fun `updated Sone processor emits no event if no stored sone exists`() {
71 whenever(database.getSone("sone")).thenReturn(null)
72 updatedSoneProcessor.updateSone(newSone)
73 verify(eventBus, never()).post(any())
77 fun `updated Sone processor emits no event if new Sone is older than stored Sone`() {
78 whenever(newSone.time).thenReturn(500L)
79 updatedSoneProcessor.updateSone(newSone)
80 verify(eventBus, never()).post(any())
84 fun `updated Sone processor emits correct events when new Sone is newer`() {
85 updatedSoneProcessor.updateSone(newSone)
86 verify(eventBus, times(4)).post(events.capture())
87 assertThat(events.allValues, containsInAnyOrder(
88 NewPostFoundEvent(posts[2]),
89 PostRemovedEvent(posts[0]),
90 NewPostReplyFoundEvent(postReplies[2]),
91 PostReplyRemovedEvent(postReplies[0])
96 fun `updated Sone processor does not mark new post as known if sone was not followed after post`() {
97 updatedSoneProcessor.updateSone(newSone)
98 verify(posts[2], never()).isKnown = true
102 fun `updated Sone processor does not mark new posts as known if Sone is not followed`() {
103 whenever(database.getFollowingTime("sone")).thenReturn(null)
104 updatedSoneProcessor.updateSone(newSone)
105 posts.forEach { verify(it, never()).isKnown = true }
109 fun `updated Sone processor marks new post as known if sone was followed after post`() {
110 whenever(database.getFollowingTime("sone")).thenReturn(3500L)
111 updatedSoneProcessor.updateSone(newSone)
112 verify(posts[2]).isKnown = true
116 fun `updated Sone processor does not emit event for post if it is already known`() {
117 whenever(posts[2].isKnown).thenReturn(true)
118 updatedSoneProcessor.updateSone(newSone)
119 verify(eventBus, atLeastOnce()).post(events.capture())
120 assertThat(events.allValues, not(contains<Any>(NewPostFoundEvent(posts[2]))))
124 fun `updated Sone processor does not mark new reply as known if sone was not followed after reply`() {
125 updatedSoneProcessor.updateSone(newSone)
126 verify(postReplies[2], never()).isKnown = true
130 fun `updated Sone processor marks new reply as known if sone was followed after reply`() {
131 whenever(database.getFollowingTime("sone")).thenReturn(3500L)
132 updatedSoneProcessor.updateSone(newSone)
133 verify(postReplies[2]).isKnown = true
137 fun `updated Sone processor does not emit event for reply if it is already known`() {
138 whenever(postReplies[2].isKnown).thenReturn(true)
139 updatedSoneProcessor.updateSone(newSone)
140 verify(eventBus, atLeastOnce()).post(events.capture())
141 assertThat(events.allValues, not(contains<Any>(NewPostReplyFoundEvent(postReplies[2]))))
145 fun `updated sone processor stores sone in database`() {
146 updatedSoneProcessor.updateSone(newSone)
147 verify(database).storeSone(newSone)
151 fun `default updated Sone processor can be created by dependency injection`() {
152 assertThat(baseInjector.createChildInjector(
153 Database::class.isProvidedByMock()
154 ).getInstance<UpdatedSoneProcessor>(), notNullValue())