Clean up some imports
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / pages / SearchPageTest.kt
1 package net.pterodactylus.sone.web.pages
2
3 import com.google.common.base.Optional.absent
4 import net.pterodactylus.sone.data.Album
5 import net.pterodactylus.sone.data.Image
6 import net.pterodactylus.sone.data.Post
7 import net.pterodactylus.sone.data.PostReply
8 import net.pterodactylus.sone.data.Profile
9 import net.pterodactylus.sone.data.Sone
10 import net.pterodactylus.sone.test.asOptional
11 import net.pterodactylus.sone.test.mock
12 import net.pterodactylus.sone.test.whenever
13 import org.hamcrest.MatcherAssert.assertThat
14 import org.hamcrest.Matchers.contains
15 import org.junit.Test
16
17 /**
18  * Unit test for [SearchPage].
19  */
20 class SearchPageTest : WebPageTest() {
21
22         private val page = SearchPage(template, webInterface)
23
24         override fun getPage() = page
25
26         @Test
27         fun `empty query redirects to index page`() {
28                 verifyRedirect("index.html")
29         }
30
31         @Test
32         fun `empty search phrases redirect to index page`() {
33                 addHttpRequestParameter("query", "\"\"")
34                 verifyRedirect("index.html")
35         }
36
37         @Test
38         fun `invalid search phrases redirect to index page`() {
39                 addHttpRequestParameter("query", "\"")
40                 verifyRedirect("index.html")
41         }
42
43         @Test
44         fun `searching for sone link redirects to view sone page`() {
45                 addSone("sone-id", mock<Sone>())
46                 addHttpRequestParameter("query", "sone://sone-id")
47                 verifyRedirect("viewSone.html?sone=sone-id")
48         }
49
50         @Test
51         fun `searching for sone link without prefix redirects to view sone page`() {
52                 addSone("sone-id", mock<Sone>())
53                 addHttpRequestParameter("query", "sone-id")
54                 verifyRedirect("viewSone.html?sone=sone-id")
55         }
56
57         @Test
58         fun `searching for a post link redirects to post page`() {
59                 addPost("post-id", mock<Post>())
60                 addHttpRequestParameter("query", "post://post-id")
61                 verifyRedirect("viewPost.html?post=post-id")
62         }
63
64         @Test
65         fun `searching for a post ID without prefix redirects to post page`() {
66                 addPost("post-id", mock<Post>())
67                 addHttpRequestParameter("query", "post-id")
68                 verifyRedirect("viewPost.html?post=post-id")
69         }
70
71         @Test
72         fun `searching for a reply link redirects to the post page`() {
73                 val postReply = mock<PostReply>().apply { whenever(postId).thenReturn("post-id") }
74                 addPostReply("reply-id", postReply)
75                 addHttpRequestParameter("query", "reply://reply-id")
76                 verifyRedirect("viewPost.html?post=post-id")
77         }
78
79         @Test
80         fun `searching for a reply ID redirects to the post page`() {
81                 val postReply = mock<PostReply>().apply { whenever(postId).thenReturn("post-id") }
82                 addPostReply("reply-id", postReply)
83                 addHttpRequestParameter("query", "reply-id")
84                 verifyRedirect("viewPost.html?post=post-id")
85         }
86
87         @Test
88         fun `searching for an album link redirects to the image browser`() {
89                 addAlbum("album-id", mock<Album>())
90                 addHttpRequestParameter("query", "album://album-id")
91                 verifyRedirect("imageBrowser.html?album=album-id")
92         }
93
94         @Test
95         fun `searching for an album ID redirects to the image browser`() {
96                 addAlbum("album-id", mock<Album>())
97                 addHttpRequestParameter("query", "album-id")
98                 verifyRedirect("imageBrowser.html?album=album-id")
99         }
100
101         @Test
102         fun `searching for an image link redirects to the image browser`() {
103                 addImage("image-id", mock<Image>())
104                 addHttpRequestParameter("query", "image://image-id")
105                 verifyRedirect("imageBrowser.html?image=image-id")
106         }
107
108         @Test
109         fun `searching for an image ID redirects to the image browser`() {
110                 addImage("image-id", mock<Image>())
111                 addHttpRequestParameter("query", "image-id")
112                 verifyRedirect("imageBrowser.html?image=image-id")
113         }
114
115         private fun createReply(text: String, postId: String? = null, sone: Sone? = null) = mock<PostReply>().apply {
116                 whenever(this.text).thenReturn(text)
117                 postId?.run { whenever(this@apply.postId).thenReturn(postId) }
118                 sone?.run { whenever(this@apply.sone).thenReturn(sone) }
119         }
120
121         private fun createPost(id: String, text: String) = mock<Post>().apply {
122                 whenever(this.id).thenReturn(id)
123                 whenever(recipient).thenReturn(absent())
124                 whenever(this.text).thenReturn(text)
125         }
126
127         private fun createSoneWithPost(post: Post, sone: Sone? = null) = sone?.apply {
128                 whenever(posts).thenReturn(listOf(post))
129         } ?: mock<Sone>().apply {
130                 whenever(posts).thenReturn(listOf(post))
131                 whenever(profile).thenReturn(Profile(this))
132         }
133
134         @Test
135         fun `searching for a single word finds the post`() {
136                 val postWithMatch = createPost("post-with-match", "the word here")
137                 val postWithoutMatch = createPost("post-without-match", "no match here")
138                 val soneWithMatch = createSoneWithPost(postWithMatch)
139                 val soneWithoutMatch = createSoneWithPost(postWithoutMatch)
140                 addSone("sone-with-match", soneWithMatch)
141                 addSone("sone-without-match", soneWithoutMatch)
142                 addHttpRequestParameter("query", "word")
143                 page.handleRequest(freenetRequest, templateContext)
144                 assertThat(this["postHits"], contains<Post>(postWithMatch))
145         }
146
147         @Test
148         fun `searching for a single word locates word in reply`() {
149                 val postWithMatch = createPost("post-with-match", "no match here")
150                 val postWithoutMatch = createPost("post-without-match", "no match here")
151                 val soneWithMatch = createSoneWithPost(postWithMatch)
152                 val soneWithoutMatch = createSoneWithPost(postWithoutMatch)
153                 val replyWithMatch = createReply("the word here", "post-with-match", soneWithMatch)
154                 val replyWithoutMatch = createReply("no match here", "post-without-match", soneWithoutMatch)
155                 addPostReply("reply-with-match", replyWithMatch)
156                 addPostReply("reply-without-match", replyWithoutMatch)
157                 addSone("sone-with-match", soneWithMatch)
158                 addSone("sone-without-match", soneWithoutMatch)
159                 addHttpRequestParameter("query", "word")
160                 page.handleRequest(freenetRequest, templateContext)
161                 assertThat(this["postHits"], contains<Post>(postWithMatch))
162         }
163
164         private fun createSoneWithPost(idPostfix: String, text: String, recipient: Sone? = null, sender: Sone? = null) =
165                         createPost("post-$idPostfix", text, recipient).apply {
166                                 addSone("sone-$idPostfix", createSoneWithPost(this, sender))
167                         }
168
169         @Test
170         fun `earlier matches score higher than later matches`() {
171                 val postWithEarlyMatch = createSoneWithPost("with-early-match", "optional match")
172                 val postWithLaterMatch = createSoneWithPost("with-later-match", "match that is optional")
173                 addHttpRequestParameter("query", "optional ")
174                 page.handleRequest(freenetRequest, templateContext)
175                 assertThat(this["postHits"], contains<Post>(postWithEarlyMatch, postWithLaterMatch))
176         }
177
178         @Test
179         fun `searching for required word does not return posts without that word`() {
180                 val postWithRequiredMatch = createSoneWithPost("with-required-match", "required match")
181                 createPost("without-required-match", "not a match")
182                 addHttpRequestParameter("query", "+required ")
183                 page.handleRequest(freenetRequest, templateContext)
184                 assertThat(this["postHits"], contains<Post>(postWithRequiredMatch))
185         }
186
187         @Test
188         fun `searching for forbidden word does not return posts with that word`() {
189                 createSoneWithPost("with-forbidden-match", "forbidden match")
190                 val postWithoutForbiddenMatch = createSoneWithPost("without-forbidden-match", "not a match")
191                 addHttpRequestParameter("query", "match -forbidden")
192                 page.handleRequest(freenetRequest, templateContext)
193                 assertThat(this["postHits"], contains<Post>(postWithoutForbiddenMatch))
194         }
195
196         @Test
197         fun `searching for a plus sign searches for optional plus sign`() {
198                 val postWithMatch = createSoneWithPost("with-match", "with + match")
199                 createSoneWithPost("without-match", "without match")
200                 addHttpRequestParameter("query", "+")
201                 page.handleRequest(freenetRequest, templateContext)
202                 assertThat(this["postHits"], contains<Post>(postWithMatch))
203         }
204
205         @Test
206         fun `searching for a minus sign searches for optional minus sign`() {
207                 val postWithMatch = createSoneWithPost("with-match", "with - match")
208                 createSoneWithPost("without-match", "without match")
209                 addHttpRequestParameter("query", "-")
210                 page.handleRequest(freenetRequest, templateContext)
211                 assertThat(this["postHits"], contains<Post>(postWithMatch))
212         }
213
214         private fun createPost(id: String, text: String, recipient: Sone?) = mock<Post>().apply {
215                 whenever(this.id).thenReturn(id)
216                 val recipientId = recipient?.id
217                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
218                 whenever(this.recipient).thenReturn(recipient.asOptional())
219                 whenever(this.text).thenReturn(text)
220         }
221
222         private fun createSone(id: String, firstName: String, middleName: String, lastName: String) = mock<Sone>().apply {
223                 whenever(this.id).thenReturn(id)
224                 whenever(this.name).thenReturn(id)
225                 whenever(this.profile).thenReturn(Profile(this).apply {
226                         this.firstName = firstName
227                         this.middleName = middleName
228                         this.lastName = lastName
229                 })
230         }
231
232         @Test
233         fun `searching for a recipient finds the correct post`() {
234                 val recipient = createSone("recipient", "reci", "pi", "ent")
235                 val postWithMatch = createSoneWithPost("with-match", "test", recipient)
236                 createSoneWithPost("without-match", "no match")
237                 addHttpRequestParameter("query", "recipient")
238                 page.handleRequest(freenetRequest, templateContext)
239                 assertThat(this["postHits"], contains<Post>(postWithMatch))
240         }
241
242         @Test
243         fun `searching for a field value finds the correct sone`() {
244                 val soneWithProfileField = createSone("sone", "s", "o", "ne")
245                 soneWithProfileField.profile.addField("field").value = "value"
246                 createSoneWithPost("with-match", "test", sender = soneWithProfileField)
247                 createSoneWithPost("without-match", "no match")
248                 addHttpRequestParameter("query", "value")
249                 page.handleRequest(freenetRequest, templateContext)
250                 assertThat(this["soneHits"], contains(soneWithProfileField))
251         }
252
253         @Suppress("UNCHECKED_CAST")
254         private operator fun <T> get(key: String): T? = templateContext[key] as? T
255
256 }