2 * Sone - SoneMentionDetectorTest.kt - Copyright © 2019 David ‘Bombe’ Roden
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.
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.
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/>.
18 package net.pterodactylus.sone.text
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.*
32 * Unit test for [SoneMentionDetector].
34 @Suppress("UnstableApiUsage")
35 class SoneMentionDetectorTest {
37 private val eventBus = EventBus()
38 private val soneProvider = TestSoneProvider()
39 private val postProvider = TestPostProvider()
40 private val soneTextParser = SoneTextParser(soneProvider, postProvider)
41 private val capturedFoundEvents = mutableListOf<MentionOfLocalSoneFoundEvent>()
42 private val capturedRemovedEvents = mutableListOf<MentionOfLocalSoneRemovedEvent>()
43 private val postReplyProvider = TestPostReplyProvider()
46 eventBus.register(SoneMentionDetector(eventBus, soneTextParser, postReplyProvider))
47 eventBus.register(object : Any() {
49 fun captureFoundEvent(mentionOfLocalSoneFoundEvent: MentionOfLocalSoneFoundEvent) {
50 capturedFoundEvents += mentionOfLocalSoneFoundEvent
54 fun captureRemovedEvent(event: MentionOfLocalSoneRemovedEvent) {
55 capturedRemovedEvents += event
61 fun `detector does not emit event on post that does not contain any sones`() {
62 val post = createPost()
63 eventBus.post(NewPostFoundEvent(post))
64 assertThat(capturedFoundEvents, emptyIterable())
68 fun `detector does not emit event on post that does contain two remote sones`() {
69 val post = createPost("text mentions sone://${remoteSone1.id} and sone://${remoteSone2.id}.")
70 eventBus.post(NewPostFoundEvent(post))
71 assertThat(capturedFoundEvents, emptyIterable())
75 fun `detector emits event on post that contains links to a remote and a local sone`() {
76 val post = createPost("text mentions sone://${localSone1.id} and sone://${remoteSone2.id}.")
77 eventBus.post(NewPostFoundEvent(post))
78 assertThat(capturedFoundEvents, contains(MentionOfLocalSoneFoundEvent(post)))
82 fun `detector emits one event on post that contains two links to the same local sone`() {
83 val post = createPost("text mentions sone://${localSone1.id} and sone://${localSone1.id}.")
84 eventBus.post(NewPostFoundEvent(post))
85 assertThat(capturedFoundEvents, contains(MentionOfLocalSoneFoundEvent(post)))
89 fun `detector emits one event on post that contains links to two local sones`() {
90 val post = createPost("text mentions sone://${localSone1.id} and sone://${localSone2.id}.")
91 eventBus.post(NewPostFoundEvent(post))
92 assertThat(capturedFoundEvents, contains(MentionOfLocalSoneFoundEvent(post)))
96 fun `detector does not emit event for post by local sone`() {
97 val post = createPost("text mentions sone://${localSone1.id} and sone://${localSone2.id}.", localSone1)
98 eventBus.post(NewPostFoundEvent(post))
99 assertThat(capturedFoundEvents, emptyIterable())
103 fun `detector does not emit event for reply that contains no sones`() {
104 val reply = emptyPostReply()
105 eventBus.post(NewPostReplyFoundEvent(reply))
106 assertThat(capturedFoundEvents, emptyIterable())
110 fun `detector does not emit event for reply that contains two links to remote sones`() {
111 val reply = emptyPostReply("text mentions sone://${remoteSone1.id} and sone://${remoteSone2.id}.")
112 eventBus.post(NewPostReplyFoundEvent(reply))
113 assertThat(capturedFoundEvents, emptyIterable())
117 fun `detector emits event on reply that contains links to a remote and a local sone`() {
118 val post = createPost()
119 val reply = emptyPostReply("text mentions sone://${remoteSone1.id} and sone://${localSone1.id}.", post)
120 eventBus.post(NewPostReplyFoundEvent(reply))
121 assertThat(capturedFoundEvents, contains(MentionOfLocalSoneFoundEvent(post)))
125 fun `detector emits one event on reply that contains two links to the same local sone`() {
126 val post = createPost()
127 val reply = emptyPostReply("text mentions sone://${localSone1.id} and sone://${localSone1.id}.", post)
128 eventBus.post(NewPostReplyFoundEvent(reply))
129 assertThat(capturedFoundEvents, contains(MentionOfLocalSoneFoundEvent(post)))
133 fun `detector emits one event on reply that contains two links to local sones`() {
134 val post = createPost()
135 val reply = emptyPostReply("text mentions sone://${localSone1.id} and sone://${localSone2.id}.", post)
136 eventBus.post(NewPostReplyFoundEvent(reply))
137 assertThat(capturedFoundEvents, contains(MentionOfLocalSoneFoundEvent(post)))
141 fun `detector does not emit event for reply by local sone`() {
142 val reply = emptyPostReply("text mentions sone://${localSone1.id} and sone://${localSone2.id}.", sone = localSone1)
143 eventBus.post(NewPostReplyFoundEvent(reply))
144 assertThat(capturedFoundEvents, emptyIterable())
148 fun `detector does not emit removed event when a post without mention is removed`() {
149 val post = createPost()
150 eventBus.post(PostRemovedEvent(post))
151 assertThat(capturedRemovedEvents, emptyIterable())
155 fun `detector does emit removed event when post with mention is removed`() {
156 val post = createPost("sone://${localSone1.id}")
157 eventBus.post(NewPostFoundEvent(post))
158 eventBus.post(PostRemovedEvent(post))
159 assertThat(capturedRemovedEvents, contains(MentionOfLocalSoneRemovedEvent(post)))
163 fun `detector does not emit removed event when a post without mention is marked as known`() {
164 val post = createPost()
165 eventBus.post(MarkPostKnownEvent(post))
166 assertThat(capturedRemovedEvents, emptyIterable())
170 fun `detector does emit removed event when post with mention is marked as known`() {
171 val post = createPost("sone://${localSone1.id}")
172 eventBus.post(NewPostFoundEvent(post))
173 eventBus.post(MarkPostKnownEvent(post))
174 assertThat(capturedRemovedEvents, contains(MentionOfLocalSoneRemovedEvent(post)))
178 fun `detector does emit removed event when reply with mention is removed and no more mentions in that post exist`() {
179 val post = createPost()
180 val reply = emptyPostReply("sone://${localSone1.id}", post)
181 postReplyProvider.postReplies[post.id] = listOf(reply)
182 eventBus.post(NewPostReplyFoundEvent(reply))
183 eventBus.post(PostReplyRemovedEvent(reply))
184 assertThat(capturedRemovedEvents, contains(MentionOfLocalSoneRemovedEvent(post)))
188 fun `detector does not emit removed event when reply with mention is removed and post mentions local sone`() {
189 val post = createPost("sone://${localSone1.id}")
190 val reply = emptyPostReply("sone://${localSone1.id}", post)
191 eventBus.post(NewPostReplyFoundEvent(reply))
192 eventBus.post(PostReplyRemovedEvent(reply))
193 assertThat(capturedRemovedEvents, emptyIterable())
197 fun `detector does emit removed event when reply with mention is removed and post mentions local sone but is known`() {
198 val post = createPost("sone://${localSone1.id}", known = true)
199 val reply = emptyPostReply("sone://${localSone1.id}", post)
200 eventBus.post(NewPostReplyFoundEvent(reply))
201 eventBus.post(PostReplyRemovedEvent(reply))
202 assertThat(capturedRemovedEvents, contains(MentionOfLocalSoneRemovedEvent(post)))
206 fun `detector does not emit removed event when reply with mention is removed and post has other replies with mentions`() {
207 val post = createPost()
208 val reply1 = emptyPostReply("sone://${localSone1.id}", post)
209 val reply2 = emptyPostReply("sone://${localSone1.id}", post)
210 postReplyProvider.postReplies[post.id] = listOf(reply1, reply2)
211 eventBus.post(NewPostReplyFoundEvent(reply1))
212 eventBus.post(PostReplyRemovedEvent(reply1))
213 assertThat(capturedRemovedEvents, emptyIterable())
217 fun `detector does emit removed event when reply with mention is removed and post has other replies with mentions which are known`() {
218 val post = createPost()
219 val reply1 = emptyPostReply("sone://${localSone1.id}", post)
220 val reply2 = emptyPostReply("sone://${localSone1.id}", post, known = true)
221 postReplyProvider.postReplies[post.id] = listOf(reply1, reply2)
222 eventBus.post(NewPostReplyFoundEvent(reply1))
223 eventBus.post(PostReplyRemovedEvent(reply1))
224 assertThat(capturedRemovedEvents, contains(MentionOfLocalSoneRemovedEvent(post)))
229 private val remoteSone1 = createRemoteSone()
230 private val remoteSone2 = createRemoteSone()
232 private val localSone1 = createLocalSone()
233 private val localSone2 = createLocalSone()
235 private fun createPost(text: String = "", sone: Sone = remoteSone1, known: Boolean = false): Post.EmptyPost {
236 return object : Post.EmptyPost("post-id") {
237 override fun getSone() = sone
238 override fun getText() = text
239 override fun isKnown() = known
243 private class TestSoneProvider : SoneProvider {
245 override val sones: Collection<Sone> get() = remoteSones + localSones
246 override val localSones: Collection<Sone> get() = setOf(localSone1, localSone2)
247 override val remoteSones: Collection<Sone> get() = setOf(remoteSone1, remoteSone2)
248 override val soneLoader: (String) -> Sone? get() = this::getSone
249 override fun getSone(soneId: String): Sone? =
250 localSones.firstOrNull { it.id == soneId } ?: remoteSones.firstOrNull { it.id == soneId }
254 private class TestPostProvider : PostProvider {
256 override fun getPost(postId: String): Post? = null
257 override fun getPosts(soneId: String): Collection<Post> = emptyList()
258 override fun getDirectedPosts(recipientId: String): Collection<Post> = emptyList()
262 private class TestPostReplyProvider : PostReplyProvider {
264 val replies = mutableMapOf<String, PostReply>()
265 val postReplies = mutableMapOf<String, List<PostReply>>()
267 override fun getPostReply(id: String) = replies[id]
268 override fun getReplies(postId: String) = postReplies[postId] ?: emptyList()
272 private fun emptyPostReply(text: String = "", post: Post = createPost(), sone: Sone = remoteSone1, known: Boolean = false) = object : PostReply {
273 override val id = "reply-id"
274 override fun getSone() = sone
275 override fun getPostId() = post.id
276 override fun getPost(): Optional<Post> = of(post)
277 override fun getTime() = 1L
278 override fun getText() = text
279 override fun isKnown() = known
280 override fun setKnown(known: Boolean): PostReply = this