9e7c71e68b1bbd90bde9e0f9d29d4bbf80b907a7
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / core / UpdatedSoneProcessorTest.kt
1 package net.pterodactylus.sone.core
2
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
24 import org.junit.Test
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
30
31 /**
32  * Unit test for all [UpdatedSoneProcessor] implementations.
33  */
34 class UpdatedSoneProcessorTest {
35
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())
43
44         private val events = argumentCaptor<Any>()
45
46         @Before
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) }
50         }
51
52         @Before
53         fun setupSones() {
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())
61         }
62
63         @Before
64         fun setupDatabase() {
65                 whenever(database.getSone("sone")).thenReturn(storedSone)
66                 whenever(database.getFollowingTime("sone")).thenReturn(500L)
67         }
68
69         @Test
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())
74         }
75
76         @Test
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())
81         }
82
83         @Test
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])
92                 ))
93         }
94
95         @Test
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
99         }
100
101         @Test
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 }
106         }
107
108         @Test
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
113         }
114
115         @Test
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]))))
121         }
122
123         @Test
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
127         }
128
129         @Test
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
134         }
135
136         @Test
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]))))
142         }
143
144         @Test
145         fun `updated sone processor stores sone in database`() {
146                 updatedSoneProcessor.updateSone(newSone)
147                 verify(database).storeSone(newSone)
148         }
149
150         @Test
151         fun `default updated Sone processor can be created by dependency injection`() {
152                 assertThat(baseInjector.createChildInjector(
153                                 Database::class.isProvidedByMock()
154                 ).getInstance<UpdatedSoneProcessor>(), notNullValue())
155         }
156
157 }