🐛 Emit event for replies as well
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / text / SoneMentionDetectorTest.kt
1 /**
2  * Sone - SoneMentionDetectorTest.kt - Copyright © 2019 David ‘Bombe’ Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.text
19
20 import com.google.common.base.*
21 import com.google.common.base.Optional.*
22 import com.google.common.eventbus.*
23 import net.pterodactylus.sone.core.event.*
24 import net.pterodactylus.sone.data.*
25 import net.pterodactylus.sone.database.*
26 import net.pterodactylus.sone.test.*
27 import org.hamcrest.MatcherAssert.*
28 import org.hamcrest.Matchers.*
29 import kotlin.test.*
30
31 /**
32  * Unit test for [SoneMentionDetector].
33  */
34 class SoneMentionDetectorTest {
35
36         private val eventBus = EventBus()
37         private val soneProvider = TestSoneProvider()
38         private val postProvider = TestPostProvider()
39         private val soneTextParser = SoneTextParser(soneProvider, postProvider)
40         private val capturedEvents = mutableListOf<LocalSoneMentionedInPostEvent>()
41
42         init {
43                 eventBus.register(SoneMentionDetector(eventBus, soneTextParser))
44                 eventBus.register(object : Any() {
45                         @Subscribe
46                         fun captureEvent(localSoneMentionedInPostEvent: LocalSoneMentionedInPostEvent) {
47                                 capturedEvents += localSoneMentionedInPostEvent
48                         }
49                 })
50         }
51
52         @Test
53         fun `detector does not emit event on post that does not contain any sones`() {
54                 val post = createPost()
55                 eventBus.post(NewPostFoundEvent(post))
56                 assertThat(capturedEvents, emptyIterable())
57         }
58
59         @Test
60         fun `detector does not emit event on post that does contain two remote sones`() {
61                 val post = createPost("text mentions sone://${remoteSone1.id} and sone://${remoteSone2.id}.")
62                 eventBus.post(NewPostFoundEvent(post))
63                 assertThat(capturedEvents, emptyIterable())
64         }
65
66         @Test
67         fun `detector emits event on post that contains links to a remote and a local sone`() {
68                 val post = createPost("text mentions sone://${localSone1.id} and sone://${remoteSone2.id}.")
69                 eventBus.post(NewPostFoundEvent(post))
70                 assertThat(capturedEvents, contains(LocalSoneMentionedInPostEvent(post)))
71         }
72
73         @Test
74         fun `detector emits one event on post that contains two links to the same local sone`() {
75                 val post = createPost("text mentions sone://${localSone1.id} and sone://${localSone1.id}.")
76                 eventBus.post(NewPostFoundEvent(post))
77                 assertThat(capturedEvents, contains(LocalSoneMentionedInPostEvent(post)))
78         }
79
80         @Test
81         fun `detector emits one event on post that contains links to two local sones`() {
82                 val post = createPost("text mentions sone://${localSone1.id} and sone://${localSone2.id}.")
83                 eventBus.post(NewPostFoundEvent(post))
84                 assertThat(capturedEvents, contains(LocalSoneMentionedInPostEvent(post)))
85         }
86
87         @Test
88         fun `detector does not emit event for post by local sone`() {
89                 val post = createPost("text mentions sone://${localSone1.id} and sone://${localSone2.id}.", localSone1)
90                 eventBus.post(NewPostFoundEvent(post))
91                 assertThat(capturedEvents, emptyIterable())
92         }
93
94         @Test
95         fun `detector does not emit event for reply that contains no sones`() {
96                 val reply = emptyPostReply()
97                 eventBus.post(NewPostReplyFoundEvent(reply))
98                 assertThat(capturedEvents, emptyIterable())
99         }
100
101         @Test
102         fun `detector does not emit event for reply that contains two links to remote sones`() {
103                 val reply = emptyPostReply("text mentions sone://${remoteSone1.id} and sone://${remoteSone2.id}.")
104                 eventBus.post(NewPostReplyFoundEvent(reply))
105                 assertThat(capturedEvents, emptyIterable())
106         }
107
108         @Test
109         fun `detector emits event on reply that contains links to a remote and a local sone`() {
110                 val post = createPost()
111                 val reply = emptyPostReply("text mentions sone://${remoteSone1.id} and sone://${localSone1.id}.", post)
112                 eventBus.post(NewPostReplyFoundEvent(reply))
113                 assertThat(capturedEvents, contains(LocalSoneMentionedInPostEvent(post)))
114         }
115
116         @Test
117         fun `detector emits one event on reply that contains two links to the same local sone`() {
118                 val post = createPost()
119                 val reply = emptyPostReply("text mentions sone://${localSone1.id} and sone://${localSone1.id}.", post)
120                 eventBus.post(NewPostReplyFoundEvent(reply))
121                 assertThat(capturedEvents, contains(LocalSoneMentionedInPostEvent(post)))
122         }
123
124         @Test
125         fun `detector emits one event on reply that contains two links to local sones`() {
126                 val post = createPost()
127                 val reply = emptyPostReply("text mentions sone://${localSone1.id} and sone://${localSone2.id}.", post)
128                 eventBus.post(NewPostReplyFoundEvent(reply))
129                 assertThat(capturedEvents, contains(LocalSoneMentionedInPostEvent(post)))
130         }
131
132         @Test
133         fun `detector does not emit event for reply by local sone`() {
134                 val reply = emptyPostReply("text mentions sone://${localSone1.id} and sone://${localSone2.id}.", sone = localSone1)
135                 eventBus.post(NewPostReplyFoundEvent(reply))
136                 assertThat(capturedEvents, emptyIterable())
137         }
138
139 }
140
141 private val remoteSone1 = createRemoteSone()
142 private val remoteSone2 = createRemoteSone()
143
144 private val localSone1 = createLocalSone()
145 private val localSone2 = createLocalSone()
146
147 private fun createPost(text: String = "", sone: Sone = remoteSone1): Post.EmptyPost {
148         return object : Post.EmptyPost("post-id") {
149                 override fun getSone() = sone
150                 override fun getText() = text
151         }
152 }
153
154 private class TestSoneProvider : SoneProvider {
155
156         override val sones: Collection<Sone> get() = remoteSones + localSones
157         override val localSones: Collection<Sone> get() = setOf(localSone1, localSone2)
158         override val remoteSones: Collection<Sone> get() = setOf(remoteSone1, remoteSone2)
159         override val soneLoader: (String) -> Sone? get() = this::getSone
160         override fun getSone(soneId: String): Sone? =
161                         localSones.firstOrNull { it.id == soneId } ?: remoteSones.firstOrNull { it.id == soneId }
162
163 }
164
165 private class TestPostProvider : PostProvider {
166
167         override fun getPost(postId: String): Post? = null
168         override fun getPosts(soneId: String): Collection<Post> = emptyList()
169         override fun getDirectedPosts(recipientId: String): Collection<Post> = emptyList()
170
171 }
172
173 private fun emptyPostReply(text: String = "", post: Post = createPost(), sone: Sone = remoteSone1) = object : PostReply {
174         override val id = "reply-id"
175         override fun getSone() = sone
176         override fun getPostId() = post.id
177         override fun getPost(): Optional<Post> = of(post)
178         override fun getTime() = 1L
179         override fun getText() = text
180         override fun isKnown() = false
181         override fun setKnown(known: Boolean): PostReply = this
182 }